You are flying through space in your spaceship. Or are you actually late for that one meeting? The limbo between reality and the world of dreams can be tricky. Snooze your alarm and use your BeatCannon™ to fight against enemies and obstacles. All to the soothing sound of your looping alarm clock.
This is a rhythm game (sort of). We tried our best to make it workable in web, however, audio latency might be better on native versions. They can be downloaded on the game’s itch.io page.
This game was a submission to GMTK Jam 2025. The topic was loop. It was a four day Gamejam, and we build it with four people.
Credits #
The team: Elaneus, JonWon, seba & midgecraft
All music, graphics and SFX created by our team during GameJam. Exceptions listed here:
- Explosion animation by Kenney (https://www.kenney.nl/assets/smoke-particles)
- Font: Neo Navy (https://www.dafont.com/de/absolute-neon-script.font)
To learn more about the music creation process, check out seba’s blog post.
Making of #
We were the same crew as last year during creation of TowerUp for GMTK 2024. This time around we decided to go for a rhythm game. The theme “loop” just called for some music looping. Maybe not the wisest choice, given that none of us had ever build a rhythm game before. But we skimmed some youtube tutorials, and it seemed easy enough! Little did we know.
Syncing gameplay to music #
The main problem with rhythm games is that the audio and the input & visualization all have to match. However, the time when you say “play” in Godot and the time the sound comes actually out of the speakers can be significantly later.
If you play directly from Godot editor or with a local build, it’s not that bad. But if you have a web export it becomes noticeable. And e.g. bluetooth headphones can add a lot of latency.
A good introduction to the topic can be found in the Godot docs and there is an example on godotengine’s github page.
We experimented with both System clock and sound clock approach, but found the system clock to work better on Web.
We ended up using signals that emitted on 4th and 8th, so that various things in the game could react to it. For instance, the levels are created by describing what events should happen after how many beats.
For recognizing whether the player hit a beat in time we are using collision detection of the marker going over the visualization. There is a large box for showing the “miss” and a small box for the “hit” around each of the beats.

The marker is moved based on the progress within the measure, calculated using the system clock:
const BPM = 120
const BARS = 4
var beat_delay = 0.02 # magic gamejam value - it made things better IMO
func _ready() -> void:
time_begin = Time.get_ticks_usec()
time_delay = AudioServer.get_time_to_next_mix() + AudioServer.get_output_latency()
func _process(_delta):
# Obtain from ticks.
time = (Time.get_ticks_usec() - time_begin) / 1000000.0
# Compensate.
time -= time_delay
time -= beat_delay
var beat: float = time * BPM / 60.0
var measures_passed = beat / BARS +1
var measures_passed_int = int(beat) / BARS +1
measure_progress_percentage = measures_passed - measures_passed_int
%AudioVisualization.update_marker(measure_progress_percentage)
Web exports #
After last year our game was barely playable on Web briefly before the deadline (which was luckily extended), we did more web testing this time. This button became our new favorite:
We still had fun with a known Godot 4.4 bug where web export crashes if a AudioStreamPlayer
has autoplay set to true
.
Luckily the ticket contained a workaround.
And this year we went with Compatibility
mode instead of Forward+
.
If you are planning to release to web, I recommend reading
this documentation page.
The web build feature is really cool for an itch.io Gamejam since it allows everyone to test the game quickly without downloads. However, specifically for the rhythm game the local builds worked a lot better.