PixiJSTypeScriptGSAPWeb Audio
Controls
- Swipe or drag a gem onto a neighbour to swap them, or tap one gem and then a neighbour
- Keyboard: arrow keys move the cursor, Enter or Space picks a gem, then an arrow swaps it; Escape cancels; H shows a hint
- Tap, click or press Enter during a cascade to speed it up
- A hint pulses after a few seconds without a move
- Add ?level=3 or ?zen to the address to open a level or zen mode directly
Needs WebGL. Without it the poster is shown. Respects the reduced-motion setting: no particles or shaking, short fades instead of falls. Sound is off until you turn it on. Progress is saved in this browser.
How it's built
A match-3 puzzle game: swap neighbouring gems to make lines, chain cascades, forge special gems and reach each level's goal within its moves. Eight levels with stars, plus an endless zen mode.
How it's built
- Rules and drawing are separate. The game rules (
core/) are plain TypeScript with no PixiJS imports: the board, finding matches, special gems, gravity and refill, scoring, finding possible moves and reshuffling. A move returns a list of steps (swap, cascade, reshuffle), and the renderer only plays those steps back. The rules can be tested without a browser, and the same steps always look the same. - Seeded randomness. Each level starts from its own seed, so a level is the same board every time, and tests can replay whole games. Refills are random but come from the same seeded generator.
- An explicit state machine. The game flows menu → idle ⇄ busy → won or lost → menu. Bad transitions throw, so a second swap during a cascade can't slip through.
- Special gems. Four in a line makes a striped gem that clears its column or row, an L or T shape makes a bomb (3×3), and five in a line makes a colour gem that removes every gem of the colour it is swapped with. Specials hit by other specials go off in a chain.
- Never stuck. After every move the rules check that a move still exists, and shuffle the board if not. A hint pulses after six seconds without a move; it is the move that does most for the current goal.
- Tuned by simulation. Level targets were set by letting a simple bot that follows the hints play each level on 20–30 random boards. The unit tests check that every level can be won this way.
- Drawing. PixiJS 8 (WebGL). Each gem shape is drawn once with Pixi Graphics and baked into a texture, so the board is plain sprites and there are no image files. GSAP runs the swaps, pops and bouncy falls. Particles come from a small pool of reused sprites. New gems wait above the board behind a mask. Effects: faceted gems, gems raining in at level start, a lift on swap and a head shake on a wrong swap, stretch-and-squash falls, shockwave rings, glows and shards on every clear, opening beams for striped gems, lightning for the colour gem, a board shake and warm aura that grow with the combo, floating score popups, idle twinkles and pulsing specials, and fireworks with a gem wave on a win. The HUD has combo words, a shining goal bar, a moves counter that ticks and warns at five, a popping results panel and drifting embers (CSS only).
- Input. Swipe or drag, tap a gem and then a neighbour, or use the keyboard (arrows, Enter, H for a hint). A tap during a cascade speeds it up six times.
- Everything readable is HTML. The goal, score, moves, menus and results are HTML; a polite live region announces each move's result. The canvas is hidden from screen readers.
- Reduced motion. No particles or shaking, no hint pulse (an outline instead), short fades instead of falls. The game stays fully playable.
- Performance. The pixel ratio is capped at 2. The Pixi ticker stops while the board is off screen or the tab is hidden. If the graphics context is lost, the poster covers the board until it comes back.
- Sound and music are generated with Web Audio (no files) and are off until turned on. The music is an endless A-minor loop (pad, bass, a random pentatonic arpeggio with echo, soft hats) booked ahead on the audio clock; combos open its filter and make the arpeggio busier. Effects go through a shared compressor. Audio pauses while the tab is hidden. Progress, best scores and both sound settings are saved in this browser (
localStorage, versioned key; nothing breaks if storage is blocked). - Slow devices. Devices with 4 or fewer cores or 4 GB or less memory start on a light tier (pixel ratio 1, no antialiasing, a third of the particles, no glows, popups, twinkles or embers). Any device whose frames stay slower than about 45 fps drops to the same tier while playing.