A course is now a plain data object (boxes + machines + cannons + spawn/finish)
built by buildCourseFromSpec, which dispatches to the greybox box builder and
the Lane C machine factories. New courses are DATA, not a game.ts fork; load one
with ?course=<name>. Added COURSES.toaster = Toaster Alley, a flat, reliably
completable second level that puts the never-placed FAN into play (tailwind) and
reuses the mine→gate loop from a spec.
game.ts refactor: Breakfast Rush's tuned build moves verbatim into
buildBreakfastRush (returns its finish box); installGame picks the course by
?course=, parametrises the race loop's finish + respawn spawn, keeps a per-course
best time, and adds a small on-screen course switcher. Breakfast Rush is
untouched behaviourally (greybox now builds after the blob — colliders still
exist before the first physics step).
Deliberately NOT done: porting the finely-tuned Breakfast Rush to a spec (no
gameplay gain, real regression risk), and placing a see-saw (it's a supported
spec kind but wants an elevated bridge = deliberate level design).
Browser-verified: Toaster Alley completes end-to-end (best 4.73s saved under its
own key, green mine→gate loop opens the line); Breakfast Rush unchanged (spawns
on the plateau, crosses the gap-jump, puddles paint it). tsc + vite build green;
all 10 test suites pass (360 assertions).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>