Beginner-Friendly Tutorials Jul 23, 2026

How to Make a Rhythm Game in GameMaker - First Music Sync Evening 2026

How to make a GameMaker rhythm game in one evening—music sync, BPM math, audio_sound_get_track_position, hit windows, latency budget, and a playable one-lane prototype.

By GamineAI Team

How to Make a Rhythm Game in GameMaker - First Music Sync Evening 2026

Chickens pixel art thumbnail

If you are searching gamemaker rhythm game, you do not need another Necrodancer essay. You need a Monday path: pick one song, lock BPM, drive a metronome from audio track position, spawn one lane of notes, grade hits with honest windows, and decide keep or hold before you invent a twelve-lane chart editor.

On July 22, 2026, GameMaker published Making A Rhythm Game In GameMaker—a practical walkthrough aimed at music synchronization and a basic playable loop.GameDev.net syndication That matters because rhythm games die on drift: if notes follow frame counters while music follows the sound card, hit windows feel unfair even when your art is perfect.

Who this is for: beginners on GameMaker LTS / monthly, creators prototyping a jam rhythm toy, and working GML programmers who want a receipt-backed sync core.
Time: 2–4 hours for a one-lane prototype that proves sync.
Honest limit: this is not a full charting suite, FMOD/Wwise deep dive, or multiplayer battle-rhythm netcode. Marketplace BPM helpers exist (BPM sync asset, GMSync); tonight you learn the why so you can evaluate those tools instead of cargo-culting them.

Non-repetition: This is not GameMaker Steam demo export sanity or setlive branch dry run. Those own shipping folders. This URL owns timing feel.

Why this matters now

  1. Official teaching moment. The Jul 22 GameMaker post puts rhythm fundamentals in the engine’s own blog—search and Discord will spike “how do I sync?” for a week.Official post
  2. LTS 2026 is the primary line. Teams pinning LTS need timing patterns that survive export, not IDE-only Run window magic.LTS 2026.0
  3. SERP is thin on keep/hold. Official + old sync blogs explain pieces; GamineAI can win with a first-evening gate table, latency budget, chart receipt, and clear handoff to Steam export when the prototype graduates.

What “synced” actually means

Approach Source of truth Risk
Frame counter / alarm Room speed Drift when FPS dips or vsync changes
delta_time metronome alone Accumulated time Still drifts vs audio if music seeks or buffers
Audio track position Playing sound instance Correct for rhythm—notes follow the song

Rhythm rule: the music player writes time; the metronome reads time; gameplay reacts to metronome events. Do not let sprites “decide” the beat.

Prerequisites

  • [ ] GameMaker that can play audio (LTS 2026.0 or current monthly—match your studio pin).
  • [ ] One constant-BPM practice track (no live rubato for night one).
  • [ ] Known BPM (tap-tempo tools are fine; write the number down).
  • [ ] A throwaway project—not your Steam demo main.
  • [ ] Keyboard or one gamepad button for hits.
  • [ ] Named session owner for the receipt at the end.

If your song changes tempo mid-track, hold chart complexity—prototype on a steady section first.

Beginner path - one-lane sync in one evening

Step 1 - Write the evening card

Song: practice_120bpm.ogg
BPM: 120
Beat duration: 60 / 120 = 0.5 seconds per quarter note
Done when: a visual pulse and a note lane stay locked for 60 seconds without “feeling late”

Step 2 - Beat math (keep it on a sticky note)

beat_duration_sec = 60 / bpm
beat_duration_ms  = beat_duration_sec * 1000

At 120 BPM, quarters are 500 ms. Eighths are 250 ms. Your hit window might be ±80 ms around each beat—tune later, do not invent ±400 ms “casual mode” before sync is proven.

Step 3 - Play music and store the instance handle

In GML, audio_play_sound returns a handle for that playing instance. Track-position APIs need that handle—not only the sound asset index. Pattern used across GameMaker sync tutorials: store bgm = audio_play_sound(...), then read position from bgm.csanyk sync notes

Pseudo-structure:

// Create
bpm = 120;
beat_dur = 60 / bpm;
bgm = audio_play_sound(snd_practice, 10, true);
next_beat_t = beat_dur;
beat_index = 0;

Step 4 - Metronome Step - audio is boss

