Switch Lab – a 3D keyboard toy in the browser with 100 switches you can swap and type on (three.js, mobile)

Hi everyone! I made a little web app where you can try 100 mechanical keyboard switches on one 3D keyboard and hear how each one sounds, before buying any of them.

:play_button: (free, desktop & mobile): Switch Lab · 스위치 랩

Pick a switch and type on the 3D board with your real keyboard (the keys press along), click with a mouse, or tap on your phone. Switch to another one and the whole board gets rebuilt: keycaps lift off, the old switches slide out, new ones slide in, and the caps rain back down. Open the inside view to see the stem and spring move, practice typing with the switch you picked (a cat sometimes walks across your keyboard), or play a typing marathon against other people’s past runs.

Some technical notes

Key travel: every one of the 87 keys runs its own damped spring sim, substepped at 1 ms inside useFrame. Tactile switches get a 0.5 mm zone where acceleration drops to 18%, so the bump shows up in the motion. Clicky switches fire the click sound when the stem crosses that point, and bottom-out / release sounds fire when a key hits either end above a speed threshold. Sound timing comes from the motion, not from the keydown event.

Swap animation: a 3.7 s timeline: caps lift (0.25 s), old switches slide out column by column (0.75 s), new switches slide in (1.4 s), then the caps drop in a diagonal wave (delay = (x + y × 1.4) × 32 ms, 0.46 s fall with a small bounce). Each cap plays the new switch’s sound as it lands, plus a synthesized whoosh.

Switch model: housing, stem, slider and spring are all built in code (the spring is a TubeGeometry along a helix). Geometry is built once and shared by all 87 keys and the standalone switch view. Clear and milky housings come from per-switch opacity, so you can see the spring through translucent tops.

Performance: re-rendering a still scene 60 times a second was eating 87–100% of the main thread on the typing pes. The Canvas now uses frameloop=“demand”, and a small component
wakes it forit awake while something animates by itself (springs, the swap).
It also stophe cat) whenthe canvas is scrolled off screen.

First frame: the first render used to freeze for
about 0.3 s w theframeloop is held at “never”,
renderer.comuns, then itswitches to “demand” (with a 1.5 s fallback).

Look: PMREM environment from RoomEnvironment,
one shadow-c2048 shadowmap) plus a hemisphere light.

No 3D model files. Everything 3D is built in
code. Key soound-testrecordings (one sprite file per switch, AAC with a
WAV fallbackr with ±2%random playback rate so repeated keys don’t sound
copy-pasted. adding0.1–0.3 s of lag because they sleep between sounds,
so a constanutput awake.

Stack: t/fiber, drei,React 19, Vite, Web Audio.

I’d really love feedback, especially on how it runs on your phons motion feels right!