Playable: pick a bread, set the dial, drop the lever, watch it brown, pop it
onto the plate. No timer readout — you go by smell.
- toasting.ts: heat map from real toaster behaviour (element stripes, cool top
edge where the slice stands proud of the slot, edge falloff, per-run noise
bias). Moisture must boil off before the crust browns at full rate, so
sourdough stalls then catches up; sugar browns and burns early.
Rate is measured against the heat map's actual ~0.77 mean, not guessed:
power 6 -> golden 0.511 at 10s, verified in-browser.
- Props on a real scale (1 unit ~ 11cm, one slice wide) — the toaster is
meant to dwarf the bread.
- The pop solves a genuine ballistic arc from slot to plate.
Three bugs found by driving it rather than trusting the compile:
- valueNoise2D read one past its grid at x=w-1, so heatBias was NaN along an
edge, which poisoned mean browning to NaN — i.e. every judge score would
have been NaN. Clamped.
- erode() clamped at the field border, so border texels could never erode out
of the mask and kept those NaNs in scope. Off-grid now counts as outside.
- Timer.connect(document) zeroes dt whenever document.hidden is true, which
froze the sim solid in an embedded browser. Dropped; rAF already pauses for
hidden tabs. App.step(dt) is now exposed so the game can be driven
deterministically for verification.
Also: screen shake was mutating the camera permanently instead of offsetting
it per-render, and the plate's lathe profile touched the axis (degenerate
triangles -> starburst normals) — rebuilt from primitives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>