# Status — platformer-2d (Incanto)

## Implemented

- Full-window single-canvas page with loading overlay, an on-screen JUMP button,
  and the iframe GAME_SIZE harness.
- `game.scene.json` — **Castle Run**: viewport (`design [960,540]`, `fit:
  expand`), `physics.gravity [0,1800]`, `move` (A/D + arrows) / `jump`
  (Space/W/Up) input, `knight`/`goblin` sheets + `coin`/`gem` textures, and the
  level —
  - `Game` root: `ScoreKeeper` (`scoreToWin 100000`, `lives 3`).
  - Parallax castle backdrop (sky, sun, clouds, far castle band + towers, near
    castle band + battlements) via `ParallaxLayer`.
  - `GroundA–D` stone with green moss caps and gaps; `Plat1–4` floating
    platforms; `MovePlat` (`Patrol` horizontal) + `Lift` (`Oscillate` vertical),
    both group `platform` (rideable).
  - `Spikes1/2` (`hazard`), `DeathPlane` (`pit`), `Checkpoint`, `Goal`.
  - `Gob1–3` goblins (`Patrol` + `GoblinSkin`, group `enemy`).
  - 12 coins + 2 gems (`Pickup` + bobbing `Oscillate` sprite).
  - `Player` (`CharacterBody2D` + `PlayerController`) with `Skin` (knight) +
    `Feet` sensor; `Camera` (`FollowCam`); SFX players; HUD + banner UILayers.
- Custom code in `src/behaviors.ts`: `PlayerController` (coyote/buffer/double-
  jump/variable height/stomp/knockback/hearts+lives/checkpoint respawn/platform
  carry/anim), `GoblinSkin`, `FollowCam` (follow + shake), `ParallaxLayer`,
  `HudUpdater`. Particle puffs on double-jump/stomp/land/checkpoint via
  `Particles2D`.
- `connections`: each coin/gem `collected → addScore` (+ SFX); root `won/lost →
  SfxWin/SfxLose`.
- `App.tsx`: inject the four asset urls, `createGame2D`, optional music, JUMP
  button, remove loader, expose `window.game`. Node uids omitted (loader-
  generated).

## Works (verified)

- `bun run check` → 1/1 scene valid. `bun run typecheck` → clean. `bun run lint`
  → clean.
- `bun run verify` (headless `runScript`): 13/13 assertions pass — run right,
  jump off the ground and settle, a coin raises the score (Pickup → addScore), a
  STOMP removes a goblin and scores, a side hit costs a heart, dying respawns the
  knight at the checkpoint, the goal emits `won` once, and a pit fall with the
  last life emits `lost`.
- Played in a real browser (`bun run dev`, Playwright-driven): the knight + the
  goblins render as their real animated sheets; coins/gems render as sprites;
  ground has moss caps; the parallax castle bands scroll; HUD shows ◆ coins,
  ♥♥♥ hearts and lives. A tap jump is a short hop (~41px), a held jump is full
  (~156px), and a mid-air press double-jumps — variable height + double-jump
  confirmed. FollowCam tracks + clamps to the level bounds. ZERO console errors.

## Not Included (on purpose — and the next polish passes)

- Background castle is styled `ColorRect2D` (no tilemap node in v0): two parallax
  layers (`CastleFarLayer` 0.82 / `CastleNearLayer` 0.6), each a Node2D with ONE
  `ParallaxLayer` whose children (wall band + towers + crenellation merlons + warm
  glowing windows + a gate + a pennant) inherit the scroll. Reads clearly as a
  castle skyline; swap for tile/sprite art later.
- No wall-jump/dash, no enemy variety beyond the goblin, no melee (the knight
  has an attack sheet 12–17 if you want it), no bundled music (SFX presets only).
- One hand-authored level — extend by copying nodes into the right GROUP
  (`enemy`/`hazard`/`pit`/`checkpoint`/`platform`); `PlayerController` picks them
  up with no extra wiring.

## The round's surfaces, in 2D (2026-09-04)

A course past GroundD (x 3000+): `Trampoline` (`restitution 1`) with a dead `Bouncer`, `Ice`
(`friction 0`) with a `Sled` at 260 px/s, and a `Hound` (`CharacterBody2D` + `Chase`
`ground: true`) under a `Perch`. `verify.ts` measures the rebound (287 of 300 px), the slide
(400 px of ice) and that the hound stays on the floor under a perched player.

## Pausing

ESC pauses and shows the pause menu; OPTIONS opens the settings over it and
BACK returns to the menu that asked. All of it is `GameFlow` (`pausePanelPath`,
`screen(path)`, `back()`) wired with `connections` — there is no TypeScript for
any screen in this game.
