Shipping a Game Boy “Wario Synth” from real MIDI

Published: (March 14, 2026 at 09:32 AM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Cover image for Shipping a Game Boy “Wario Synth” from real MIDI

Wario Synth Logo

Wario Synthesis Engine 8-Bit Midi

Turn any song into a Game Boy version.

Live Demo

www.wario.style

About

WAH! 🎮

Type in literally any song. We’ll find a MIDI file somewhere on the internet and absolutely demolish it through a janky homebrew Game Boy sound chip running in your browser.

  • Is it accurate? Sometimes.
  • Is it legal? Probably.
  • Does it slap? Absolutely.

Four glorious channels of chiptune chaos:

  • 🟨 Pulse 1 — screamy lead melodies
  • 🟨 Pulse 2 — whatever pulse 1 forgot
  • 🟩 Wave — chunky bass that hits different
  • Noise — percussion (tssss pshhhh)

Zero samples. Zero server audio. Just raw oscillators having the time of their lives.

Wario sprite

Features

  • MIDI search from BitMidi and other sources
  • Browser playback with soundfont piano preview
  • Wario Synthesis Engine: procedural Game Boy‑style synthesis from parsed MIDI structure
  • Share links with dynamic social previews

What we shipped (MVP)

  • MIDI search + ranking across sources (backend fetch/proxy with SSRF protection)
  • Deterministic MIDI parsing + metadata (stable, debuggable)
  • Reliable playback with Web Audio + iOS “tap to enable audio” UX
  • Motif / variation mode (role‑mapping: melody/bass/chords/texture → synth layers)

The feature that derailed us: “Download MP3”

We added an export button that:

  1. Offline‑renders (OfflineAudioContext)
  2. Encodes MP3 in JS (lamejs)
  3. Triggers a blob download

It used to feel great:

  • “Rendering audio…”
  • “Encoding MP3…”
  • “MP3 downloaded!”

Then browsers started blocking it.

The real problem

Modern browsers often silently block downloads that happen after long async work (render/encode), because the “user gesture” is considered gone. No error, no file, just… nothing.

We tried the usual workarounds (and complexity ballooned):

  • Bundle the encoder (avoid CDN globals)
  • Two‑click “prepare then download”
  • Save File Picker (showSaveFilePicker) where supported
  • Pre‑open a tab/window on click, then navigate it to the blob

Eventually the export UX became the least reliable part of the app, so we removed the Download MP3 button instead of shipping something flaky.

What we learned

  • Reliability beats cleverness: a flaky button poisons trust.
  • Browser policies are product constraints: autoplay unlock + download gesture rules define your UX.
  • Determinism makes iteration fun: stable parsing/metadata keeps debugging sane.

How we can level it up next

  • Build our own MIDI library: crawl/cache “known good” MIDIs, normalize metadata, dedupe, rank by “sounds good in our synth”.
  • Better musical intelligence (still lightweight): improved role mapping, basic key/scale heuristics, smarter drum/noise handling.
  • Bring export back properly: either server‑side rendering/export or a deliberate “Save…” flow that’s actually reliable cross‑browser.

Turning random MIDIs into crunchy Game Boy performances is stupidly fun—and it’s a great playground for audio, MIDI weirdness, and shipping fast.

0 views
Back to Blog

Related posts

Read more »

Travigo

Travel as fast as you speak with Gemini! Where live agents meet immersive storytelling & 3D navigation. This project was created for entering the Gemini Live Ag...

Micro games

Hey Gamers! 👾 As part of the Rapid Games Prototyping module, we are tasked with reviewing a peer's game. The challenge is to analyse a prototype built in just...