Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
# tetris
# games

Tetris for **Space Console** — a game that runs on the launcher (the TV/screen),
driven by the same shared **intent vocabulary** (`up/down/left/right/enter/back`)
the launcher and controller already speak, so a phone controller can drive it
later with no changes.
The game collection for **Space Console** — 30+ self-contained games that run on
the launcher (the TV/screen). Each lives in its own folder (`tetris/`, `snake/`,
`chess/`, `poker/`, `minesweeper/`, `yardline-rc/`, …) and is launched into the
launcher's persistent iframe shell.

Every game is driven by the shared **intent vocabulary**
(`up/down/left/right/enter/back`) the launcher and controller already speak, so
the same game works from a keyboard, a TV remote, a gamepad, or a phone controller
relaying those intents — the game is a pure consumer of the stream. Steering games
additionally accept continuous **analog** driving frames.

Zero-build, zero-backend static site — plain ES modules, no bundler, no
framework. Open `index.html` and it runs.
framework. Open any game's `index.html` and it runs.

```sh
npm install # dev server only
npm run dev # http://localhost:5175 (auto-reload)
npm install # dev tooling only
npm run dev # http://localhost:5175 (auto-reload) — serves the folder
```

## Controls
## Embedding contract

Everything routes through the shared intent layer (keyboard / TV remote / gamepad):
Shared helpers live in `assets/js/shared/` (`input.js`, `controls.js`,
`roster.js`, `stats.js`, `sound.js`, `touch.js`). A game subscribes to the intent
stream via the shared `Input` layer and talks to the launcher shell over
`postMessage`:

| Intent | Keyboard | Action |
| Direction | Message | Meaning |
| --- | --- | --- |
| left / right | ← → (or A / D) | Move piece |
| up | ↑ (or W) | Rotate |
| down | ↓ (or S) | Soft drop |
| enter | Enter / Space | Hard drop · start · resume |
| back | Esc / Back | Pause · return |
| shell → game | `sc:intent {intent, player}` | a button press, tagged with the sender's seat |
| shell → game | `sc:analog {steer, throttle, brake, handbrake, player}` | a driving frame (steering games) |
| shell → game | `sc:players {players}` | the current roster |
| game → shell | `sc:controls {profile, buttons}` | which phone pad to show (`dpad` / `buttons` / `analog` + aux) |
| game → shell | `sc:gameover {kind, …}` | report a score / 2-player result to the stats store |
| game → shell | `sc:back` | exit to the menu |

Most games are plain ES modules with no build step. The one exception is
`yardline-rc`, a **prebuilt** Babylon.js/Vite 3D bundle: it's copied verbatim and
NOT cache-busted (see `scripts/stamp.mjs` `NO_STAMP`, and `yardline-rc/BUILD.md`).
`rc-rush` is a plain-canvas pseudo-3D racer, no build needed.

## Documentation

All docs live in the **wiki** repo (the org-wide hub), not here:

- Service docs: `wiki/docs/services/tetris/`
- Service docs: `wiki/docs/services/games/`
- How we build, deploy, and review across repos: `wiki/docs/way-of-working.md`

Published site: `main` deploys to the Pages root; feature branches get a preview
at `/preview/<branch-slug>-<hash>/`. Scripts are cache-busted at deploy time
(`npm run build` → `_dist/`); local `npm run dev` stays build-free.
(`npm run build` → `_dist/`), except the prebuilt bundle noted above; local
`npm run dev` stays build-free.
Loading