All work

Interactive web application · 2026

PokéSynth

A synthesizer where every Pokémon is a unique musical instrument, driven by real game data.

PokéSynth

PokéSynth — Case Study

Project Overview

PokéSynth is a browser-based synthesizer where every Pokémon becomes a unique musical instrument. Each Pokémon’s base stats and typing shape the sound it produces — from the warm sine waves of a Water-type to the harsh FM distortion of a Dragon-type. With 898 Pokémon available, the app generates 898 distinct instruments from real game data, with zero backend infrastructure.

Live: pokesynth.com


Problem & Motivation

Pokémon and music are two domains with massive, overlapping fan bases — yet few projects combine them in a meaningful, interactive way. The goal was to build a web toy where every Pokémon is playable: not just viewable, but sonically distinct and fun to experiment with.

The core design question: can six base stats and a type category produce enough timbral variety to make each Pokémon sound recognizably different?


Technical Approach

Synth Engine (synth-engine.ts)

The audio engine is built on Tone.js using a PolySynth wrapper. The Pokémon’s primary type selects 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 effects chain runs: Synth → Filter → Distortion → Chorus → EQ3 → Compressor → Reverb → Limiter → Destination. Per-category EQ presets shape the final tone (e.g., boosted lows for Rock/Ground, scooped mids for Ghost/Dark).

PokéAPI Integration

All Pokémon data is fetched client-side from PokéAPI using TanStack Query with staleTime: Infinity — once fetched, data is cached for the session. The app provides three selection methods:

  • Autocomplete search — fuzzy-matched against all 898 names, pre-fetched as a single lightweight list
  • Paginated grid browser — browse all Pokémon with sprite thumbnails, using keepPreviousData for seamless pagination
  • Random selection — pick a random ID from 1–898

Animated sprites are sourced from Generation V Black/White data when available, falling back to static front sprites.

Piano Keyboard

A 15-key polyphonic keyboard spanning just over one octave, with:

  • Pointer events for unified mouse and touch input
  • Keyboard mapping — keys A through L for white notes, W/E/T/Y/U for sharps
  • Octave shifting — Z and X keys shift the playable range up and down
  • Touch optimization: contextmenu suppression and touch-action: manipulation prevent unwanted browser behaviors on mobile

Dynamic Theming

When a Pokémon is selected, its primary type drives a real-time theme update via 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 UI element — borders, backgrounds, text highlights, indicator LEDs — recolors instantly. The type color map covers all 18 Pokémon types with hand-tuned hue/saturation pairs.

Stat Visualizer

An animated bar chart displays all six stats with:

  • Stat name and numeric value
  • The mapped audio parameter label (e.g., “ATK → distortion”)
  • A pulse animation triggered when notes are actively playing, providing visual feedback that connects the stats to the sound

UX Considerations

  • CLS prevention — A fixed-height placeholder (min-h-[280px]) reserves space for the Pokémon card and stat panel before any selection, eliminating layout shift
  • Mobile touch optimization — Context menu suppression, touch-action: manipulation, and pointer events ensure smooth play on touchscreens
  • Responsive keyboard hints — Key labels shown on desktop, hidden on mobile where they’d be meaningless
  • Retro aesthetic — Game Boy-inspired pixel art styling with a CRT scanline overlay, pixelated sprite rendering (image-rendering: pixelated), and a monospace-adjacent 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 demonstrates that real game data can drive meaningful creative output. The six base stats provide enough dimensionality to make Charizard sound unmistakably different from Blastoise — not through arbitrary mapping, but because the stat distributions genuinely reflect each Pokémon’s character. A fast, frail Pokémon sounds fast and frail. A tanky defender sounds muffled and sustained.

The project runs entirely client-side with zero backend — all data comes from PokéAPI, all synthesis happens in the browser via Web Audio. This makes it instantly shareable, trivially deployable, and endlessly explorable across 898 unique instruments.