Every Step (or a fixed timer object):

  1. Read t = audio_sound_get_track_position(bgm) (seconds).
  2. While t >= next_beat_t: emit beat event, beat_index++, next_beat_t += beat_dur.
  3. Never “catch up” by skipping visual feedback without logging—it hides desync.

If the window loses focus and audio pauses, decide explicitly: pause chart time with music, or freeze input. Silent policy fights feel unfair.

Step 5 - One visual proof before notes

Flash a sprite or change image_blend on each beat for 60 seconds. If the flash drifts from what you hear, stop—do not spawn notes yet. Your ears are the QA tool.

Step 6 - Spawn a single lane

On each beat (or every other beat), create a note object with:

  • target_t = the beat time it should be hit
  • travel time from spawn Y to hit line (seconds)

In Step, position notes by time remaining, not by vspeed alone:

seconds_to_hit = target_t - audio_sound_get_track_position(bgm)
y = hit_line_y - seconds_to_hit * pixels_per_second

Frame-based vspeed without time correction is how “it worked at 60 FPS in the IDE” becomes “Steam Deck feels early.”

Step 7 - Hit windows and grades

On key press:

error_ms = abs(audio_time - target_t) * 1000

Example windows (tune after sync is solid):

Grade error
Perfect ≤ 40 ms
Great ≤ 80 ms
OK ≤ 120 ms
Miss else / timeout

Play a short SFX on grade—audio feedback teaches windows faster than score numbers.

Step 8 - Record a 30-second proof clip

Before you celebrate, record (phone webcam is fine) 30 seconds of: metronome flash + note hits. Watch muted once—if flashes do not match the waveform kicks you still feel in your bones, re-tap BPM. Then watch with sound. File the clip path in the receipt notes. This is the artifact a producer can review without installing GameMaker.

Beginner checklist card (print this)

  • [ ] BPM written and verified by ear for 16 bars
  • [ ] audio_play_sound handle stored in a variable
  • [ ] Pulse locked 60 seconds
  • [ ] Notes use seconds_to_hit math
  • [ ] 20 graded hits logged (count Perfect/Great/OK/Miss)
  • [ ] Restart tested twice
  • [ ] Receipt JSON filled (even if export_tested: false)

Developer path - latency, charts, export honesty

Input and audio latency budget

Layer What to measure Night-one action
Display vsync / fullscreen vs window Test both; pick one for tuning
Audio buffer driver latency Keep same device while tuning
Input keyboard vs pad Separate calibration offsets later
Export IDE Run vs YYC/VM exe Re-tune after export sanity

Add a global offset_ms (can be negative) applied to hit tests—not to the metronome itself—so calibration does not rewrite chart times.

Chart data - start boring

JSON or CSV for night one:

{
  "bpm": 120,
  "offset_ms": 0,
  "notes": [
    { "t": 2.0, "lane": 0 },
    { "t": 2.5, "lane": 0 },
    { "t": 3.0, "lane": 0 }
  ]
}

t is seconds from song start. Do not encode notes as “frame 183” unless you enjoy rewriting charts when room speed changes.

Seeking and restarts

When the player restarts:

  1. Stop and replay audio from 0 (or seek both audio + chart).
  2. Reset next_beat_t and note spawns from the same origin.
  3. Clear in-flight note instances.

Partial seeks without chart reset create ghost notes—classic jam bug.

Marketplace assets - keep / hold

Option Keep when… Hold when…
Roll your own metronome Learning / jam / unique rules You need weeks of chart tools tomorrow
BPM itch asset You verified events vs track position You cannot read/modify the GML
GMSync Note-length API matches your design License or GMS version mismatch

Rule: buy helpers after your one-lane proof works. Otherwise you debug the asset and the song at once.

Variable BPM and stems

Hold for week two. Official and community guidance stresses early prototypes to expose sync problems before content scales.GameDev.net Multi-tempo charts need sections with their own BPM and offsets—do not fake it with stretched beat_dur mid-song on night one.

Minimal metronome object sketch (working-dev)

Create a controller object with roughly this Step logic (names illustrative):

t = audio_sound_get_track_position(bgm);
while (t >= next_beat_t) {
    event_user(0); // flash / spawn hook
    beat_index += 1;
    next_beat_t += beat_dur;
}

