All work

Pokémon Synthesizer · 2026

PokéSynth

A synthesizer where every Pokémon plays as its own instrument, tuned to its real stats.

PokéSynth

PokéSynth

Project Overview

PokéSynth is a synthesizer where every Pokémon is its own instrument. A Pokémon’s base stats and typing shape the sound it makes, from the warm sine tones of a Water-type to the harsh FM bite of a Dragon-type. There are 898 Pokémon in play, which means 898 distinct instruments, all generated from real game data with nothing running on a server.

Live: pokesynth.com


Problem & Motivation

Pokémon and music both have huge, overlapping fan bases, and almost nobody had put them together in a way you can actually play with. I wanted a web toy where every Pokémon is playable: not just something you look at, but something that sounds distinct and is fun to mess around with.

The question underneath it: can six base stats and a type produce enough variety in tone to make each Pokémon sound recognisably different?


Technical Approach

Synth Engine (synth-engine.ts)

The audio engine runs on Tone.js wrapped in a PolySynth. A Pokémon’s primary type picks one of 6 synthesis architectures:

Category Types Inner Synth Character
fm Fire, Fighting, Dragon FMSynth (sawtooth carrier) Aggressive, bright
fm-eerie Ghost, Dark, Poison FMSynth (high mod index, square mod) Haunting, unstable
fm-heavy Rock, Ground FMSynth (square carrier) Thick, percussive
am Electric, Steel, Psychic AMSynth Shimmering, metallic
basic-sine Water, Ice, Flying Synth (sine) Smooth, pure
basic-tri Grass, Bug, Fairy, Normal Synth (triangle) Warm, soft

Each of the 6 base stats maps to a distinct audio parameter:

Stat Audio Parameter Effect
HP Envelope sustain & release Higher HP → longer, more sustained tones
Attack Distortion amount (+ FM modulation index) Higher Attack → grittier, more aggressive timbre
Defense Low-pass filter cutoff Higher Defense → darker, more muffled sound
Sp. Atk Reverb decay & wet mix Higher Sp. Atk → more spacious, atmospheric
Sp. Def Chorus depth & detune Higher Sp. Def → wider, more shimmering
Speed Envelope attack & decay speed Higher Speed → snappier, more percussive onset

The full signal path runs Synth → Filter → Distortion → Chorus → EQ3 → Compressor → Reverb → Limiter → Destination. Per-category EQ presets shape the final tone: boosted lows for Rock and Ground, scooped mids for Ghost and Dark.

PokéAPI Integration

All Pokémon data is fetched in the browser from PokéAPI using TanStack Query with staleTime: Infinity, so once something is fetched it stays cached for the session. There are three ways to pick a Pokémon:

  • Autocomplete search, fuzzy-matched against all 898 names, pre-fetched as one lightweight list
  • A paginated grid you can browse with sprite thumbnails, using keepPreviousData so pagination doesn’t flicker
  • Random selection, which just grabs an ID between 1 and 898

Animated sprites come from Generation V Black/White data where it exists, falling back to the static front sprite otherwise.

Piano Keyboard

A 15-key polyphonic keyboard covering just over an octave:

  • Pointer events so mouse and touch are handled the same way
  • Keyboard mapping: A through L for the white notes, W/E/T/Y/U for the sharps
  • Octave shifting on Z and X to move the playable range up and down
  • Touch handling that suppresses the context menu and sets touch-action: manipulation so mobile doesn’t fire off unwanted browser gestures mid-play

Dynamic Theming

Pick a Pokémon and its primary type retints the whole interface in real time through CSS custom properties:

--type-hue    → base hue from type color map
--type-sat    → saturation percentage
--primary     → HSL value for primary UI color
--accent      → hue-rotated (+40°) accent color

Every element recolours at once: borders, backgrounds, text highlights, even the indicator LEDs. The type colour map covers all 18 types with hand-tuned hue and saturation pairs.

Stat Visualiser

An animated bar chart shows all six stats, each with:

  • The stat name and its numeric value
  • The audio parameter it maps to (for example “ATK → distortion”)
  • A pulse animation that fires while notes are playing, so you can see the stats driving the sound

UX Considerations

  • No layout shift: a fixed-height placeholder (min-h-[280px]) holds space for the Pokémon card and stat panel before you’ve selected anything, so nothing jumps around
  • Mobile touch: context menu suppression, touch-action: manipulation, and pointer events keep play smooth on a touchscreen
  • Responsive hints: key labels show on desktop and hide on mobile, where they’d mean nothing
  • Retro look: Game Boy pixel-art styling with a CRT scanline overlay, pixelated sprite rendering (image-rendering: pixelated), and a near-monospace type scale

Stack

Layer Technology
Framework React 18 + TypeScript
Build Vite
Styling Tailwind CSS + CSS custom properties
Audio Tone.js (Web Audio API)
Data fetching TanStack Query v5
API PokéAPI (REST, no auth)
Routing React Router v6

Outcome & Reflection

PokéSynth is proof that real game data can drive something genuinely creative. Six base stats give you enough to work with that Charizard sounds unmistakably different from Blastoise, and not because I arbitrarily made it so. The stat spreads genuinely reflect each Pokémon’s character, so a fast, frail one sounds fast and frail, and a tanky defender sounds muffled and sustained.

The whole thing runs client-side with no backend at all: the data comes from PokéAPI, the synthesis happens in the browser through Web Audio. That makes it instantly shareable, trivial to deploy, and endlessly explorable across all 898 instruments.