v0.1.0 initial commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# 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`.
|
||||
|
||||
Reference in New Issue
Block a user