2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00
2026-07-15 01:28:56 -04:00

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

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

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 Keygame.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.

S
Description
No description provided
Readme
78 KiB
Languages
Go 99.5%
Makefile 0.5%