The pot of oil, from the atlas: oil is the fear mechanic and the double
fry is the physics, not the flavour text. Cold oil soaks (grease). Hot
oil seals — and the seal is REAL: past ~0.8 gold the crust shuts and the
inside stops listening, so one screaming-hot fry gives you 'firm in the
middle — the seal beat the cook'. The honest path is the card's path:
blanch in the shimmer until fluffy, REST on the rack while the steam
escapes (dryness is what golds — the oil spends it, the rack rebuilds
it), then back in HOT for the colour. The basket knocks the oil down a
full degree when it lands, because thermal mass does not care about
your schedule.
THE SPIT is the knuckle lesson with a floor: raw chips in oil past 8.4
throw it back, and a spit only burns the hand PARKED OVER THE POT — the
pointer is your hand, and standing back costs nothing. The judge's row
reads 'it spat 13 times; you did not flinch' or names exactly what the
hovering cost you.
First cut had two dead spots the adversarial pass caught: the seal was
too weak (a single hot fry still cooked through for 9.1) and the spit
window was unreachable (the basket-knock kept the oil under SPIT_AT for
the whole raw phase). Rebalanced: seal 1.25x, gold rate up, spit at 8.4.
Verified: double-fry 10.0 ('proper gold · fluffy inside · dry. drained.
correct · 2 fries — as the card says'); one-hot-fry-hand-hovering 7.6
with 13 burns. Day 24 on the card, procedural arm, ghost demo slot 24,
hero_chips on the scorecard, Ray's portrait already on the ticket.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
John's spec from the atlas, honored verbatim: the basket is a small 2D
tray and ARRANGEMENT is the skill. Six wings arrive DUMPED in a pile;
every piece wants a clear gap to breathe (Clark–Evans inverted — the
same spacing statistics that reward an even topping spread here reward
margins). Smothered wings brown slow and keep a PALE face the judge can
see; steam is a LOCAL sin — a corner pile in an empty tray still steams
(the first cut used global fill fraction, which six wings could never
trip; the adversarial pass caught the dead mechanic and the smother
statistic replaced it). The drawer pauses the cook and bleeds the heat —
hovering costs. The SHAKE is the egg-crack grammar: hold F, release; a
sane charge turns the pale faces to the wind, a full-send puts five
wings on his floor and the corner eye goes horrified.
New station, full rails: sim/airfryer.ts (pure, seeded), the top-down
scene with the sliding basket (snap-out on reset — a stale docked tray
was eating the demo's opening drags), judgeAirfryer (THE CRISP golden
band / THE TURN pale faces / THE AIR steam / THE COUNT floor wings),
day 23 on the card with the cursed recipe card, a procedural endless
arm, fan-whir foley that dies when the drawer opens, ghost demo slot 23,
and the wing man's portrait (high-five not coming).
Verified: honest lattice play 9.5 twice back-to-back; the lazy pile
3.6 ('a steamer wearing a fryer badge', raw, never shaken); full-charge
shake loses 5 of 6 with the horrified eye.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Six blurred backdrops off the FLUX lane — dusk backyard for the grill,
copper-hung splashback for the pan, steaming stockpot shelf for the
poach, butcher's tile for the steak board, pantry shelves for the eggs,
steel cold room for the fridge — and a lesson in frustums for their
integration. A far wall plane (the kitchen splashback trick) is
invisible to these stations' pitched-down cameras: at 45 degrees of
downward tilt nothing above the horizontal ever enters the frame. So
the art ships as the scene BACKGROUND instead — screen-space, swapped
in on enter() and restored on exit() — and the oversized 24x12 bench
slabs that covered every pixel shrank to real bench size so the room
can peek around them. The stations went from furniture in fog to
furniture in a kitchen.
Mechanics untouched by the slab diet — the drag planes are infinite
THREE.Planes, not the meshes: grill/pan/fridge/steak drivers all pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Twenty-two assets off the Cloudflare FLUX lane (scripts/gen-art-batch.sh
— idempotent, fixed seed per character, ~5s each, barely a dent in the
10k daily neurons):
- Thirteen regulars on their tickets, clipped into the corner like a
loyalty card photo: Deidre's floral cardigan, Ray's flat cap, the
child on tiptoes with a fistful of coins, the bloke from two doors
down in his dressing gown, the delivery mid-yawn at 6am, the lunch
rush as three impatient torsos, the pavlova order in her pearls. The
inspector's ticket uses his own portrait; a name with no face made
simply shows no frame (onerror removes it).
- THE MOTHER's jar rendered in all three states on the title button:
bubbling over the rim, sulking under grey liquor, and dead with a
tiny white surrender flag planted in the crust.
- Six dish heroes on the scorecard beside the ask: the skewers, the
pan, the sliced rib eye, the whites bowl, the poached egg mid-drip,
the benedict.
Verified live: pavlova portrait on day 20's ticket, benedict table on
21's, jar_sulking at gap 3, hero_eggs on the eggs scorecard.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Five moods generated on the Cloudflare Workers AI FLUX lane (10k free
neurons a day — scripts/cf-flux.py is the tap): a gaunt man in a black
three-piece suit, burgundy scarf, small round glasses, tiny notebook and
fountain pen, same claymation family as the judge and unmistakably not
him. Fixed seed, expression-only prompt deltas, so he is the same figure
across all five — the horrified one recoils mid-note, the impressed one
wears the small smile of a man betrayed by a good meal.
The grayscale filter is gone: the scorecard and the corner eye both
route by critic day (critic_* / judge_* prefix), demos and dailies stay
the judge's own. Also fixed 'the the count betrayed you' — his rows
already start with THE and he would never stammer in print.
Verified live: day 20 corner eye critic_neutral, scorecard
critic_impressed at 10.0 and critic_disappointed at 4.9 (C stamp, his
lines), day 21 back to the judge everywhere.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Day 12: juice order routed end-to-end (72.8%, 4 pips, THE JUICE beside
THE TOAST on one scorecard). Day 13: the stop-line — proper dice stops
at 0.846 and scores 1.0; through-the-root scores 0.0 at identical CV.
Sting 0.098 quick → 1.0 after 10s idle; the screen blurs to genuinely
unreadable (screenshot-verified). Juicer GLBs landed mid-review.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Juicer verified through __tj: Pyramid 72.8%/4 pips, Juicernaut 100%/all
caught, damaged halve caps at theoretical 0.6, mash 8.5% + pulp,
reversals 77.1% vs 72.8% equal-sweep. Station renders (cone, moat,
filling glass, live HUD). Not yet routed into a day — integration point
documented in sim/juicing.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- button_mushroom / portobello / king_oyster in the ingredient cast:
slippery skins (0.55-0.8, the tomato treatment), soft flesh, portobello
gills layered and weeping; new 'mushroom' cap-and-stem silhouette.
- Verified via harness: dinner knife pressed on a button skates (1 slip,
cut lands 0.157 off-aim; tomato baseline 2 slips / 0.218), The Best
Thing bites clean through under the same press, sawing properly cuts
center with zero slips.
- gen-assets.sh: find MODELBEAST at ~/MODELBEAST, token from
backnforth/.env, MB_HOST to the m3ultra queue; every mb stage retries
10x with 60s pause because m4pro's venvs are gone (ponytail-marked,
remove when m4pro is healed).
- launch.json: port 5273 (5173 taken by another session's server).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Code-complete and verified headless; NOT wired into a day yet (see brief §0.5).
The core, all reusing the M0-M10 bones:
- sim/ingredients.ts: the cast (tomato/orange/onion/garlic/parmesan/brie/
cucumber/avocado/roast_tomato) with shape, skin slip, flesh moisture+layers,
seeds, sting, temperature needs, gratability.
- sim/cutting.ts: CutSession = ingredient + knife + pattern (halve/slices/
wedges/dice), generalizing the M10 slicing sim. New physics: slip (press a
flat blade on slippery skin and it skates, the aim jumps, juice sprays) and
juice (moisture x speed, so deliberate leaks and frantic hoses).
- sim/mess.ts: the bench is judged. Field over the board UV + a solids list;
the wipe is the butter brush in reverse and mass-conserving, so one pass
smears and the second cleans.
- scenes/prep.ts: aim/bite/saw, deepening seams, pieces fan out, juice stain
texture, instanced solids, live 'bench: clean/smeared/a crime scene'.
- judging.ts: The Pieces (CV, w1.3) + The Bench (w0.9); clarkEvans extracted
for M15's toppings; criteria grouped by station and the card grouped with it.
- lines.ts: 8 lines each, in his voice.
Measured, not asserted:
- Even deliberate slices -> CV ~0, bench mass 0.51.
- Sloppy + frantic (0.3 u/frame) -> CV 0.72, mass 18.8, 16 solids, 'a crime scene'.
- Dinner knife pressed on a tomato without sawing -> skates, aim jumps 0 -> 0.12.
The Best Thing under the same press bites in 7 frames, 0 slips.
- Wipe two passes -> mass 0.51 -> 0.09.
Tuning found by playing: slice CV runs over piece WIDTHS not volumes (round
ingredients make end slices thin by geometry — a perfect cut scored 0.40, which
is a geometry lesson, not a skill test); juice coefficient 0.5 -> 0.1 (the first
tomato flooded the board before the second cut).
Assets: gen_3d retries once per stage, bakery seeds bumped, prep cast queued.
2D landed (bruschetta_hero, wonderslice_bag). 3D is BLOCKED: every bg_remove
fails because m4pro's disk is 100% full. Procedural stand-ins carry the bench.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A particulate spread. The jelly is ordinary rheology; the rind is discrete
solids that ride the knife and drop off per unit of stroke DISTANCE, not per
second — a dabbing knife makes a pile, a moving knife lays a trail, and since
the shed rate scales with what's left on the blade, one dip cannot cover the
slice. Even rind takes several dips placed with intent. Scraping picks bits
back up (60% survive the blade), so a clump can be argued with.
The judge scores the scatter with the Clark–Evans nearest-neighbour index over
the bread's own area, and quotes it: R near 0 is one clump, 1 is random, above
1 is deliberate. Verified end to end on day 8:
dab in a corner 8 bits "one clump (R 0.24)" drags grade to B
three placed dips 24 bits "evenly strewn (R 1.17)" A, 8.9/10
First cut shed per-second; even careful strokes dumped the whole load in the
first half-second and scored "clumped (R 0.50)". Distance-based shedding is
what makes evenness the reward for technique rather than luck.
Rind renders as instanced chunks parented to the slice mesh, so it rides the
pop, the landing, and the pedestal turn. Points, not a field: the judge wants
nearest-neighbour statistics, and those want points.
Same sRGB trap as M3, new spot: the instanced material's colour was passed as
raw floats, which the renderer reads as linear — candied orange rendered as
pale butter. setRGB(..., SRGBColorSpace).
New content: day 8 handwritten (Deidre wants a piece in every bite), marmalade
in the procedural pool, five rind-district lines for the judge, and a marmalade
jar GLB generated on-device like everything else, with a plain-glass fallback
while it loads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Knife angle (wheel) is the only input, and spread/scrape/gouge all fall out of it.
Verified by driving real input through the real code paths:
cold toast + fridge butter -> damage 0.015, spread 0.029 (tears, as designed)
fresh warm toast -> damage 0, spread 0.117 (flows cleanly)
burnt toast, knife on edge -> char 99.9% -> 82.7% -> 54.5%
evenness 0.029 -> 0.123 -> 0.226
pale toast, knife on edge -> gouges; steak knife gouges 3.2x harder
That evenness column is the mechanic: scraping rescues you from char and wrecks
uniformity doing it. The judge will have opinions.
The trap is calibrated, not hoped for. Pressure comes from steepness, but past
SCRAPE_ANGLE the knife stops spreading:
fridge butter / cold toast yield 0.72 needs angle 0.75 IMPOSSIBLE
bench butter / cold toast yield 0.54 needs angle 0.57 (cliff at 0.62)
fridge butter / fresh toast yield 0.36 needs angle 0.38 fine
soft butter / fresh toast yield 0.16 needs angle 0.12 dream mode
So cold toast + hard butter cannot be spread at any angle, and the way out isn't
technique — it's not dawdling. The pressure gauge draws both marks so you can
see the gold sitting past the red and understand why you're losing.
Emergent and kept: a steak knife's narrow blade concentrates pressure enough to
beat cold butter's yield. It's the right tool for cold butter and a menace
everywhere else.
- cutlery.ts: 9 hand-authored archetypes (silhouettes are gameplay — the drawer
has to be fair) + compound box colliders for M4.
- dev.ts: harness that drives real gestures deterministically. Earns its keep.
Two bugs: cutlery meshes used mesh.rotation.x = -PI/2, which sends a profile
drawn toward +y to -z and one drawn toward -y to +z — the handle and blade were
laid out in opposite directions, overlapping, nowhere near the cursor. Now
rotated at the geometry level. And resize() computed aspect = 0/0 = NaN when the
container reports zero, which poisons the projection matrix so every raycast
silently misses — i.e. the entire mechanic stops with no error.
Metals need something to reflect: added a RoomEnvironment IBL and rebalanced the
direct rig, which was tuned before it existed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
The bread slice is the whole game's canvas, so it's built first and properly:
- Field: a 128x128 scalar field with bilinear sample, a mass-conserving brush,
self-levelling relax, and the masked statistics the judge will read.
- Slice: extruded loaf silhouette (domed top), planar-projected UVs so the sim
grid lines up with the bread, per-texel silhouette mask, and four fields
(browning/dryness/spread/damage) packed into one RGBA8 texture per frame.
- Custom shader: browning ramp with blotchy char, crumb/crust/inclusions,
spread wetting + opacity + thickness relief, gloss, gouge exposure, and
flat data views for the judge screen.
- bread.ts / spreads.ts: the archetypes and the rheology the difficulty
curve will live in.
- scripts/gen-assets.sh: reproducible fixed-seed asset generation through
MODELBEAST (flux_local -> bg_remove_local -> hunyuan3d_mlx). All on-device.
Legibility work that mattered: butter rendered invisible at first. Fixes were
a gamma-style wetting darkening (a multiply *brightens* pale crumb), a normal
perturbation taken in UV units rather than raw texel deltas (~30x too small),
and pulling the lighting back under 1.0 so ACES stops desaturating yellow to
cream.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>