跳到正文
DEV Community· Bharat Ankh·· 4 小時前AI 評分51

Bharat Ankh 推出 Seedsong 節奏遊戲,歌曲在遊玩時即時生成

I made a rhythm game where the song doesn't exist until you play it (160 lines of procedural WebAudio)

AI 導讀

Bharat Ankh 開發並公開 Seedsong 節奏遊戲,歌曲會隨玩家命中的音符即時生成,而不是使用預製音軌。文字種子會決定調式、速度、根音及和絃進程,同一文字會生成相同歌曲與譜面;音樂由約 160 行的 songgen.js 和 WebAudio 振盪器生成,並非使用 AI 音樂模型或音訊檔案。

正文

Play it here (free, in the browser): https://playgama.ai/play/h2lla7p4eujkc6

Most rhythm games start with a finished track and build a chart on top of it. Seedsong goes the other way. Each note you hit is the melody. If you miss one, that note just never plays. The garden around the ring blooms as you play, and every stage adds a new layer to the arrangement:

roots (bass) → canopy (pads) → rustle (drums) → fireflies (arpeggio) → aurora (bells)

If you miss, flowers wilt and the layers drop out again. The song you hear is a record of how well you played.

There are no audio files in the game. Everything comes from one ~160-line composer (songgen.js) and WebAudio oscillators.

1. A seed in, a whole song out

Everything is deterministic from a string. A tiny FNV-1a hash turns the string into a 32-bit number, and a mulberry32 PRNG grows from that number:

function hash(str) {
  let h = 2166136261 >>> 0;
  for (let i = 0; i < str.length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 16777619); }
  return h >>> 0;
}

From that RNG the game picks:

  • a mode (ionian, dorian, aeolian, mixolydian, lydian)
  • a tempo (84-124 BPM in steps of 4)
  • a root note
  • three chord progressions (A, B, C) from a small hand-picked list, e.g. [0, 5, 2, 6] = I-vi-iii-vii in scale degrees

Then it arranges them as intro (2 bars) → A → B → A → C → outro (2 bars). The energy rises from 0 to 2 across the song.

This makes seed mode possible. You type any word ("pancakes", your cat's name, whatever) and a new song grows from it. The same word always gives the same song, so you can send a word to a friend and you'll both play the same chart.

2. The melody walks between chord tones

A melody made of random notes sounds random. So the melody walks:

  • On strong beats (every 4th sixteenth), the melody snaps to the nearest chord tone of the current chord, in any octave. Half the time it skips a plain repeat, so the line keeps moving.
  • On weak beats, it steps by a small interval picked from [-2, -1, -1, 1, 1, 2, 0]. Small steps are more likely than leaps.
  • It stays inside a range of scale degrees 3-13, so it never wanders off the keyboard.

Rhythm comes from short 16-step patterns grouped into 3 difficulty tiers. Each 2-bar motif is re-rolled every 4 bars, so phrases repeat enough to feel like a song but not enough to get boring.

3. The chart follows the melody's shape

I like this part the most. The chart isn't placed separately from the music. The melody's direction decides which of the 4 lanes each seed comes from:

// melody up = clockwise, down = counter-clockwise, repeat = jump across
const mv = deg - prevDeg;
const lane = (lastLane + (mv > 0 ? 1 : mv < 0 ? 3 : 2)) % 4;

When the tune climbs, your hands move clockwise around the ring. When it falls, they move back. A repeated note sends you to the opposite side. After a minute you start to feel the melody through your fingers, even on a song generated a second ago.

On hard difficulty, high-energy bars add a harmony note a third below on the opposite lane. That gives you chords to hit.

4. Testing a game that's random

Procedural charts can produce unplayable patterns, so node test.js checks every built-in song and difficulty:

  • no same-lane "jacks" faster than 120 ms
  • lanes stay balanced
  • duration is sane
  • determinism: the same seed gives the same chart, every time

The composer runs in both Node and the browser (window.SG / module.exports), so the music logic can be unit-tested without a browser.

5. A new song every day

The newest update (rolling out on Playgama now) adds a "Today's song ✦" button next to Plant. It seeds the composer with the local date, so everyone gets the same new song each day, and a streak counts how many days in a row you've played. Under the hood it's just songFromText('today ' + date), and the deterministic seed makes it work for free.

Try it

I'd love to hear which words give the best songs.


AI disclosure: the game's code was written with an AI coding assistant (Claude). This post was also written by an AI agent working on my behalf (the facts and code snippets are from the game's source). The music is not from an AI music model. It is generated at runtime by the game's own procedural composer described above. No samples, no downloaded assets.

來源:DEV Community · dev.to