Cold-start progress, early WebGPU bail, and Hugging Face Space packaging - #5
Merged
Conversation
…packaging Cold start pulls ~314 MB from R2 and showed nothing while it happened — getOrFetch buffered the whole body, so the boot overlay sat on a static string for minutes. It now streams and reports per megabyte: "connectome — 78.4 / 125.7 MB (62%)". Measured on a cold IndexedDB: 119 updates for 125.7 MB, 33 for 42.8, ~97 for 140.3 — about one per MB. The throttle is load-bearing, not cosmetic; emitting per chunk would fire thousands of DOM writes a second and measurably slow the download itself. Streaming is opt-in via an optional callback, so the four call sites that pass none keep the original arrayBuffer path byte for byte. The bigger fix was not planned. The `"gpu" in navigator` check ran AFTER loadBrain, so a Safari or Firefox visitor downloaded 125 MB and only then learned their browser cannot run this. It is now the first statement of main(): verified zero .bin requests on that path, and the dead end links to the plain-language landing page, which needs no WebGPU. On a Hugging Face audience that is the single most common failure mode. Hugging Face Space packaging, as a separate space/ directory so none of it touches the GitHub README: - space/README.md carries the YAML frontmatter HF requires as the literal first bytes of the file. app_file is index.html, not app.html: the Space page frames app_file, and a WebGPU-less visitor landing directly in the simulator would get nothing but a black overlay. index.html explains the project in ~49 KB of plain HTML and forwards deep links to the simulator before paint. - space/.gitattributes is the Hub default minus *.wasm and *.bin. LFS-backed files are served as a 302 to a per-request signed URL with no-store, so the 8.6 MB mujoco wasm would re-download on every single page load. As a plain file it returns inline with an ETag and revalidates as 304. - deploy:hf builds locally and uploads dist/. The nine VITE_* R2 URLs are baked at build time from .env.production, which is gitignored; HF's build job forwards no user variables and Space Variables are runtime-only for static Spaces, so building on HF would bake same-origin defaults that build:slim then deletes — every binary would 404. Building locally makes that structurally impossible. Verified: all nine R2 URLs present in the built bundle, no same-origin fallback. Two smaller things found on the way: - index.html's pre-paint forwarder matched mode=science but not mode=game, so a shared ?mode=game link stopped at the landing page. - The app now tells an embedded visitor to open it in its own tab. Inside an iframe the storage bucket is partitioned per-embedder (and Safari may block it), so the 314 MB IndexedDB cache can silently fail to persist and every visit pays full price. src/cache.ts swallows that failure by design. The assets stay on R2 rather than moving into the Space repo. R2 egress is free; a front-page day at 10k cold visitors is ~3.1 TB, HF publishes no per-Space bandwidth quota, and undocumented limits are the kind you discover mid-spike. HF also sends no cache-control at all on Space assets. e2e 34/34, unit 5/5, tsc clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Preparing to publish as a Hugging Face Space. Three UX fixes the Space audience makes urgent, plus the packaging itself.
Cold start now shows progress
~314 MB comes from R2 and nothing indicated it was happening —
getOrFetchbuffered the whole body, so the boot overlay sat on a static string for minutes. It now streams:connectome — 78.4 / 125.7 MB (62%).Measured on a cold IndexedDB: 119 updates for 125.7 MB, 33 for 42.8, ~97 for 140.3 — about one per megabyte. The throttle is load-bearing rather than cosmetic; per-chunk emission would fire thousands of DOM writes a second and measurably slow the download. Streaming is opt-in via an optional callback, so the four call sites passing none keep the original
arrayBuffer()path unchanged.The WebGPU bail moved to the top of
main()This wasn't on the plan and turned out to matter most. The
"gpu" in navigatorcheck ran afterloadBrain, so a Safari or Firefox visitor downloaded 125 MB and only then learned their browser can't run it. Verified after the change: zero.binrequests on that path, and the dead end links to the landing page, which needs no WebGPU.On an HF audience — browsed casually, often on mobile, often not in Chrome — that's the most common failure mode, and the one that generates "doesn't work" comments.
Space packaging (
space/, kept out of the GitHub README)space/README.md— the YAML frontmatter HF requires as the literal first bytes.app_file: index.html, deliberately notapp.html: the Space page framesapp_file, and a WebGPU-less visitor landing straight in the simulator sees only a black overlay.index.htmlexplains the project and forwards deep links to the simulator before paint.space/.gitattributes— Hub default minus*.wasmand*.bin. LFS-backed files are served as a 302 to a per-request signed URL withcache-control: no-store, so the 8.6 MB mujoco wasm would re-download on every page load. Plain, it returns inline with an ETag and revalidates as 304.deploy:hf— builds locally, uploadsdist/. The nineVITE_*R2 URLs bake in at build time from.env.production, which is gitignored; HF's build job forwards no user variables and Space Variables are runtime-only for static Spaces. Building on HF would bake same-origin defaults thatbuild:slimthen deletes — every binary 404s. Building locally makes that structurally impossible. Verified: all nine R2 URLs in the built bundle, no same-origin fallback.Two more found on the way
index.html's pre-paint forwarder matchedmode=sciencebut notmode=game, so a shared?mode=gamelink stopped at the landing page.src/cache.tsswallows that failure by design.Assets stay on R2
R2 egress is free. A front-page day at 10k cold visitors is ~3.1 TB; HF publishes no per-Space bandwidth quota, and undocumented limits are the kind you discover mid-spike. HF also sends no
cache-controlat all on Space assets, so caching would be strictly worse.Still to verify before announcing
Ten minutes, and nobody has done it: open the Space in Chrome with third-party storage blocked and confirm
navigator.gpuandindexedDBare actually available inside the frame. Evidence is strong — WebGPU isn't Permissions-Policy gated, andabgunaydin/draw-instantis already a running WebGPU static Space — but it was never instrumented in an iframe.tscclean · unit 5/5 · e2e 34/34.🤖 Generated with Claude Code