In event_user(0), either flash or spawn. Keep spawn density low until R3 is green. If you need eighth notes, emit on beat_dur * 0.5 with a separate counter—or store note times only in the chart and let the chart drive spawns while the metronome only drives UI pulse. Splitting pulse bus vs chart bus prevents double responsibility bugs when you later add sliders or holds.

Chart authoring workflow that scales past tonight

  1. Tap BPM once; freeze it in project macros.
  2. Build a 8–16 note JSON for the chorus only.
  3. Playtest with grade histogram (how many Perfect vs Miss).
  4. Adjust offset_ms before you redraw notes.
  5. Only then duplicate patterns for verse/bridge.

Teams that redraw charts every time they change offset waste art time. Offset is a player/device calibration; chart times stay song-relative.

Autoplay debug mode

Add a debug flag that auto-presses when abs(error_ms) < 5. If autoplay still misses, your clocks disagree—fix R3/R4 before blaming human skill. Ship builds must compile with autoplay off.

Steam / itch shipping note

When the prototype becomes a demo:

  1. Re-run sync on the exported Windows build (not only IDE).
  2. File export receipt via the GameMaker Steam export pipeline.
  3. If you promote a fest branch, use setlive dry run discipline.

Audio that syncs in IDE and drifts in YYC is a real class of bug—catch it before wishlist week.

Gates R1–R6 (rhythm latch)

Latch gamemaker_rhythm_sync_ok only when all six pass. Receipt: gamemaker_rhythm_sync_receipt_v1.json.

Gate Pass if…
R1 Song Constant-BPM track + written BPM
R2 Audio handle Play instance stored; track position readable
R3 Metronome Visual pulse locked to heard beats ≥ 60 s
R4 Lane Notes positioned by time-to-hit, not raw vspeed only
R5 Windows Grades match intended ms bands on 20+ hits
R6 Restart Restart clears notes and reseeks audio cleanly

Example receipt

{
  "receipt": "gamemaker_rhythm_sync_receipt_v1",
  "bpm": 120,
  "song": "practice_120bpm.ogg",
  "offset_ms": 0,
  "window_perfect_ms": 40,
  "window_great_ms": 80,
  "export_tested": false,
  "gates": { "R1": true, "R2": true, "R3": true, "R4": true, "R5": true, "R6": true },
  "owner": "session-owner-name",
  "notes": "IDE-only; export retest before Steam demo."
}

Practice drills (30 minutes each)

Drill A - Mute test: mute speakers; watch flash regularity. If irregular, your Step loop is hitching—profile before blaming BPM.
Drill B - Offset sweep: nudge offset by ±10 ms steps until Perfect count peaks on 40 hits.
Drill C - FPS torture: enable a CPU burner (particle spam) and confirm notes still track music—proves time-based motion.
Drill D - Device swap: headphones vs laptop speakers; if grades collapse, document a recommended audio path in the README.
Drill E - Export twin: after export sanity, repeat Drill B on the exe and update export_tested.

What not to build tonight

  • Full vertical chart editor with undo stacks
  • Online versus battle-rhythm
  • Stem-reactive lighting for five stems
  • Mod support / workshop charts
  • AI that “listens” and generates charts without human R3 proof

Those are real products. Tonight’s product is a trusted clock.

If you only remember one sentence: music time owns the beat; everything else is presentation. That single rule separates prototypes that feel fair from demos that earn “input lag” reviews they do not deserve. Keep that sentence at the top of your chart README.

Failure modes and quick fixes

Symptom Likely cause Fix
Notes early after 30 s Frame-based motion Drive Y from time-to-hit
Pulse drifts from kick Wrong BPM / offset Retap BPM; add offset_ms
Works in IDE, fails in exe Export / audio path Export sanity + retest R3
Double beats While-loop catching up too aggressively Cap catch-up; log skipped beats
Miss on every pad hit Input latency Separate pad offset; tighten display mode
Ghost notes after restart Instances not destroyed Clear layer + reset next_beat_t

Company / diligence notes

  • Ownership: one person owns BPM/offset truth; chart authors do not invent parallel clocks.
  • Cost/ROI: one evening of sync proof saves weeks of “feel” arguments and refund-looking “input lag” reviews.
  • Accessibility: offer calibrate offset and colorblind-safe grade flashes before you ship difficulty DLC fantasies.
  • Licensing: confirm music rights for Steam; prototype on original or clearly licensed loops.
  • AI policy: if charts are AI-assisted, still human-verify R3–R5—models do not hear your buffer latency.

