Fboard: adaptive music¶
Written 2026-10-27 from the project's own docs.
Fboard's music is written as code, not shipped as finished audio files. A score of short repeating patterns is arranged into sections, and gameplay decides which section plays, how intense it is, and how fast. The engine behind this is a Rust crate, fboard_music.
Built, measured, not yet heard
The engine is the deliverable so far. The current score is a placeholder and has been judged not good enough; the musical direction (genre, references, instruments) has not been set. The project's notes say nobody has listened to the in-game music yet: levels and timing were measured, not judged by ear.
The idea¶
The direction given for the music was: code-written dynamic music instead of finished media files, with tempo, intensity and section driven by gameplay, and Strudel as the authoring tool.
Strudel is a live-coding music environment built on the TidalCycles pattern model: you write short expressions, such as s("kick ~ snare ~"), that describe what plays in each cycle (in Fboard's score, one cycle is one bar). Strudel is licensed under the AGPL, so it stays a local authoring tool and nothing of it ships in the game. Instead, Fboard has its own engine that understands a subset of Strudel's syntax, so a pattern can be auditioned in Strudel and then played by the game.
What fboard_music does¶
fboard_music is pure Rust with no game engine and no audio device in it:
- Exact time. Musical time is kept as exact fractions, not floating-point seconds, so patterns never drift.
- Patterns, following the published Tidal/Strudel model but written fresh rather than ported.
- Mini-notation, Strudel's compact string syntax for rhythms (
"[kick ~ ~ ~ kick ~ kick ~]"). - A Strudel-compatible subset of functions: sound and note controls (
s n note gain velocity speed pan attack release clip begin), combinators (stack cat seq) and transformations (fast slow rev late early degradeBy). Anything outside the subset is a loud parse error, never a silent difference. - Instruments: built-in synthesized instruments (
kick snare hat openhat clap bass lead pad, plus distortedguitarandmutepower chords) and an optional curated folder of WAV sounds. That folder is empty by design until sounds whose licenses allow shipping are chosen. - An offline renderer, used for video captures, tests and auditioning a score without the game.
Checked against real Strudel¶
A parity test compares 39 expressions (438 note onsets over four cycles) against output produced by real Strudel. All match. One deliberate difference: random operators are deterministic in Fboard but don't reproduce Strudel's particular random sequence.
The score and the conductor¶
The score is a data file compiled into the game. It has five sections: menu, cruise, combo, final (the last 15 seconds of a career run) and results. Each section is a stack of layers, and each layer has an intensity range in which it plays.
Every frame, a conductor reads a small set of gameplay inputs: the scene, speed, whether the rider is in the air or grinding, the combo multiplier, and time left. From these it:
- picks the section, switching only on two-bar boundaries so changes land musically;
- sets intensity, which fades layers in and out;
- lifts the tempo by up to 5% at full intensity.
Stingers (short musical cues) fire on a bail, a completed goal, a banked combo and a gap. The numbers that map gameplay to music are marked in the code as first guesses, to be retuned by ear once a direction exists.
Playing it on time¶
In the game, sound plays through the Kira audio library rather than Bevy's built-in audio. Music voices are scheduled about 120 ms ahead on a Kira clock, so they land on the beat regardless of frame rate. Kira's internal buffer is set to 64 frames, about 1.5 ms of timing resolution. Each layer has its own sub-track so intensity changes are smooth fades. More on the engine side: Bevy: audio with Kira.
A bug fixed along the way: master volume had been applied twice to music and loops. It is now applied once.
The demo score¶
To demonstrate the tooling, the project includes "Fare Meter", an original fast skate-punk instrumental at 196 bpm on the built-in guitar instruments. It is not the game's score. It was written as an original piece after a request to use a well-known song was declined on copyright grounds. Its mix was balanced by measurement only; nobody has listened to it yet.
The music tour TAS run is a run built to move through the music's sections and intensities so the adaptive behaviour can be heard in one capture.
Open items¶
- Choose a musical direction, then rewrite the score and retune the gameplay-to-music mapping by ear.
- Curate shippable sounds into the sound folder.
- The live in-game audio path (clock scheduling, layer fades, a low-pass filter on pause) runs without warnings but was only exercised muted; only its timing arithmetic is unit-tested. The offline capture mix applies layer volume per note, so its fades are coarser than the live game's.
See also¶
- A pattern engine in Rust: the engine's internals in more depth.