Point your finger to restyle your live camera. Point right for the next style, left for the previous — claymation, anime, oil painting, pixel art… — or open your hand to drop back to the normal feed.
Your webcam is tracked in real time with Google MediaPipe Hand Landmarker
(21-point hand tracking, in the browser). The direction your index finger points
picks the style, and the live feed is restyled frame-by-frame by
fal-ai/flux-2/klein/realtime.
┌──────────────────────────────────────────┐
│ ✨ Anime (live) │
│ │
│ restyled camera feed │
│ 👉 ──▶ (next style) │
│ │
│ [Normal] [Claymation] [Pixar] (Anime) … │ ← style strip, active highlighted
└──────────────────────────────────────────┘
- 🖐️ Hands-free style switching — point your index finger left/right to flip through styles; styles cycle in order.
- 📷 Normal feed first — style index 0 is your raw camera (no model call, instant, free); every other style streams through fal.
- ✋ Open hand → reset — snap straight back to the normal feed.
- ⚡ Realtime — frames stream at a target FPS with pipelined backpressure and an auto-reconnect watchdog (the endpoint re-checks billing ~every 30 s).
- 🪞 Selfie-correct — the preview and the sent frame are both mirrored, so "point toward the right edge of the screen" always means next.
- 🎛️ Tweakable — endpoint, output size, steps, temporal feedback and send FPS in the Settings panel. Click a chip in the strip to jump to any style.
| Gesture | Action |
|---|---|
| 👉 Index finger pointing right | Next style |
| 👈 Index finger pointing left | Previous style |
| 🖐️ Open hand | Back to Normal feed |
Hold a direction to keep cycling (one step per ~0.75 s). A short "flick" steps one style. The on-screen arrow fills up as the gesture is recognized.
Keyboard fallback: the ← / → arrow keys step through styles too — handy for testing the styling round-trip without relying on hand tracking. (Ignored while you're typing in the Settings panel.)
browser (public/) server (server.js)
├─ MediaPipe HandLandmarker ─ hand ┐
├─ gestures.js (point left/right) │
├─ filters.js (One-Euro cursor) │
└─ styler.js │
├─ tokenProvider ─────────────┼─► POST /api/fal/token
│ │ attaches FAL_KEY → mints a short-lived token
└─ square JPEG over WS ───────┼──────────────────────────────────────► fal-ai/flux-2/klein/realtime
│ (WebSocket connects straight to fal with the token)
└─ → streamed styled frames
- Hand tracking runs entirely in the browser (WebGL/WASM) on a small inference canvas — the displayed camera stays sharp and inference stays cheap.
- Only frames for an active style are sent (the normal feed sends nothing).
- Your fal key stays on the server. The browser asks
/api/fal/tokenfor a short-lived realtime token (the server attaches the key); the realtime WebSocket then connects straight to fal with that token. The key never reaches the browser. (A generic/api/fal/proxyis also kept for any other REST call.)
- Hand tracking: @mediapipe/tasks-vision (HandLandmarker)
- Realtime styling:
fal-ai/flux-2/klein/realtimevia@fal-ai/client - Server: Node.js + Express (static + tiny fal proxy)
- Frontend: build-less vanilla JavaScript (ES modules) + Canvas API
Requirements: Node.js 18+ and a fal API key (https://fal.ai/dashboard/keys,
format key-id:key-secret).
git clone https://github.com/ahmetvural79/CameraRealtimeStyle.git
cd CameraRealtimeStyle
npm install
cp .env.example .env # then put your FAL_KEY in .env
npm startOpen http://localhost:3000, click Start Camera, and grant camera
permission. (The page is served over localhost so the camera works in a
secure context.) Then point left/right to change the style.
You can also pass the key inline:
FAL_KEY=your-key-id:your-key-secret npm start| Variable | Default | Description |
|---|---|---|
FAL_KEY |
— | Required for styling. Your fal key (key-id:key-secret) |
PORT |
3000 |
Server port |
The Settings panel (footer) exposes the realtime endpoint, output size
(square 768 / square_hd 1024), inference steps, temporal feedback
(1.0 = follow the camera each frame, lower = smoother/ghosting), and the send
FPS target.
Edit the STYLES list ([name, prompt] pairs) near the top of
public/styler.js. The first entry is the raw camera (prompt = null);
reorder or add your own prompts freely. Prompts are framed as transformations
(Turn this into…) so the model restyles your camera rather than inventing a
new scene.
CameraRealtimeStyle/
├─ server.js Express static + fal proxy (/api/fal/proxy)
├─ package.json
├─ .env.example
└─ public/
├─ index.html stage, styled output, style strip, settings
├─ styles.css
├─ app.js camera + MediaPipe loop + style orchestration
├─ gestures.js 21 landmarks → point left / right / open
├─ filters.js One-Euro smoothing for the cursor
└─ styler.js fal realtime connection + the STYLES list
- Point clearly sideways (finger roughly horizontal) — an upward "1 finger" pose is treated as a neutral pointer and won't switch styles.
- Good, even lighting makes hand tracking much more reliable.
- The view is 16:9 widescreen and the camera is requested at 1080p. The klein realtime model only outputs a square (768 or 1024), so the app sends the largest centered square of your camera (mirrored) and the styled layer is center-cropped to fill the widescreen frame.
- Speed vs. quality. The 16:9 ratio is display-only and doesn't affect model
speed — the cost is the square the model processes. Defaults are tuned for
speed: output size
square(768) and 2 steps. For a sharper result, bump Output size → square_hd and Steps → 3–4 in Settings (slower). Latency and FPS also depend on the endpoint's current load.