Spaces:
Running
Running
File size: 16,238 Bytes
988be21 27aa296 988be21 17d0c97 988be21 27aa296 988be21 b53e86d 988be21 27aa296 988be21 5e1643b 988be21 5e1643b 988be21 17d0c97 988be21 b53e86d 988be21 b85bdcb 0c7052b b85bdcb 988be21 17d0c97 988be21 b85bdcb 988be21 17d0c97 988be21 17d0c97 988be21 17d0c97 988be21 b53e86d 988be21 0c7052b 988be21 | 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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | #!/usr/bin/env python3
"""The Text-to-Scene gallery: what every shown configuration built on each of the 20 scenes (user, 2026-10-16:
"gallery可以放上去").
The internal leaderboard's gallery, rebuilt for this site: the evaluator's four candidate renders per model and case
(the benchmark's own cameras, 1280x720), with the case score and cost. Only the configurations on the leaderboard
(data/t2s-sandbox.json, written by scripts/t2s_sandbox_round.py, so run that first); nothing internal (paths, judge
notes, clips) is carried over. Pages:
gallery/index.html the agents, in leaderboard order, each with a strip of fixed scenes
gallery/cases.html scene by scene: every agent's view-0 render, best first; a click shows all four views
gallery/model/<key>.html one agent: its 20 scenes, each with the four renders, score, components and cost
Renders are re-encoded as WebP (1280 px at q72, 480 px thumbnails at q70): about 120 kB a view instead of 260 kB,
with no visible difference at full size. Encoding is incremental.
python3 scripts/t2s_gallery.py --src ../t2s-src
"""
from __future__ import annotations
import argparse
import html
import json
import math
import re
import shutil
from concurrent.futures import ProcessPoolExecutor
from pathlib import Path
from PIL import Image
ROOT = Path(__file__).resolve().parent.parent
OUT = ROOT / "gallery"
V = "20261016t2s"
STRIP = ["blue-city", "cyberpunk", "egyptian-temple", "nordic-harbour", "winter-town"] # the same five for everyone
CSS_V, PAPER_CSS = "20261017logo", "5427505a" # buildingbench.css as scripts/simworld_logo.py last versioned it
MARK = "assets/simworld-mark.png?v=20261017logo" # the SimWorld emblem (scripts/simworld_logo.py)
e = html.escape
def trunc(x: float, n: int = 3) -> str:
return f"{math.floor(x * 10 ** n + 1e-9) / 10 ** n:.{n}f}"
def money(x):
return f"${x:.2f}" if x is not None else "–"
# ---- renders -------------------------------------------------------------------------------------------------
def encode(job):
src, full, thumb = job
if full.exists() and thumb.exists() and full.stat().st_mtime >= src.stat().st_mtime:
return 0
full.parent.mkdir(parents=True, exist_ok=True)
im = Image.open(src).convert("RGB")
im.save(full, "WEBP", quality=72, method=6)
t = im.resize((480, round(480 * im.height / im.width)), Image.LANCZOS)
t.save(thumb, "WEBP", quality=70, method=6)
return 1
def renders(src: Path, D: dict, internal: dict) -> None:
jobs, keep = [], set()
for m in D["models"]:
for c in D["cases"]:
for v in range(4):
s = src / "img" / internal[m["name"]] / c["id"] / f"v{v}.jpg"
if not s.exists() and not m["cases"][c["id"]]["score"]:
continue # no scene for this case: left out
assert s.exists(), s
full = OUT / "img" / m["key"] / c["slug"] / f"v{v}.webp"
thumb = full.with_name(f"v{v}_t.webp")
jobs.append((s, full, thumb))
keep |= {full, thumb}
with ProcessPoolExecutor() as ex:
n = sum(ex.map(encode, jobs, chunksize=8))
for f in (OUT / "img").rglob("*.webp"): # a configuration that left the leaderboard
if f not in keep:
f.unlink()
for d in sorted((OUT / "img").rglob("*"), reverse=True):
if d.is_dir() and not any(d.iterdir()):
d.rmdir()
print(f"renders: {n} encoded, {len(jobs) - n} unchanged")
# ---- pages ---------------------------------------------------------------------------------------------------
def page(root: str, title: str, desc: str, body: str) -> str:
nav = (f'<header class="site-header"><div class="brand"><a aria-label="Code4Scene home" class="brand-home" href="{root}index.html#top">'
f'<img alt="" class="brand-mark" decoding="async" height="30" src="{root}{MARK}" width="30"/>'
'<span>Code4Scene</span></a><a class="brand-by" href="https://simworld.org/">by SimWorld</a></div>'
f'<nav aria-label="Main navigation"><a href="{root}index.html#top">Benchmark</a><a href="{root}index.html#leaderboard">Leaderboard</a>'
f'<a href="{root}index.html#cases">Visualization</a><a class="nav-active" href="{root}gallery/index.html">Gallery</a>'
'<a href="https://arxiv.org/abs/2609.36777" rel="noopener" target="_blank">Paper ↗</a>'
'<a href="https://github.com/SimWorld-AI/Code4Scene" rel="noopener" target="_blank">Github ↗</a></nav></header>')
foot = ('<footer><p>Code4Scene · UC San Diego & UC Berkeley · <a href="https://arxiv.org/abs/2609.36777" rel="noopener" '
'target="_blank">arXiv:2609.36777</a> · <a href="https://github.com/SimWorld-AI/Code4Scene" rel="noopener" target="_blank">'
'GitHub</a> · <a href="https://simworld.org/" rel="noopener" target="_blank">SimWorld Home</a></p></footer>')
return ('<!DOCTYPE html>\n<html lang="en"><head>\n<meta charset="utf-8"/><meta content="width=device-width,initial-scale=1" name="viewport"/>\n'
f'<title>{e(title)}</title><meta content="{e(desc)}" name="description"/>\n'
f'<link href="{root}{MARK}" rel="icon" sizes="192x192" type="image/png"/><link href="{root}{MARK}" rel="apple-touch-icon"/>\n'
f'<link href="{root}assets/paper.css?v={PAPER_CSS}" rel="stylesheet"/>\n'
f'<link href="{root}assets/buildingbench.css?v={CSS_V}" rel="stylesheet"/>\n'
f'<link href="{root}assets/gallery.css?v={V}" rel="stylesheet"/>\n'
f'<link rel="stylesheet" href="{root}assets/explore/gallery-links.css?v=20261019explore1" data-explore-include>\n'
f'</head><body class="gallery-page"><a class="skip-link" href="#main">Skip to the gallery</a>\n{nav}\n'
f'<main class="page-main" id="main">\n{body}\n</main>\n{foot}\n'
f'<script defer src="{root}assets/explore/gallery-links.js?v=20261019explore1" data-explore-include></script>\n'
f'<script defer src="{root}assets/gallery.js?v={V}"></script>\n</body></html>\n')
def logo(svg: str, uid: str) -> str:
for gid in set(re.findall(r'id="([^"]+)"', svg)):
svg = svg.replace(f'id="{gid}"', f'id="{gid}{uid}"').replace(f"url(#{gid})", f"url(#{gid}{uid})")
return f'<span class="logo" aria-hidden="true">{svg}</span>'
def has_scene(m: dict, c: dict) -> bool:
"""Whether the agent left a scene for this case (one with no valid scene scores 0 and has no renders)."""
return (OUT / "img" / m["key"] / c["slug"] / "v0.webp").exists()
def views(m: dict, c: dict, prefix: str, first_only: bool = False, chip: str = "") -> str:
"""The four renders as thumbnails linking to full size; gallery.js opens them in a viewer, grouped per agent and
scene. first_only: show view 1 and keep the other three as links the viewer steps through; chip: a score on it."""
group = f"{m['key']}/{c['slug']}"
out = []
for v in range(4):
base = f"{prefix}img/{m['key']}/{c['slug']}/v{v}"
cap = f"{m['name']} · {c['title']} · view {v + 1} of 4 · score {trunc(m['cases'][c['id']]['score'])}"
img = (f'<img alt="{e(cap)}" decoding="async" height="270" loading="lazy" src="{base}_t.webp?v={V}" width="480"/>'
if v == 0 or not first_only else "")
if v == 0 and chip:
img += f'<span class="gal-chip">{chip}</span>'
hidden = ' hidden=""' if first_only and v else ""
out.append(f'<a class="gimg" data-group="{e(group)}" data-caption="{e(cap)}" href="{base}.webp?v={V}"{hidden}>{img}</a>')
return f'<div class="{"gal-first" if first_only else "gal-views"}">{"".join(out)}</div>'
def brief(text: str) -> str:
return f'<p class="gal-brief">{e(text)}</p>'
def switcher(active: str) -> str:
link = lambda key, href, text: (f'<a aria-current="page" class="on" href="{href}">{text}</a>' if key == active
else f'<a href="{href}">{text}</a>')
return ('<nav aria-label="Browse the gallery" class="gal-switch">' + link("agent", "index.html", "By agent")
+ link("scene", "cases.html", "By scene") + "</nav>")
INTRO = ("What each configuration built on the 20 Research Track scenes in the October 2026 Text-to-Scene re-run, as the "
"evaluator saw it: four renders per scene from the benchmark's own cameras, with the case score and the agent's cost. "
"Scores are truncated to three decimals; a case without a valid scene scores 0.")
def basis_tip(m: dict) -> str:
why = m.get("cost_basis") or (m.get("cost_none") if m["cost"] is None else None)
return f' title="{e(m["name"])}: {e(why)}"' if why else ""
def basis_note(m: dict) -> str:
if m.get("cost_basis"):
return f'<p class="gal-note gal-basis">Cost: {e(m["cost_basis"])}.</p>'
if m["cost"] is None and m.get("cost_none"):
return f'<p class="gal-note gal-basis">No cost: {e(m["cost_none"])}.</p>'
return ""
def index_page(D: dict, logos: dict) -> str:
rows = []
for i, m in enumerate(D["models"]):
strip = "".join(f'<img alt="" decoding="async" height="270" loading="lazy" src="img/{m["key"]}/{s}/v0_t.webp?v={V}" width="480"/>'
for s in STRIP if (OUT / "img" / m["key"] / s / "v0.webp").exists())
rows.append(f'<li><a class="gal-agent" href="model/{m["key"]}.html"><span class="rk">{i + 1}</span>'
f'<span class="who">{logo(logos[m["logo"]], f"G{i}")}<span><b>{e(m["name"])}</b><small>{e(m["org"])}</small></span></span>'
f'<span class="num"><small>Score</small><b>{trunc(m["score"])}</b></span>'
f'<span class="num"{basis_tip(m)}><small>Median cost</small>{money(m["cost"])}{"*" if m.get("cost_basis") else ""}</span>'
f'<span class="strip" aria-hidden="true">{strip}</span></a></li>')
names = ", ".join(D["titles"][s] for s in STRIP)
body = ('<section class="gal-top"><div class="container"><span class="section-label">Gallery</span>'
'<h1 class="section-title">Every scene, every agent</h1>'
f'<p class="section-desc">{e(INTRO)}</p>{switcher("agent")}</div></section>'
f'<section class="gal-body"><div class="container"><p class="gal-note">In leaderboard order. The strip shows the same five '
f'scenes for every agent: {e(names)}.</p><ol class="gal-agents">{"".join(rows)}</ol></div></section>')
return page("../", "Code4Scene · Gallery", "Every Text-to-Scene output of the October 2026 re-run, by agent.", body)
def cases_page(D: dict, logos: dict) -> str:
pills = "".join(f'<a href="#{c["slug"]}">{e(c["title"])}</a>' for c in D["cases"])
secs = []
for c in D["cases"]:
ranked = sorted((m for m in D["models"] if has_scene(m, c)), key=lambda m: -m["cases"][c["id"]]["score"])
tiles = []
for j, m in enumerate(ranked):
r = m["cases"][c["id"]]
dot = f'<i aria-hidden="true" class="dot" style="background:{m["colour"]}"></i>' # 300 tiles: a dot, not the logo
tiles.append(f'<figure class="gal-tile">{views(m, c, "", True, trunc(r["score"]))}<figcaption>{dot}'
f'<a class="who" href="model/{m["key"]}.html#{c["slug"]}">{e(m["name"])}</a>'
f'<small>{money(r["cost"])}</small></figcaption></figure>')
secs.append(f'<section class="gal-case" id="{c["slug"]}"><div class="gal-case-head"><h2>{e(c["title"])}</h2>'
f'<a class="gal-up" href="#top-pills">All scenes ↑</a></div>{brief(c["brief"])}'
f'<div class="gal-grid">{"".join(tiles)}</div></section>')
body = ('<section class="gal-top"><div class="container"><span class="section-label">Gallery</span>'
'<h1 class="section-title">Every agent, scene by scene</h1>'
f'<p class="section-desc">{e(INTRO)} Agents are ordered by their score on the scene; click a render for all four views.</p>'
f'{switcher("scene")}<nav aria-label="Scenes" class="gal-pills" id="top-pills">{pills}</nav></div></section>'
f'<section class="gal-body"><div class="container">{"".join(secs)}</div></section>')
return page("../", "Code4Scene · Gallery by scene", "Every agent's Text-to-Scene output on each of the 20 scenes.", body)
def model_page(D: dict, i: int, logos: dict) -> str:
m = D["models"][i]
prev_, next_ = D["models"][i - 1] if i else None, D["models"][i + 1] if i + 1 < len(D["models"]) else None
pn = ('<nav aria-label="Other agents" class="gal-pn">'
+ (f'<a href="{prev_["key"]}.html">← {e(prev_["name"])}</a>' if prev_ else "<span></span>")
+ (f'<a href="{next_["key"]}.html">{e(next_["name"])} →</a>' if next_ else "<span></span>") + "</nav>")
stats = "".join(f'<div><small>{k}</small><b>{v}</b></div>' for k, v in (
("Rank", f'{i + 1} <span>of {len(D["models"])}</span>'), ("Score", trunc(m["score"])), ("Detailed", trunc(m["detailed"])),
("Overview", trunc(m["overview"])), ("Physical", trunc(m["physical"])), ("Median cost", money(m["cost"]))))
pills = "".join(f'<a href="#{c["slug"]}">{e(c["title"])}</a>' for c in D["cases"] if has_scene(m, c))
secs = []
for c in D["cases"]:
if not has_scene(m, c):
continue
r = m["cases"][c["id"]]
comp = f'Detailed {trunc(r["detailed"])} · Overview {trunc(r["overview"])} · Physical {trunc(r["physical"])}'
secs.append(f'<section class="gal-case" id="{c["slug"]}"><div class="gal-case-head"><h2>{e(c["title"])}</h2>'
f'<span class="gal-score">{trunc(r["score"])}</span><span class="gal-comp">{comp}</span>'
f'<span class="gal-cost">{money(r["cost"])}</span>'
f'<a class="gal-up" href="../cases.html#{c["slug"]}">All agents on this scene →</a></div>'
f'{brief(c["brief"])}{views(m, c, "../")}</section>')
body = ('<section class="gal-top"><div class="container"><nav aria-label="Breadcrumb" class="gal-crumb"><a href="../index.html">Gallery</a> / '
f'<span>{e(m["name"])}</span></nav><h1 class="section-title gal-name">{logo(logos[m["logo"]], "H")}{e(m["name"])}</h1>'
f'<p class="section-desc">{e(m["org"])} · Text-to-Scene re-run, October 2026 · the 20 Research Track scenes, four '
f'renders each from the evaluator\'s cameras.</p><div class="gal-stats">{stats}</div>'
+ basis_note(m) +
f'<nav aria-label="Scenes" class="gal-pills">{pills}</nav></div></section>'
f'<section class="gal-body"><div class="container">{"".join(secs)}{pn}</div></section>')
return page("../../", f"Code4Scene · {m['name']} · Gallery",
f"What {m['name']} built on each of the 20 Text-to-Scene scenes, with scores and costs.", body)
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
ap.add_argument("--src", type=Path, required=True)
a = ap.parse_args()
D = json.loads((ROOT / "data/t2s-sandbox.json").read_text())
D["titles"] = {c["slug"]: c["title"] for c in D["cases"]}
internal = {m["name"]: m["key"] for m in json.loads((a.src / "data.json").read_text())["models"]}
import subprocess
logos = json.loads(subprocess.run(
["node", "-e", "global.window={};eval(require('fs').readFileSync(process.argv[1],'utf8'));"
"process.stdout.write(JSON.stringify(window.SITE.logos))", str(ROOT / "data/site.js")],
capture_output=True, text=True, check=True).stdout)
OUT.mkdir(exist_ok=True)
renders(a.src, D, internal)
(OUT / "index.html").write_text(index_page(D, logos))
(OUT / "cases.html").write_text(cases_page(D, logos))
md = OUT / "model"
if md.exists():
shutil.rmtree(md)
md.mkdir()
for i, m in enumerate(D["models"]):
(md / f"{m['key']}.html").write_text(model_page(D, i, logos))
print(f"gallery: {len(D['models'])} agents x {len(D['cases'])} scenes, {len(D['models']) + 2} pages")
if __name__ == "__main__":
main()
|