My game writes a new song every day and ships zero audio files
GRAZE has a soundtrack now. It is a different song every day, nobody recorded any of it, and the app did not get any bigger.
Here is how it works and why I built it this way.
THE CONSTRAINT
GRAZE has never shipped a single asset. No image files, no audio files. Every obstacle, particle and glow is drawn with canvas primitives at runtime, and every sound is a Web Audio oscillator. That started as a practical decision, since I was building this in twenty minute windows at 3am after my son was born and could not afford a toolchain, but it turned into the thing that made the soundtrack possible.
Adding music the normal way would have meant bundling megabytes of audio and picking one track everyone hears forever. Generating it meant I could do something a file cannot.
THE IDEA
The daily course in GRAZE is generated from the date. Seed a small PRNG with today's UTC date string, and every phone on earth produces an identical course, with no server and nothing downloaded. The date is the level file.
So: do the same thing to the music.
Seed a second PRNG with the date and let it choose key, tempo, chord progression, bass figure, hi-hat pattern, arp figure and rate, waveform, filter resonance, and how long each chord lasts. Every player hears the same song on the same day. Tomorrow is a different one. Nothing is stored, nothing is streamed, and yesterday's song is reproducible forever because the date has not changed.
WHAT MAKES TWO TRACKS SOUND DIFFERENT
My first version varied key, tempo and chord progression. It sounded identical every day.
That was the lesson. Key is almost inaudible without an A/B reference, eight BPM is nothing, and six progressions that are all cousins of each other read as one progression. What actually separates two house records is rhythm and timbre.
So the seed now picks a bass figure from five patterns over sixteen steps, a hat figure from four, sixteenth or eighth note arps, saw or square oscillators, filter resonance, and one or two bars per chord. It also picks from eight progressions chosen for contrast rather than similarity: a Phrygian flat-II for a dark day, a Dorian major IV for a bright one, a harmonic minor major V when it should feel tense.
Now the days sound like different tracks instead of transpositions.
THE PART I LIKE MOST
The arrangement is gated on your score, not on time.
Under 150 points you get a pad. At 150 the kick arrives, 250 brings the bass, 600 the arp, and it keeps filling in until the whole thing is playing at 10,000. Score only ever rises, so a part can never drop back out mid-run.
The effect is that you can hear how a run is going before you look at the number. A great run sounds like a great run. And because most players never break 10,000, completing the arrangement is a real thing to chase.
Heat, the risk multiplier, does not add parts. It rides the filter, so grazing an edge audibly opens the track up and playing safe closes it down. Layers gated on Heat lurched in and out, because Heat can go from nothing to sixteen times in a few seconds and it decays when you play safe. That was version two of three.
TWO THINGS THAT BIT ME
The arp was playing a minor third over every chord. I had written the arp figure as fixed semitones, which meant it sounded a minor triad against the major chords in the progression. Indexing the chord itself instead of hardcoding intervals fixed it, and it is a mistake that is completely invisible until you look at the numbers.
And audio must never be scheduled from the animation frame. Notes are scheduled ahead on a timer, roughly 100ms of lookahead, because frame-driven audio jitters the moment the game gets busy, which is exactly when the music matters most.
GRAZE: Edge Rush is free on iOS. Score by almost dying: the closer you graze the edge that kills you, the higher your multiplier climbs, and playing it safe scores nothing. Same course for everyone, every day.
Today's board resets at midnight UTC and it is still open.


Discussion