simocracy-v2 · sim-load-perf-merged
A 33-iteration autoresearch session optimised the sim avatar cold-load pipeline that drives /senate, /gallery, and every walking world. After merge to main and Vercel deploy, the production end serves the new mega-atlas pipeline, atlases load in WebP-lossless, sim avatars render correctly across the gallery, the Senate walking world, and individual sim profiles. Pixel parity verified against the saved bench checksum baseline.
cold_load_µs (iter #31 baseline)Headline. The 33-iteration autoresearch session landed a major sim-rendering performance improvement that's now live on simocracy.org. Smoke test confirms: every page that exercises the sprite renderer (landing hero, gallery, Senate walking world, sim profiles) loads correctly and serves the new mega-atlas + WebP-lossless pipeline. Pixel-rendered output is byte-identical to the pre-merge baseline. Cold-load for a busy walking-world scene is ~98% smaller than the original raw baseline.
The merge commit (bde378f) brought in 35 commits across the atlas pipeline. The pipeline is now:
| Stage | Before | After |
|---|---|---|
| Atlas manifests | 50 separate JSON fetches (1.45 MB) | Bundled into JS chunk via atlas-manifests.generated.ts (0 fetches) |
| Per-part atlases | 21 PNG round-trips per character set | Single mega-atlas PNG per character set (4 RTTs → 1 batch) |
| Static (first paint) | Same atlas as anim | Frame-5-only mega-static.webp, inlined as base64 in JS chunk (0 RTT) |
| Anim (walk cycle) | PNG (~3.3 MB total) | mega-anim.webp lossless (286 KB total) — 2D shelf-packed (-59% pixel count) |
| Fetch order | await static, then void anim | Both fired in parallel — HTTP/2 multiplexes on one RTT |
| Bundle hygiene | ~89 lines dead code in renderer + ~70 dead lines in types | Removed; manifest schema uses short keys, derived constants |
End-to-end browser walkthrough through the merged build, showing the optimised pipeline serving real production traffic. The full sequence is recorded in assets/walkthrough.webm below.
SimAvatar components.
useWalkingAvatars. The single anim atlas powers every walk cycle for every visible sim.
SimRecord.image blob from PDS) which is the cheap default render. On hover the canvas mounts and the mega-atlas pipeline kicks in for animation — same code path as walking worlds, single atlas batch.
active). Walking cycle animates from mega-anim.webp after lazy load. Constitution and stats (3 chats, 3 council seats, 9 S-Process deliberations) render alongside.The smoke test isn't only "did the page paint?" — we also verify the actual asset delivery matches what the optimisation work intended. Three checks:
Curl the deployed atlases. The exact byte counts match the build artefacts on disk — confirming Vercel served the new pipeline, not a cached old build.
$ for cs in adult oldman nekonin children; do
for tier in mega-static.webp mega-anim.webp; do
curl -sLI https://www.simocracy.org/atlases/$cs/$tier \
| grep -E 'content-type|content-length'
done
done
adult/mega-static.webp content-type: image/webp content-length: 23916
adult/mega-anim.webp content-type: image/webp content-length: 160602
oldman/mega-static.webp content-type: image/webp content-length: 6628
oldman/mega-anim.webp content-type: image/webp content-length: 27616
nekonin/mega-static.webp content-type: image/webp content-length: 7834
nekonin/mega-anim.webp content-type: image/webp content-length: 35956
children/mega-static.webp content-type: image/webp content-length: 6016
children/mega-anim.webp content-type: image/webp content-length: 42852
total: 311 KB across all 4 character sets (mega-static + mega-anim)
The autoresearch bench composites 21 representative sims and SHA-256-hashes their rendered pixels. Re-running the bench against the merged main produces identical checksums to the pre-merge baseline — every single optimisation in the session preserved byte-identical rendered output.
The bench-recorded best cold_load_µs = 85,096 (iter #31) is preserved. Pixel parity is the precondition for every "keep" iteration in autoresearch.jsonl.
Detailed terminal capture of the bench run is in the second video below.
Sanity check: per-part JSON manifests (clothes-atlas.json, etc.) are still in public/atlases/ as build artefacts for the build script's incremental work, but the loader's per-part fallback path was removed in iter #25 — production clients fetch the mega-atlas directly via the bundled manifest module and never make per-part requests.
$ curl -s https://www.simocracy.org/atlases/adult/clothes-atlas.json | wc -c
207 # tiny because sprites[] was stripped in iter #1; still served but not loaded
SimAvatar mode="hover"./senate) animates ~20 sims simultaneously — the canonical stress test for the atlas pipeline. No visible glitches; all sims walk smoothly./gallery) shows 123 sim cards with thumbnails, no loading flicker. Page-level stats render correctly./sims/einstein) render the large animated avatar without delay.curl -I confirms image/webp is being served for all eight mega-atlas files (4 CSes × static + anim).The original smoke-test plan called for creating a new sim via the disposable-email OAuth flow to exercise the full write path through org.simocracy.sim, the facilitator's org.simocracy.history sidecar, and the indexer's auto-backfill. In practice, certified.one's OAuth provider returned an email verification step that broke agent-browser's tab tracking (the OAuth redirect opened a new tab and the snapshot/click flow lost its anchor refs).
Because the optimisation work is entirely about asset delivery (mega-atlas + bundled manifest + WebP) and not about the sim CRUD path, this didn't block the smoke test — every sim already on the platform exercises the same pipeline. The 123 sims in the gallery + the ~20 walking in the Senate + Einstein's profile cover every render mode (static, hover, active) the new code touches.
For a future round, the OAuth-flow smoke test should be retried with explicit retry on tab refresh after the verification redirect, or driven entirely through the simocracy.org /api/records route with a pre-existing session token.
The autoresearch session captured several wins that bench couldn't measure but would still help real users — documented in autoresearch.ideas.md:
atlas-manifests.generated.ts so the ~50 KB bundled module only loads on pages that mount the sprite renderer (currently it ships transitively with the gallery, profile, my-sims, walking worlds).createImageBitmap + worker-thread decode for off-main-thread atlas decoding.<link rel="preload"> hints for mega-anim.webp URLs in the walking-world page <head> so the browser starts the fetch during JS parse rather than waiting for loadMegaImage to fire.None of these are blocked by anything in this PR — they're deferred follow-ups, not regressions.
bde378f on main
Branchautoresearch/sim-load-perf-2026-05-13 (preserved for the per-iteration log)
Iterations logautoresearch.jsonl — 33 iterations, 15 keeps, 18 discards
Bench command./autoresearch.sh (which runs node scripts/autoresearch-bench.mjs)
Bench scenario21 sims across 4 character sets, frame-5 first paint + frames 1/9 walk cycle
Production base URLhttps://www.simocracy.org/
Atlas URL pattern/atlases/{adult|oldman|nekonin|children}/{mega-static|mega-anim}.{webp,png}
Walkthrough videowalkthrough.webm (2.2 MB)
Bench-verify videobench-verify.webm (1.0 MB)
Screenshotsassets/01-*.png through assets/05-*.png