blurz #
Real-time webcam video effects powered by WebGPU shaders and MediaPipe hand tracking.
Position your hands in front of the camera and watch as GPU-powered effects are applied to the quads between your fingertips. Switch between 16 different effects and toggle between single-quad and five-finger quad mode.
Requirements #
- A browser with WebGPU support (Chrome 113+, Edge 113+, or enable flags in Firefox Nightly)
- Camera permission granted to the page
- Two hands visible to the camera (for quad effects)
Usage #
pnpm install
pnpm dev
Open https://blurz.localhost (served via portless — no port juggling). On first run, portless generates a local CA, asks to trust it, and may prompt for your password to bind port 443.
To run the dev server directly without the portless proxy, bypass it with PORTLESS=0 pnpm dev.
Controls #
| Input | Action |
|---|---|
| ← / → (or ↑ / ↓) | Cycle effects |
| Tap left half of canvas | Previous effect |
| Tap right half of canvas | Next effect |
| Clench both fists | Toggle quad mode (single / five-finger) |
Single mode: both hands form one quad between index fingers and thumbs — one effect applies to the entire area.
Five-finger mode: five fingers create four adjacent quads — each gets its own dedicated effect.
Available Effects #
- Gaussian Blur
- Chromatic Aberration
- Pixelation
- Edge Detect
- Kaleidoscope
- Invert
- Swirl
- CRT
- Thermal
- ASCII
- Posterize
- Bloom
- Displace
- Neon Edge
- RGB Glitch
- Psychedelic
- Liquid Chrome
In five-finger mode, quads 13–16 are used (Neon Edge, RGB Glitch, Psychedelic, Liquid Chrome).
Architecture #
src/
├── App.tsx — Root component: init pipeline, render loop, controls
├── index.tsx — Entry point
├── index.css — Styles: HUD, loading, error overlays
├── lib/
│ ├── constants.ts — Shared constants (finger indices, effect assignments)
│ ├── types.ts — TypeScript interfaces (Point, QuadCorners)
│ ├── effects.ts — Effect definitions and catalog
│ ├── webgpu.ts — WebGPU renderer (textures, pipelines, ping-pong)
│ └── handtrack.ts — HandTracker class (MediaPipe + smoothing + gestures)
└── shaders/
├── preamble.wgsl — Shared WGSL preamble (VertexOutput, Uniforms, helpers)
├── fullscreen-triangle.wgsl — Fullscreen triangle vertex shader
├── copy.wgsl — External texture → 2D texture copy
├── composite.wgsl — Final compositing + quad outlines
├── blur-horizontal.wgsl — Gaussian blur horizontal pass
├── blur-vertical.wgsl — Gaussian blur vertical pass
└── effects/ — 16 effect shaders
Pipeline #
- Camera captures video →
<video>element - Copy pass copies the external video texture into a regular
GPUTexture - Hand tracking (MediaPipe) detects landmarks → One Euro smoothing → fist detection → quad geometry
- Effect passes run per-quad shaders using ping-pong textures (multi-pass for Gaussian blur)
- Composite pass blends the sharp webcam feed with effect textures, drawing white quad outlines
Adding a New Effect #
- Create a WGSL fragment shader in
src/shaders/effects/(useVertexOutputandUniformsfrom the shared preamble) - Import it in
src/lib/effects.tsand add an entry to theEFFECTSarray - Optionally assign it to a five-finger quad slot in
src/lib/constants.ts
Build #
pnpm build
Produces a static bundle in dist/.