perf(sim): preload all clips into memory for instant altitude swaps #19

Merged
benstull merged 1 commits from feature/preload-media-cache into main 2026-06-25 14:48:59 +00:00
Owner

Preload all clips into memory for instant altitude swaps — answers "can we preload all the videos so things load faster when changing altitudes?"

Problem

Each altitude change reset the single <video> element's src and re-fetched the scale's footage over the network. The dev no-store cache policy applied to /media too, so every scale change paid a full fetch + decode round-trip.

Change

  • simulator/app.py — split the cache middleware: app shell / JS / CSS stay no-store (by-eye dev iteration), but /media is now cacheable (public, max-age, immutable) since the clips are static.
  • simulator/static/app.js — preload every ring clip (19 base + 5 transition, ~350 MB) into in-memory blob object URLs at startup. Non-blocking: the first scale plays immediately while the rest stream in, ordered current-scale-outward. mediaUrl() serves the cached blob when ready, else falls back to the network. A small progress chip self-removes when done.
  • tests — assert app assets stay no-store and /media is cacheable.

Verification

  • 269 passed, 2 skipped.
  • Server smoke: / & /app.jsno-store; /media/...public, max-age=31536000, immutable.
  • Frontend behavior verified by-eye by the operator (no headless browser in repo yet).

🤖 Generated with Claude Code

**Preload all clips into memory for instant altitude swaps** — answers "can we preload all the videos so things load faster when changing altitudes?" ## Problem Each altitude change reset the single `<video>` element's `src` and re-fetched the scale's footage over the network. The dev `no-store` cache policy applied to `/media` too, so every scale change paid a full fetch + decode round-trip. ## Change - **`simulator/app.py`** — split the cache middleware: app shell / JS / CSS stay `no-store` (by-eye dev iteration), but `/media` is now cacheable (`public, max-age, immutable`) since the clips are static. - **`simulator/static/app.js`** — preload every ring clip (19 base + 5 transition, ~350 MB) into in-memory **blob object URLs** at startup. Non-blocking: the first scale plays immediately while the rest stream in, ordered current-scale-outward. `mediaUrl()` serves the cached blob when ready, else falls back to the network. A small progress chip self-removes when done. - **tests** — assert app assets stay `no-store` and `/media` is cacheable. ## Verification - `269 passed, 2 skipped`. - Server smoke: `/` & `/app.js` → `no-store`; `/media/...` → `public, max-age=31536000, immutable`. - Frontend behavior verified by-eye by the operator (no headless browser in repo yet). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
benstull added 1 commit 2026-06-25 14:48:25 +00:00
Each altitude change reset the single <video> element's src and re-fetched
the scale's footage over the network, compounded by the dev no-store policy
applying to /media too — so every scale change paid a full fetch+decode.

- simulator/app.py: split the cache middleware — app shell/JS/CSS stay
  no-store (by-eye dev iteration), but /media is now cacheable
  (public, max-age, immutable) since the clips are static.
- simulator/static/app.js: preload every ring clip (19 base + 5 transition,
  ~350 MB) into in-memory blob object URLs at startup — non-blocking, the
  first scale plays immediately while the rest stream in, ordered current
  scale outward. mediaUrl() serves the cached blob when ready, else falls
  back to the network. A small progress chip self-removes when done.
- tests: assert app assets stay no-store and /media is cacheable.

269 passed, 2 skipped. Frontend verified by-eye by the operator (no headless
browser in repo yet).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
benstull merged commit ab2edf77bb into main 2026-06-25 14:48:59 +00:00
benstull deleted branch feature/preload-media-cache 2026-06-25 14:49:01 +00:00
Sign in to join this conversation.