Do You Believe in Light?
A ball of light that answers you — just open the page
An ambient lamp that runs in a browser tab. Open it and you get a slowly breathing ball of light — no signup, no install, works on phone and desktop alike.
Built for the Bund Summit Hackathon 2026, AI Coding track.
Five ways to play
- Ambient — needs no permissions at all. Open it and the light is already breathing.
- Breathing — 4-7-8 and 4-4-4-4 patterns; inhale, hold and exhale along with the light.
- Script — one sentence generates a lighting performance with an arc to it. With no LLM key configured it falls back to six built-in scripts, losing nothing.
- Gesture — the camera tracks both hands: open and close them to control spread, raise and lower a palm for brightness and hue.
- Party — three microphone frequency bands plus adaptive beat detection drive the whole field.
The point is that these five are not five separate implementations. Sound, gesture, breathing and scripts all write into the same set of target values; smoothing and rendering happen once, inside the light-field engine. Adding a new mode is usually adding one more source of data, not another render pipeline.
The console
- Presentation (5 modes): particles / blended / veil / pure light / flat colour. Flat colour is a deliberately different visual language — particles off, bloom off, the atmosphere’s base tint and vignette pulled away, leaving crisp solid shapes on true black.
- Form (4 shapes): orb / aurora / flame / ripple. Forms are interpolated, not switched: the shader holds both parameter sets and mixes between them.
- Veils (16 patterns): flow, quadrants, pulse, spectrum bars, chase lights, beams, lasers, spotlight, light river, tunnel, dial, strobe…
- Sleep fade: the last 45% is where dimming starts, drawing inward, warming and desaturating together rather than just lowering brightness.
- Ultra-dark: overall brightness goes down to 8%, and below 30% an overlay takes it darker than the system minimum. Unlocking takes a 1.5-second press, so you can’t fumble it in the dark.
Two things that matter more than features
Privacy. The microphone and camera are requested only when you tap Party or Gesture. Everything is processed on-device; nothing is recorded, nothing is uploaded. Declining doesn’t affect the other three modes. MediaPipe’s wasm and models are vendored locally, so nothing talks to a third party at runtime.
Photosensitivity. The flash criteria follow WCAG 2.3.1 (relative luminance change ≥10% more than three times per second). The two audio paths that change overall brightness are each guarded differently: discrete beat triggers carry an enforced minimum interval, holding flashes below 3 Hz, while the continuous low-frequency brightness push — which has no natural gaps — is amplitude-limited instead. Position, hue, jitter and structure are exempt: they don’t change overall luminance, so they can track fast. The first screen warns users with photosensitive epilepsy explicitly.
How it’s built
A single static page. No backend, no build step. three.js is mapped to a local vendor directory through an importmap, with the MediaPipe models vendored alongside it.
The render chain is particles → veil → trails → bloom → atmosphere. Particles draw in a single call — 5,000 / 10,000 / 18,000 points depending on quality tier, with position, colour and size all computed in the vertex shader. The veil is one full-screen implicit field whose sixteen patterns branch on a uniform, so the whole draw call takes one path and never diverges. Trails ping-pong two half-resolution HalfFloat buffers and composite with max rather than addition, so the feedback loop can’t accumulate and blow out.
On the gesture path MediaPipe infers at 30Hz and the output runs through a 1€ filter. A fixed low-pass is a dead end here: lower it and tracking goes soggy, raise it and you amplify recognition noise along with the signal. The 1€ filter sets its cutoff from the signal’s own speed — filtering hard when slow, barely at all when fast. Machines that can’t keep up drop to 15Hz based on measured inference time.
Deployed on Cloudflare Pages: static files plus one optional Function proxying the script LLM. That host was a hard requirement — pages.dev is reachable from mainland China without a detour.



- Launched
- 2026
- My role
- Solo developer
- Built with
- three.jsWeb Audio APIMediaPipeCloudflare Pages