TL;DR
We optimize for three things: tiny bundles, smooth frames, and reproducible results. That drives every decision from rendering to audio to state.
One RAF, fixed Δt
Each page runs a single requestAnimationFrame loop. We clamp Δt (e.g., ≤50 ms) so frame drops don’t explode physics. Background tabs pause the loop and resync on return. This keeps animations stable and laptops cool.
Canvas over heavy DOM
We draw almost everything on Canvas:
- Predictable performance and less layout thrash.
- Pixel-perfect HUD elements that don’t cause style recalculations.
- Clean separation between “simulation state” and “UI scaffolding.”
When DOM is needed (menus, inputs), we keep it minimal and style inline or via a tiny global sheet.
Pooled WebAudio
Sounds sell realism, but audio nodes are expensive if you create/destroy them repeatedly. We maintain a pooled bus with a small voice cap (e.g., 6). Mobile audio unlocks after the first gesture, then stays reliable.
Seeded PRNG, banned Math.random()
Randomness must be deterministic to be replayable. A seeded PRNG (e.g., xorshift/mulberry) guarantees the same number stream for a given seed on any device. That’s how Share links can replay both process and outcome.
State in the URL
We encode { seed, state } in a compact string attached to the URL. Users control sharing; we don’t need accounts or serverside sessions for core features. Bonus: it’s privacy-friendly and easy to debug.
Budget and guardrails
- Page script budget: ≤250 KB (excluding fonts).
- Audio buffer budget: tiny; many effects are synthesized.
- Auto-degrade: if fps < 45, we fade out shadows/particles.
- Zero red console policy for releases.
Testing the right things
- Determinism: same seed → same path → same result (Wheel/Coin/Dice/Top).
- Input latency: keyboard/drag → on-screen effect in ≤60 ms.
- Battery sanity: background tabs pause loops and audio.
- Mobile touch targets: 44 px minimum, help overlay readable.
Roadmap (without breaking the core)
- PWA lite: manifest + cache for 8 tools and the homepage.
- Embeds: guidance for OBS/iframes with a safe CSP.
- Unit toggles: mph ↔ km/h, without changing seeded semantics.
- I18n: language packs layered on top of the same share format.
Try next:
See it in action: Timer & Scoreboard.
Watch physics under pressure: Racing and Golf.
Deep dive into seeds: Reproducible Randomness.