Postmortem: Derecho 3D Explainer Scene
Pure procedural WebGL compilation eliminated external assets and guaranteed frame purity, but unbundled script Playwright timeouts and headless Chromium ReadPixels GPU stalls required parallel SHOOT_WORKERS=4 acceleration.
- Mode
- session
- Scope
- derecho-explainer
- Created
- July 31, 2026
- Model
- Gemini 3.6 Flash
- Tooling
- Antigravity CLI
/data/mitate/derecho/derecho.html/data/mitate/derecho/derecho.sheet.jpg/data/mitate/derecho/derecho.nocap.sheet.jpg/data/mitate/derecho/derecho.aspect.jpg/data/mitate/derecho/prompt_draft.md/data/mitate/derecho/PROJECT.md/data/mitate/derecho/ORIGINAL_REQUEST.md/data/mitate/smoke.js/data/mitate/shoot.js/data/mitate/build.js/data/mitate/backend.js
t=6.00s) to prevent desynchronized before/after comparison pairs.smoke.js, motion, and probe alongside images instead of subjective "looks fixed" assertions.build.js poster <scene> <t> rather than extracting frames from compressed MP4 containers.1. What went well
Procedural Zero-Asset Scene Architecture: derecho.html was generated using pure Three.js procedural primitives, instanced rain/debris meshes, and TSL nodes with zero external HTTP texture or model dependencies (citation: /data/mitate/derecho/derecho.html).
Automated Contract & Determinism Verification: smoke.js caught non-deterministic state accumulation (stormKeyLight.intensity += spike inside animate(t)) before video recording (citation: /data/mitate/smoke.js).
Parallel Worker Acceleration (SHOOT_WORKERS=4): Parallelizing Playwright frame capture across 4 contiguous Chromium worker pages provided a ~4x speedup, avoiding single-browser GPU memory bottlenecks (citation: /data/mitate/shoot.js).
Multi-Axis Review Passes: build.js sheet, aspect, nocap, squint, and poster provided empirical visual verification across 16:9, 4:3, 1:1, and 9:16 aspect ratios (citation: /data/mitate/derecho/derecho.sheet.jpg, /data/mitate/derecho/derecho.aspect.jpg).


?nocap) to ensure geometry communicates mechanics on its own.
2. What did not go well
Stateful Accumulation Bug in animate(t): Accidental stormKeyLight.intensity += spike mutated state across frames. Seeking backward or skipping frames caused light intensity to explode exponentially, failing smoke.js (citation: /data/mitate/smoke.js log: seekTo(6) not deterministic — scene carries state across frames).
Headless Browser GPU Stalls & Crashes: Single-worker rendering (tasks 56, 101, 149) triggered Chromium ReadPixels GPU stalls (citation: /data/mitate/backend.js log: GPU stall due to ReadPixels), leading to browser crashes (Target page, context or browser has been closed).
Unbundled Script Playwright Worker Failure: Direct shoot.js runs on unbundled HTML failed with error: scene never set window.sceneReady because Three.js vendor script tag was missing before running build.js bundle (citation: /data/mitate/shoot.js:134).
CLI Mode Syntax Error: Running bun run shoot.js derecho.html derecho.mp4 failed with unknown mode: derecho.mp4 because shoot.js requires explicit mode subcommands (citation: /data/mitate/shoot.js:50).
Atmospheric Noir vs Exposure Threshold Warning: Atmospheric storm noir lighting triggered smoke.js exposure warnings (citation: /data/mitate/smoke.js log: exposure: crushed — 53.2% near black). Raising ambient baseline (baseHemi: 1.25, baseFill: 0.95) resolved exposure thresholds while preserving storm mood.
3. Deviations from the plan
| Planned | Shipped | Verdict |
|---|---|---|
| ~30s 3D animated derecho explainer | 30.0s 5-beat procedural animation (derecho.html) |
Better than planned — zero external assets, pure WebGL |
| Exported playable video | 30 FPS MP4 video master (derecho.mp4) |
Met requirement — frame-exact 900 frame capture |
| Single-worker headless shoot | 4-worker parallel Playwright shoot (SHOOT_WORKERS=4) |
Better than planned — bypassed single-threaded Chromium GPU stalls |
| Basic text postmortem | Ultra-visual HTML postmortem with embedded live 3D web preview & review gallery | Better than planned — interactive WebGL dashboard |
4. Escapes (tests)
Unbundled Script Escape: shoot.js had no static pre-flight check asserting that Three.js was bundled before launching Chromium, causing a 20-second Playwright timeout instead of an instant CLI error (citation: /data/mitate/shoot.js:134).
State Accumulation Escape: Static code linters did not flag += assignments inside animate(t). Only dynamic runtime seeking in smoke.js caught the non-determinism (citation: /data/mitate/smoke.js).
CLI Argument Parsing Escape: shoot.js positional argument parsing printed unknown mode instead of showing --help usage (citation: /data/mitate/shoot.js:50).
5. Forward items
- Add a pre-flight bundle check to
shoot.jsthat asserts<script src="./three.global.js">is replaced with inline vendor code, failing instantly if missing. - Add an environment flag
SHOOT_WORKERS=autotobuild.jsto default to multi-worker frame rendering on multi-core systems. - Audit all
animate(t)assignments in template files to enforceconstor absolute assignment=rather than+=accumulators.