Stage 05 — Charting by Playing
You will build: a recording mode — play the song, tap the lanes, and your taps become a chart you can immediately play back. You'll learn: building tools inside your game · runtime data hygiene — and you'll make design decision 3 from the architecture doc. Warm-up — from memory: which of the three latencies shifts judgment only, and why recording must care about it.
Why this exists#
The prototype had a recording feature that could never run — you proved that in the bug hunt. Now build the real one, because hand-placing beats in an inspector is how charts don't get made. Every real rhythm game charts by playing: the charter taps along, the game captures beat timestamps, and the captured taps are the chart. The subtlety — and the reason this is a stage, not a feature checkbox — is that your taps arrive late by your own input latency. Record them raw and every chart you make is systematically late; every future player inherits your keyboard's lag.
Build it#
A — The capture#
A recording mode (project setting, debug key, whatever you choose — deliberately): while
the song plays, each lane press appends a NoteData with the current beat and lane. Decide
consciously which beat you capture: raw song-time beat, or input-latency-corrected beat.
One of them bakes your hardware into the data. The warm-up question is the answer.
B — Where the recording goes (decision 3)#
The architecture doc lays out the trap: writing into the loaded ChartResource mutates a
shared resource at runtime — the exact anti-pattern the audit taught you. Decide where
recorded notes live and how they become a real chart file, record the decision, then build
it. Whatever you choose: recordings must survive the game closing, and must never write
into res:// (exported games can't — the bug hunt's disk grinder already taught this;
user:// exists for exactly this).
C — Playback#
Load a recorded chart and play it. First recording will be rough — that's signal, not failure. Re-record the same 20 seconds three times and watch your consistency improve; you're calibrating the charter (you) as much as the tool.
D — Round-trip check#
Record → close the game entirely → reopen → play the recording. If that works, your data pipeline is honest. Commit.
git add . && git commit -m "stage 05: chart recording with latency-corrected capture"
Checkpoint — definition of done#
- A chart recorded by playing exists as a file, outside
res:// - It survives a full game restart and plays back correctly
- You can state, in one sentence, why the captured beats were (or deliberately weren't) latency-corrected
- Decision 3 recorded — and if you chose the buffer-then-promote route, one recorded chart has been promoted into the project and plays like any built-in song
- The loaded built-in chart resource is never mutated — prove it: record over a built-in song, restart, confirm the original is intact
Stretch (no instructions)#
A metronome tick during recording (the conductor already knows the beat) — and notice what hearing the tick does to your tap accuracy.
If you get stuck#
- Recorded notes all feel early on playback → you corrected latency twice (once at capture, once at judgment). Draw the signal path on paper: press → capture → save → load → judge. The correction belongs in exactly one arrow.
- File isn't there after restart → print the absolute path you wrote to
(
ProjectSettings.globalize_path("user://...")) and go look at it in the file explorer. - Playback ignores the new chart → is the game still loading the
.tresit always loads? Follow the chart from disk to the spawner by hand.