RhythmGen is a 6-lane rhythm game that generates playable charts from audio. The project is built around one shared engine with thin platform wrappers for web, Chrome extension, and Windows desktop.
Phase 1 is the web app: upload an audio file, run the pipeline, generate a chart, render gameplay state, and show stats.
Requirements:
- Node.js 20 or newer
- pnpm 9 or newer
Install dependencies:
pnpm installRun the web app locally:
pnpm --filter @rhythmgen/web devOpen the Vite URL printed by the command, usually:
http://localhost:5173
Upload any audio file. The upload decodes the audio to PCM, runs frame analysis, groups frames into musical phrases via music-interpreter, and generates a chart. You should see a chart summary with frame count, locked note count, engine stats, and a lane preview.
Build everything:
pnpm buildRun all unit tests:
pnpm testRun all typechecks:
pnpm typecheckRun web integration tests:
pnpm --filter @rhythmgen/web build
pnpm --filter @rhythmgen/web test:integrationRun the full integration target:
pnpm test:integrationBuild the WASM analyzer, once Emscripten is installed:
pnpm build:wasmThe main rule: strengthen the shared engine and keep platform wrappers thin.
Pipeline:
audio file → decoded PCM → AudioFrame[] (analyzer/WASM) → MusicalPlan (music-interpreter) → PlacementFacet.generate() → LockedNote[] → GameplayEngine + RhythmRenderer
chart-planner is an optional rhythm-game-specific default planner (pattern-selection based) that can be used instead of a custom PlacementFacet.
Package responsibilities:
packages/shared-types: interfaces, constants, and enums only. No logic, no dependencies.packages/engine: gameplay clock, judgment, scoring, combo, stats.packages/analyzer: TypeScript bindings for the C++ to WASM analyzer.packages/music-interpreter: frame enrichment, 2-beat phrase grouping, canonicalinterpretFramesentry point.packages/chart-planner: optional rhythm-game-specific default planner — pattern templates, phrase planner, note placement, note locking.packages/audio-graph: dual-path audio graph, with raw analysis and delayed playback paths.packages/renderer: gameplay-facing render state, note pooling, lane effects.packages/input: keyboard/touch dispatch and calibration helpers.apps/web: browser upload flow and package integration shell.
Authoritative timing uses the delayed playback timeline, not raw capture time. Notes are locked before they become renderer-visible.
- The WASM analyzer worker is behind an injectable factory; in-browser runs fall back to synthetic analysis frames until the WASM artifact is built.
- Renderer state is intentionally simple and design-light.
- Final UI styling and assets should happen in a separate design pass.
- Persisted settings for calibration and keybindings are tracked as a follow-up.
Work rules:
- Always work on a feature branch.
- Do not commit directly to
main. - Prefer one package per task.
- Add or update tests with behavior changes.
- Run relevant package checks before considering work complete.
- Run full workspace checks before phase checkpoints.
- Update
STATUS.mdbefore stopping. - Do not push unless explicitly asked.
Commit format (conventional commits):
feat(scope): short title
fix(scope): short title
refactor(scope): short title
docs: short title
Before committing a phase step:
pnpm --filter <package-name> build
pnpm --filter <package-name> test
pnpm --filter <package-name> typecheck
pnpm build
pnpm test
pnpm typecheckFor web integration work, also run:
pnpm --filter @rhythmgen/web build
pnpm --filter @rhythmgen/web test:integrationRead STATUS.md before starting work. It records the current phase, completed work, discovered follow-ups, and decisions made during implementation.