Integration-only (no logic changes). Validated the full candy vibe in the booted
iPhone sim and brought every artifact in line with the shipped candy palette +
Triple Treat SFX bank.
Goldens — swept all 23:
- Refreshed 15 that predated the candy palette (P12): p6_idle_t0, p6_idle_mid,
p6_select, p7_restart, p5_swap_before/after, p6_anim_swap/clear/fall/after,
p6_fx, p6_fx_after, p6_fx_match, p6_inputlock_board, p11_combo_deep — re-captured
via the documented M3TE_* hooks.
- Left 5 unchanged (board+HUD region byte-identical to the current build, verified
by cropped-region hash): p4_board, p4_hud, p9_polish, p7_win, p7_lose.
- Removed 3 obsolete pre-board orange-quad goldens (app no longer renders them):
p0_quad, p0_input_before, p0_input_after.
Docs — README.md:
- Section 2 now describes the candy board (not the old orange quad) and points at
goldens/p6_idle_t0.png; dropped the removed p0_* references.
- Added the final audio model: Triple Treat SFX provenance + per-cue mapping, the
per-round ascending cascade (one combo cue per round, clamped at combo5), the
WAVE/mono/44100/Int16 @ -15 dBFS format spec, and the cue-log capture commands.
- Added image-art asset regeneration (codex imagegen via codex exec + sips
normalize to exact per-asset dims/format).
Gate: ios-sim build links (exit 0); 21/21 pure-sx logic tests pass. Playthrough
evidence (cue NSLog ascending combo1..combo5 + win/lose stingers, screenshots)
captured in the worker report.
Polish pass before final acceptance. The 8x8 grid was rendering flush to the
left/right screen edges (gems ~4pt from the bezel on iPhone 17). Add a content
margin (BOARD_INSET_X = 16pt) layered on top of the platform safe-area insets so
the grid is framed by the background, while the HUD keeps using the bare safe
insets so it still hugs the top below the Dynamic Island. The grid is
width-constrained in portrait, so this inset is what sizes it; vertical
centering inside the safe area is unchanged, and the win/lose banner (derived
from the grid) stays centered over the framed board.
Safe-area verified on a current iPhone simulator (iPhone 17, iOS 26): HUD below
the Dynamic Island, board far above the home indicator, forced win/lose banners
centered and unclipped.
The headless geometry tests (hit_test, banner_layout) call compute() with a
zero inset directly, so they are unaffected; full logic gate stays green (18/18).
Goldens: add p9_polish.png (resting board, M3TE_ANIM_TIME=0) as the canonical
polished layout. Re-capture the README-documented deterministic goldens whose
board position shifts by the 16pt margin (p4_board, p4_hud, p6_idle_t0,
p6_idle_mid, p6_select, p7_win, p7_lose, p7_restart). The in-flight move-timeline
goldens (p5_swap_*, p6_anim_*, p6_fx_*, p6_inputlock_board) and the p0 quad
goldens are not reproducible via the documented env pins (which pin only the idle
clock + level state), so they are left as-is.
Extend the HUD to show the per-level goal (SCORE x / target) alongside
moves. When the model's level_status (P7.1) is won/lost, draw a centered
overlay banner ("YOU WIN!" / "OUT OF MOVES") with a "PLAY AGAIN" restart
button over the dimmed board; the banner appears once any winning/losing
cascade animation settles. Status is read from the model, never recomputed
in the view.
A finished level freezes board-cell input; only the restart button is live.
Its rect is derived from the shared BoardLayout grid (new BannerLayout), so
the hit-test lands exactly on the drawn button. A tap reseeds the same
starting level through board.restart and clears the transient view layers,
returning to a clean in_progress board.
Banner is text + rects only (honours colour/alpha; no draw-time image tint,
issue 0002). New env capture hooks (M3TE_TARGET / M3TE_MOVE_LIMIT /
M3TE_RESTART) force a terminal status / restart for deterministic goldens.
Tests: tests/banner_layout.sx locks the restart button rect <-> hit-test
round-trip headlessly. Goldens p7_win / p7_lose / p7_restart captured on the
iOS simulator.