File size: 5,299 Bytes
e998ba1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""The Industrial Harbor card in the same live three.js viewer as the other cards (user, 2026-10-04: "你把IndustrialHarbor的threejs弄的和其他人一样啊").

GPT-6 Astra's scored harbor (EVAL gpt-6-astra-max, map scenebench_industrial_harbor__20260907_214132, the scene the viewer
Space shows) was staged and exported to GLB on serv6 (code4scene-video/scripts/export_glb_harbor.sh, with the ContainerYard,
Hangar and FactoryEnvironment packs linked from scenebench-content), then compressed as website/compress_glb.sh does for
Text-to-Scene scenes (meshopt geometry, 512 px WebP). The harbor has no case in data/site.js (no score), so its card names
its packed model itself (data-glb) and scene-cards.js reads that before looking up a case. The live scene replaces the still
(media/t2s/industrial-harbor/astra.jpg, removed); the card's link still opens the full-resolution viewer Space.

Each step asserts it found what it edits.
    GLB=<compressed industrial-harbor__astra.glb> python3 scripts/harbor_live.py
"""
from __future__ import annotations
import hashlib, json, os, re, shutil, sys
from pathlib import Path
import numpy as np
from bs4 import BeautifulSoup

ROOT = Path(__file__).resolve().parent.parent
GLB = Path(os.environ["GLB"])
V = "20261004harborlive"
KEY = bytes.fromhex("5c2f9e71d3a84b06e1f7c29a38d05b64a7193ce8f2046db95e81c73a2df6904b")   # website/pack_models.py


def one(found, what):
    assert found, f"not found: {what}"
    return found


def pack():
    assert GLB.name == "industrial-harbor__astra.glb", GLB.name
    a = np.frombuffer(GLB.read_bytes(), np.uint8); idx = np.arange(a.size, dtype=np.int64)
    ks = np.frombuffer(KEY, np.uint8)[idx % 32] ^ ((idx // 32) * 131 & 255).astype(np.uint8)
    dst = ROOT / "models" / f"{hashlib.sha256(b'c4s-model:' + GLB.name.encode()).hexdigest()[:20]}.bin"
    dst.write_bytes((a ^ ks).tobytes())
    url = f"models/{dst.name}?v={int(dst.stat().st_mtime)}"
    print("packed", url, round(dst.stat().st_size / 1e6, 1), "MB")
    return url


def progressive(url):
    """build_progressive.py's geometry-first derivative, when textures are a real share of the file (as i2s_more_cases.py)"""
    sys.path.insert(0, str(ROOT / "scripts"))
    import build_progressive as bp
    from i2s_more_cases import texture_share
    share = texture_share(ROOT / url.split("?")[0])
    print("texture share", round(share, 3))
    if share < 0.1:
        return
    shutil.copyfile(ROOT / url.split("?")[0], bp.CACHE / url.split("/")[-1].split("?")[0])
    m = ROOT / "data/progressive-scenes.json"; d = json.loads(m.read_text())
    d.update([bp.convert(url)]); m.write_text(json.dumps(d, indent=2) + "\n")
    cu = ROOT / "scripts/progressive-card-urls.json"; cu.write_text(json.dumps(json.loads(cu.read_text()) + [url]) + "\n")


def scene_cards():
    p = ROOT / "assets/scene-cards.js"; s = p.read_text()
    a = " const c=window.SITE.cases.find(c=>c.id===el.dataset.case),a=c.agents.find(a=>a.key===el.dataset.agent);\n"
    assert s.count(a) == 1, "mount() case lookup"
    s = s.replace(a, " // a showcase card names its model itself (data-glb): it has no case, score or case-explorer entry in data/site.js\n"
                     " const c=el.dataset.glb?{agents:[{key:el.dataset.agent,glb:el.dataset.glb}]}:window.SITE.cases.find(c=>c.id===el.dataset.case),a=c.agents.find(a=>a.key===el.dataset.agent);\n")
    p.write_text(s); print("scene-cards.js: data-glb")


CSS = """
/* the featured card's live scene (scripts/harbor_live.py) */
.case-feature .live-scene{height:auto;min-height:400px;border-radius:16px 0 0 16px}
@media(max-width:900px){.case-feature .live-scene{min-height:0;height:270px;border-radius:16px 16px 0 0}}
"""


def index(url):
    p = ROOT / "index.html"
    soup = BeautifulSoup(p.read_text(), "html.parser")
    card = one(soup.find(class_="case-feature"), "harbor card")
    shot = one(card.find(class_="feature-shot"), "harbor still")
    shot.replace_with(BeautifulSoup(
        f'<div class="live-scene" data-agent="astra" data-case="industrial-harbor" data-glb="{url}"><canvas aria-label="Interactive 3D scene: '
        'Industrial Harbor. Drag to orbit, scroll or use plus and minus to zoom." tabindex="0"></canvas><span class="scene-loading" role="status">'
        'Loading 3D scene…</span><span class="scene-hint">Drag to orbit · Scroll to zoom</span><button aria-label="Pause scene rotation" '
        'class="scene-motion">Ⅱ</button></div>', "html.parser"))
    one(card.find("p"), "harbor line").string = "GPT-6 Astra (max) · 3,949 actors, built in one agent session from an empty 130 m stage"
    one(card.find(class_="text-button"), "harbor link").string = "Open at full texture resolution ↗"
    for t in soup.find_all(["script", "link"]):
        a = "src" if t.name == "script" else "href"
        u = t.get(a) or ""
        if re.match(r"assets/(buildingbench\.css|scene-cards\.js)", u):
            t[a] = re.sub(r"\?v=.*$", "", u) + f"?v={V}"
    p.write_text(str(soup)); print("index.html: harbor card on the live viewer")
    css = ROOT / "assets/buildingbench.css"; s = css.read_text()
    assert "scripts/harbor_live.py" not in s
    css.write_text(s.rstrip("\n") + "\n" + CSS)


if __name__ == "__main__":
    url = pack(); progressive(url); scene_cards(); index(url)