# Neon Nexus presentation (provider-game-demo)

Play-money presentation for Neon Nexus. The legacy internal
`game_id=orbit-breaker` remains unchanged for launch and wallet compatibility.

## Authority split

- Server (`services/orbit-games`) owns immutable outcomes
- Client (`demos/apps/provider-game-demo`) only presents `POST /v1/rounds` results
- Spin speed / fast-stop / autoplay change timing only

## Client structure

```text
src/game/NeonNexusGame.tsx
src/game/neon/
  SlotRenderer.ts      # Pixi reel strip presentation
  layout.ts            # centralized 5×4 / 5×5 geometry
  roundState.ts        # READY → … → PRESENTING_WIN → READY
  audio.ts             # intro crossfade, mute persistence
  viewport.ts          # fullscreen, incl. iOS fallback + operator frame request
  winPresentation.ts   # return / standard / big / epic thresholds
public/neon-nexus/     # symbols, music, CSS, math-config, licenses
```

## Win tiers

| Tier | Condition | Full-screen celebration |
|------|-----------|-------------------------|
| Return | `total <= bet` | No |
| Standard | `> 1×` and `< 10×` | Yes |
| Big | `>= 10×` and `< 50×` | Yes |
| Epic | `>= 50×` | Yes |

## Motion

Phones report `prefers-reduced-motion: reduce` for Reduce Motion and Low Power
Mode, which is why the panel's **Motion** setting (`auto` / `full` / `minimal`)
overrides it. Reduced motion removes movement, not information: reel travel
shortens and anticipation drops, and win screens still open — held static and
longer, since there is no count-up to watch. Only `minimal` (or spin speed
`instant`) lands the grid with no travel at all.

The effective choice is mirrored onto `<html class="app--reduced-motion">` so
CSS keyframes follow the player's override rather than the media query.

## Commands

```bash
cd demos/apps/provider-game-demo
npm run dev
npm test
npm run build   # → dist/
npm run simulate
```

See also `docs/neon-nexus-math.md`, `docs/neon-nexus-integration.md`, and
`demos/apps/provider-game-demo/INTEGRATION.md`.