How this fits a micro-studio week

Monday: R1–R3 pulse proof.
Tuesday: R4–R5 one lane + windows.
Wednesday: Tiny 30-second chart JSON.
Thursday: Export build retest; update receipt export_tested.
Friday: Decide keep custom metronome vs marketplace helper; schedule Steam export pass if demo-bound.

Common mistakes

  1. Charting before a locked pulse — art cannot fix drift.
  2. Using room speed as BPM — it is not.
  3. Ignoring the audio instance handle — position APIs need the playing voice.
  4. Giant hit windows to hide bad sync — players still feel wrong.
  5. Tuning only in IDE Run — export lies differently.
  6. Variable BPM on night one — hold.
  7. Twelve lanes before one lane grades clean — scope kill.
  8. Skipping restart tests — jam runs restart constantly.

Sample evening timeline (strict)

Minute Task Exit criteria
0–15 Project + import OGG + write BPM card Song plays looping
15–35 Metronome + flash R3 pulse locked
35–55 One lane motion Notes reach hit line on time
55–75 Hit windows + SFX Histogram looks sane
75–90 Restart + receipt R6 + JSON filled
90–120 Buffer / optional second song section Only if R1–R6 already green

If you blow the timeline building a ranking screen, you failed the evening. Delete UI chrome; keep the clock.

Key takeaways

  1. gamemaker rhythm game success starts with audio track position, not frame counters.
  2. Official Jul 22 GameMaker teaching makes this a timely skill for LTS teams.Official post
  3. Compute beat_dur = 60 / bpm and emit beats from music time.
  4. Prove a visual metronome for 60 seconds before spawning notes.
  5. Move notes by seconds_to_hit, not hope-based vspeed.
  6. Grade with millisecond windows; add calibration offset later.
  7. Latch gamemaker_rhythm_sync_ok on R1–R6.
  8. Retest after Windows export before Steam demo claims.
  9. Marketplace BPM tools are optional after you understand the clock.
  10. Pair shipping with export sanity and setlive dry run.

FAQ

How do I make a rhythm game in GameMaker?

Start with a constant-BPM track, drive a metronome from audio_sound_get_track_position on the playing instance, spawn notes from chart times, and grade input error in milliseconds. Official GameMaker guidance emphasizes sync and a basic playable loop first.Official post

Why does my GameMaker rhythm game desync?

Usually the chart follows frames while music follows the sound device, or BPM/offset is wrong. Lock visual beats to track position for a full minute before adding lanes.

What BPM formula should I use?

Quarter-note duration in seconds is 60 / bpm. At 140 BPM that is ~0.4286 s per beat.

Should I use a BPM marketplace asset?

After R1–R3 pass. Helpers like BPM sync or GMSync accelerate production; they should not replace understanding the clock.

Does this work for Steam Deck / export builds?

Only if you re-run R3–R5 on the exported binary. Use the Steam export sanity checklist before depot upload.

Can beginners finish a prototype in one evening?

Yes for one lane + pulse + short chart. No for full editor, multi-tempo album, or online versus mode.

How do hit windows relate to accessibility?

Expose calibration offset and consider wider windows as an option—not as a substitute for fixing sync.

What song should I use for the first prototype?

A dry electronic loop with a clear kick on every quarter note. Avoid live drums with swing, songs with tempo maps, or licensed tracks you cannot ship. Length of 60–90 seconds is enough to prove R3–R5 without burning export time.

Is GML Visual enough for a rhythm game?

You can prototype pulse and simple spawns in Visual, but millisecond grading and chart JSON are clearer in GML Code. Many teams sketch feel in Visual, then move the metronome to a code object before Steam export.

How does this relate to Photon or online play?

It does not—yet. Netcode for rhythm needs deterministic song time and lockstep or server authority. Finish local R1–R6 before you open the first-evening Photon path in How to Use Photon Multiplayer in GameMaker - First Realtime Room Evening 2026 (App ID → service loop → two-client room), or the official Photon GameMaker announcement for feature scope.

Related reading

Official and useful sources