Files
symph/README.md
T
2026-07-15 01:28:56 -04:00

89 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Symph
Rhythm-driven grid traversal. Real-time spatial movement over a quantized musical beat, on a 3×3 grid.
## Concept
A song advances one chord at a time on the beat (the Z-axis). Each chord is a 3×3 matrix of notes. The player holds a cell on the grid and moves across lanes (X) and rows (Y) to collect items and avoid walls. Lane shifts persist; row shifts are transient and collapse back to the base row after a fixed number of chords — a jump you must ride out or duck out of. Returning into a wall on landing is fatal.
The engine is a deterministic, side-effect-free state machine. Rendering and input polling run at host framerate (~60Hz), decoupled from beat progression. Frontends translate native input to platform-neutral actions and drain queued gameplay events into audio.
## Mechanics
| Item | Glyph | Effect |
|---|---|---|
| Energy | `*` | +1 energy, consumed on contact |
| Magnet | `M` | sweeps every Energy note in the lookahead window, all grid positions |
| Shield | `S` | arms one absorb charge; no expiry |
| Boost | `B` | doubles tempo for a fixed duration; refreshes, does not stack |
| Wall | `#` | fatal, unless a charge absorbs it or a Boost is active |
Two persistent effects (Shield charges, Boost deadline) cross level boundaries and clear on death. A Boost grants wall immunity but the field keeps rendering walls lethal — Boost expiry inside a wall band is the primary death mode.
## Build
```sh
make build-term # terminal frontend (symph-term)
make build-raylib # raylib frontend, linux only (symph-raylib)
make test
```
Requires Go 1.26+. The raylib frontend builds CGO-free (embedded `.so`, linux amd64/arm64).
## Run
```sh
bin/symph-term
```
### Controls
Vim-style bindings:
- `h` `j` `k` `l` — left, down, up, right
- `Enter` — restart after game over
- `Ctrl+S` — toggle mute
- `Esc` / `Ctrl+C` / `q` — quit
Host controls (quit, mute) bypass the engine and work in every phase, including paused.
## Frontends
- **Terminal** (`symph-term`): full Unicode glyph set, density-shaded walls, wall-band colored borders. Pauses and shows a notice below minimum viewport size.
- **Raylib** (`symph-raylib`, linux): same presentation contract, drawn with primitives. Substitutes ASCII for the Unicode atlas (default font covers codepoints 32..126); draws walls as rectangles.
Both share the grid-scan and burn-out projection pipeline in `render`; presentation policy lives there, not in the engine.
## Audio
Fire-and-forget effects, PCM synthesized at startup. PipeWire backend (`pw-play`) on Linux; silent `nullEngine` elsewhere or when `pw-play` is absent — the game stays playable without audio. FreeBSD (sndio/OSS) is unimplemented and falls through to silence.
## Layout
Unidirectional dependency flow (supports a future CGO/gomobile mobile target):
- `types/` — dependency-free structures and the value registry (identity, glyph, polarity)
- `parameter/` — compile-time constants: grid bounds, timings, glyphs, geometry
- `game/` — pure state engine; contact behavior and persistent effects
- `input/` — native key → neutral `Key``game.Action`
- `render/` — appearance tables and the shared draw pipeline; `render/raylib/` is the graphical frontend
- `audio/` — synthesized effects and platform backends
- `cmd/` — hosts: wiring, event poller, ticker
Adding an item kind is three rows — identity (`types.valueSpecs`), behavior (`game.resolvers`), appearance (`render.valueVisuals`) — with no switch edits. `init` asserts registry completeness at process start.
## Status
Early development. Terminal and raylib frontends are functional.
Planned:
- **Android** frontend via `gomobile` (`mobile/`, `platform/android/`). The `input` package is bypassed on that path — touch/gesture translates directly to `game.Action`.
- Symphony (multi-song) and Symphace (bounded environment) domain layers.
- Persistent audio stream to replace per-effect `pw-play` spawns before latency matters.
- FreeBSD audio backend (sndio/OSS).
## License
See `LICENSE`.