# Context — molehill-2d (Incanto)

## Project Overview

**Molehill** — a WHACK-A-MOLE you play with the mouse and nothing else. Nine
holes in a turf field; a mole pops out of one of them and ducks back a little
faster each time. Click it and you score; let it go and you have missed. Twelve
moles wins, three misses loses.

It is the clone-and-modify starter for **games you play by pointing**: match-3,
tower defense, cards, point-and-click, RTS, board games, idle. Every other
starter is a character you WALK, and that difference reaches further than it
looks — there is no `CharacterController`, no `move` action, no gravity and no
player body anywhere in the scene.

The scoring, the lives, the sounds and the game-over are BUILT-IN gameplay wired
in `game.scene.json`. The custom TypeScript is only the two things JSON cannot
say: when a mole pops, and what the HUD shows.

## Tech Stack

_Exact versions are in `package.json`._

- **Engine**: `incanto` + `incanto/2d` (createGame2D; Node2D, ColorRect2D,
  AudioPlayer, HudLayer/UiText/UiBanner/UiButton) + `incanto/gameplay`
  (auto-registered `Clickable`, `ScoreKeeper`).
- **Art**: none. Every visual is a `ColorRect2D` — the field, the holes, the
  moles. Swap in sprites by changing the node types and adding an `assets{}`
  block; nothing in the logic knows what a mole looks like.
- **Audio**: procedural presets (`coin` on a hit, `hurt` on a miss) — zero files.
- **Input**: the pointer. `createGame2D({ pointer: { lockOnClick: false } })` —
  locking would HIDE the cursor, which is exactly wrong for a game you aim.

## The one thing to understand

`Clickable` is a behaviour on each mole. It emits `clicked(node)` and nothing
else, and the scene wires all nine of them to ONE handler:

```jsonc
{ "signal": "clicked", "from": "Field/Hole00/Mole", "to": "Field", "handler": "onMoleClicked" }
```

The signal carries the node it happened on, so one handler serves the whole
board. A `Clickable` nobody listens to is reported by `incanto-check` — it can
never do anything, and forgetting the wire is the mistake this genre makes.

## Verifying it

`bun run verify` drives the MOUSE, which is the only input this game has:

```ts
{ atMs: 1000, click: (ctx) => moleUp(ctx) }   // click whatever is up right now
```

`click` takes a node path, a point, or a function for the case a mouse game is
usually in — the target cannot be named when the script is written. Headless
there is no renderer and therefore no raycast, so `runScript` installs a
geometric picker; a game with a picker of its own keeps it.
