import InfoBox from '../components/InfoBox.astro'

A player ahead on score in a duel could just crash on purpose, wall or own tail, and win on the spot, sometimes after only a handful of words. Nothing in the rules discouraged it: a collision ended the game immediately, and whoever had more points at that instant took it. The 40-word cap both duel modes had carried since early on didn't fix that, it just meant the same shortcut worked before word forty instead of at it. Two issues named the problem separately, removing the cap and reworking how a winner gets decided, and a wayfinder map, [PvP lives system and remove word limits](https://github.com/ken-guru/the-words-are-snake/issues/560), resolved them together as one design.

The map locked its decisions before any implementation started: lives are PvP-only, three to start, uncapped through hearts picked up along the way, and a collision costs one rather than ending the game outright. PvE keeps its original rule, first collision ends it, higher score wins, since a solo game against the AI has no opponent for a crash-to-win incentive to exploit. Four child tickets worked out the visuals, the heart-spawn rule, and the teaching hints against that one locked shape, with throwaway UI prototypes built and reviewed before any of it touched the real engine.

The rule change itself is a small branch in the turn-resolution code, and the contrast is the whole point:

```typescript
if (livesEnabled) {
  // A collision costs a life; the game only ends at zero, and then the
  // survivor wins regardless of score (#552).
  actorLives -= 1;
  if (actorLives <= 0) {
    newPhase = 'game-over';
    newWinner = isPlayer ? 'opponent' : 'player';
  }
} else {
  // PvE: the first collision ends the game; scores decide who wins.
  newPhase = 'game-over';
  if (newPlayerScore > newOpponentScore) newWinner = 'player';
  // ...
}
```

Crashing into a wall no longer hands the win to whoever was ahead a moment earlier; it costs a life and the game keeps going; the only way to win off a collision now is being the one still standing when lives run out.

<InfoBox title="Hearts spawn once, worth one thing">
  The first player to cross each 1000-point line spawns a heart, tracked by a
  single watermark shared by both players so a milestone already crossed never
  fires twice. Eating one grants exactly one life: no points, no snake growth,
  no combo participation. Any of those would have let a heart pickup start
  chaining into score, which would have reopened the same crash-for-score
  incentive the whole system exists to remove.
</InfoBox>

The visual side reached across all three modes rather than staying PvP-only. A collision now plays as a darkening wave from head to tail, fifty milliseconds between segments, three hundred milliseconds per segment, reduced-motion aware, replacing what used to be an instant snap to game-over. A new `WordChars` component absorbed three separately duplicated letter-rendering implementations into one, with entered, processed, current, and collision states shared everywhere a word gets typed. Teaching stayed reactive rather than upfront: a hint on a player's first collision, another on reaching their last life, one on the first heart spawn, all shown once per game and all bilingual, matching the no-em-dash rule the map's own notes had already written down for itself.

Eighteen new tests pin the lives rules directly at the engine seam, on top of service-level and serde coverage for the zero-lives ending and the guest-side perspective swap; the full suite closed the day at 1,272 tests. What's left is deliberately outside this pass: an end-to-end path exercising a mid-game collision that doesn't end things, hint flags that currently only remember they've fired for the length of a browser session, and a gameplay recording that still shows the old single-collision ending.