Echoborn: nyp för att spela

Ett instrument du spelar med händerna i en webbläsarflik. Handspårning, syntes och grafik, utan konto, utan backend och utan att data lämnar enheten.

Kund
Nuits
År
2026
Status
Live
Roll
Ensam grundare, Interaktionsdesign, Utveckling, Ljudprogrammering
Teknik
TanStack Start, MediaPipe, Tone.js, react-three-fiber, WebGL
Echoborn: nyp för att spela

Bakgrund

Echoborn är ett instrument du spelar med händerna, i en webbläsarflik, med kameran du redan har. Du nyper för att spela. Rör händerna och ljudet rör sig med dem.

Det finns inget konto, ingen registrering och ingen backend av något slag. Sidan laddas, kameran slås på lokalt, och ingenting om dig lämnar maskinen, eftersom det inte finns någonstans för det att ta vägen.

Problemet

Webbläsarinstrument blir nästan alltid ett pianoklaviatur ritat i HTML, spelat med musen, en ton i taget. Det är inget instrument. Det är ett diagram över ett.

Gestyrd musik har det omvända problemet. Demonstrationerna ser makalösa ut i en trettio sekunder lång video och går inte att spela i praktiken, eftersom de är byggda som teknikdemonstrationer i stället för som instrument. Fördröjning behandlas som ett mätvärde att rapportera i stället för som det som avgör om föremålet över huvud taget är musikaliskt. Över ungefär tjugo eller trettio millisekunder mellan en fysisk gest och ljudet den orsakar slutar kroppen tro att de två hänger ihop, och då spelar du ingenting längre. Du manövrerar en kontrollpanel som låter.

Jag ville ta reda på om webbläsaren kunde ta sig under den gränsen ärligt, utan nativ app och utan hårdvara.

Min roll

Ensam, som med resten av Nuits. Interaktionsdesign, utveckling, ljud, grafik.

Det intressanta arbetet låg inte i någon av dem för sig. Det låg i budgeten mellan dem: handspårning, syntes och 3D-rendering vill alla ha huvudtråden, vill alla ha GPU:n, och alla försämrar instrumentet om de svälts. Att avgöra vad som fick vara dyrt var hela jobbet.

Angreppssätt

Nypet blev gesten eftersom det har ett entydigt binärt läge. De flesta handgester ligger på ett kontinuum, vilket betyder ett tröskelvärde, vilket betyder fladder vid tröskeln, vilket betyder att toner hackar av och på medan handen står stilla. Tumspets till pekfingerspets är ett avstånd som stängs beslutsamt och öppnas beslutsamt, och det är en rörelse folk redan förstår utan instruktioner.

Allt annat mappas kontinuerligt. Position, spridning och orientering styr tonhöjd, filter och rum. Den uppdelningen ger dig de två saker ett instrument behöver: ett tydligt anslag du kan placera i tiden, och ett uttrycksfullt reglage du kan forma efter anslaget.

Det finns ingen genomgång. Du håller upp handen och något händer.

Så byggde jag det

TanStack Start levererar den. Det är hela serverberättelsen, eftersom det inte finns någon serverlogik. Alltihop är en statisk sida med mycket som händer inuti.

Handspårningen är MediaPipe, och specifikt MediaPipe med modellfilen hand_landmarker.task hostad på mitt eget ursprung i stället för hämtad från Googles CDN, vilket är vad varje exempel i ekosystemet gör. Tre skäl, i den ordning jag bryr mig om dem. Modellen är flera megabyte och den ligger i den kritiska vägen till att instrumentet över huvud taget existerar, så den borde inte hänga på en tredje parts drifttid eller på deras beslut att flytta en URL. Att hämta den från en extern värd berättar för den värden att någon på min sajt är på väg att slå på en kamera, vilket är en integritetsläcka jag då skulle behöva redovisa. Och att servera den från samma ursprung gör att den cachas under min kontroll och att andra besöket är omedelbart.

Ljudet är Tone.js ovanpå Web Audio API. Web Audio kör sin graf på en dedikerad ljudtråd, vilket är det enda skälet till att det här fungerar: spårningsloopen kan tappa en bildruta utan att ljudet hackar. Regeln jag höll fast vid är att landmärken läses på videobildrutan och skrivs rakt in i ändringar av ljudparametrar, utan mellanliggande React-tillstånd. Att dra en gest genom en komponentomrendering lägger till en bildrutas fördröjning och ger ingenting, eftersom ingenting i DOM behöver veta.

Grafiken är react-three-fiber, och den är medvetet det första som får ge vika. Renderaren körs på GPU:n, spårningen körs på sitt eget inferensschema, och om enheten inte klarar båda förlorar grafiken. En bortfallen partikel är osynlig. En försenad ton är instrumentets slut.

Felmoder, av vilka det finns flera ärliga. Svagt ljus förstör tilliten till landmärkena, och landmärken med låg tillit ger toner du inte spelade, så spårning under ett tillitströskelvärde håller kvar det senaste stabila läget i stället för att gissa. Två händer som korsas orsakar identitetsbyten mellan dem, vilket låter som att din vänsterhand plötsligt spelar högerhandens stämma. Motljus, ett fönster bakom dig, är det enskilt vanligaste skälet till att det känns trasigt, och det är inget jag kan fixa i mjukvara.

Resultat

Den ligger live på echoborn.app och kostar mig ingenting att driva, eftersom en statisk sida utan backend saknar marginalkostnad. Folk spelar på den, stänger fliken, och jag får aldrig veta något om det, vilket är överenskommelsen.

Vad jag skulle göra annorlunda

Jag trimmade nyptröskeln på mina egna händer, i mitt eget kök, i min egen belysning. Det är ett urval på ett, och handstorlekar varierar mer än jag antog. En kort kalibrering vid första laddningen skulle lösa de flesta klagomål jag får.

Jag skulle också spela in och spela upp landmärkessekvenser som testrigg. Jag felsökte ljudtiming genom att vinka åt en laptop i veckor, vilket inte är reproducerbart och ser värre ut än det låter.