Every CamPlay game makes the same promise: your camera feed never leaves your browser. That sounds like a privacy-policy platitude, so this article explains it the honest way — by walking through the actual pipeline, component by component, and finishing with instructions for verifying the claim yourself with your browser’s developer tools. Nothing here requires trusting us.
The claim is architectural, not contractual. There is no server that receives frames and pinky-swears to delete them. The machine-learning model that reads your body is downloaded to your machine and executed there, and the only thing that ever crosses the network afterwards is gameplay data: a score, a calorie estimate, your progress bar in a multiplayer race.
The pipeline at a glance
flowchart TD
CAM["Webcam · 640×480<br/>(getUserMedia)"] -- "raw frames — never leave this tab" --> ML["MediaPipe PoseLandmarker<br/>WebAssembly + GPU, in-browser"]
ML -- "33 pose landmarks per frame — just numbers" --> ENG["CamPlay pose engine<br/>plain JavaScript"]
ENG -- "speed 0–1 · jump · duck · lean · lane" --> GAME["The game<br/>three.js scene · scoring · calories"]
GAME -- "only on run end / multiplayer sync" --> FB["Firebase<br/>score · calories · distance · duration — no imagery"]Step 1: the camera stays inside the tab
When you allow camera access, the browser hands the page a MediaStream through the standard getUserMedia API at 640×480. That stream is wired to a hidden video element and read frame by frame — the same mechanism every video-chat site uses, with one difference: the frames are consumed locally as model input instead of being encoded and transmitted. A camera stream has no network connection of its own; video only leaves a page if code explicitly uploads it, records it, or pipes it into a WebRTC connection. CamPlay does none of these, and you can confirm that in the verification section below.
Step 2: pose estimation runs in WebAssembly on your GPU
The model is a BlazePose-family pose landmarker — Google’s pose-estimation architecture, packaged as MediaPipe Tasks Vision. CamPlay loads the lite variant (a ~5 MB .task file served as a static asset, like an image) together with a WebAssembly runtime, and runs it with the GPU delegate in video mode. Modern laptops handle this comfortably: WebAssembly executes near-native inference code inside the browser sandbox, and WebGL does the tensor math on the graphics chip.
For each frame the model returns 33 landmarks — nose, eyes, shoulders, elbows, wrists, hips, knees, ankles and so on — each a normalized (x, y, z) position with a confidence score. This is the crucial privacy boundary: from this point on, the entire system operates on those 33 points. The pixels have already served their purpose and are discarded frame by frame. A pose landmark set is not an image; it cannot be replayed into one. It is a stick figure’s worth of coordinates.
CamPlay throttles inference to roughly 22 detections per second — one every 45 ms — which is deliberate. Pose detection shares the machine with a 3D game rendering at 60 fps, and running the model flat-out would cost battery and frame rate for no gameplay benefit. Movement signals are smoothed across frames anyway.
Step 3: landmarks become game signals
The raw landmarks feed CamPlay’s own input engine — plain JavaScript, no network access, open in your devtools. It converts landmark motion into a handful of abstract signals: a continuous running speed derived from arm-pump cadence and head bob, one-shot jump events, held duck and lean states, and which of three lanes your body occupies. Interestingly, only nine of the 33 landmarks are used — nose, shoulders, elbows, wrists and hips — so the games work with just your head-to-waist in frame. How those signals are engineered is its own story: How CamPlay detects jumps, ducks and jogging from pose landmarks.
The games never see the camera, the frames, or even the landmarks. They receive only the distilled signals — “speed 0.7”, “jump”, “lean left” — through a strict code boundary: game code never imports pose internals, and the pose engine knows nothing about games. That separation is an engineering choice (one input engine powers five very different games) but it doubles as a privacy guarantee, because the part of the codebase that touches the camera has no reason, and no pathway, to talk to a server.
What actually crosses the network
- Static assets, downloaded TO you: the page, the game code, the pose model file, the WebAssembly runtime.
- When a run ends: the result — game, score, estimated calories, distance, duration — saved to your profile so leaderboards and your stats page work.
- In multiplayer: your display name and a tiny progress update a few times per second, so friends see your ghost on the track. The course itself is generated on every player’s machine from a shared random seed, so there is nothing heavy to send.
- Standard analytics events (pages visited, games played) as described in the privacy policy.
Notice what is absent: no frames, no images, no landmark streams. The multiplayer design is worth a beat — because every machine deterministically generates the identical course from one seed, the network traffic for an eight-player race is a trickle of numbers. Video would be six orders of magnitude more data, in a game that never needs it.
Verify it yourself in two minutes
- Open any CamPlay game, press F12, and open the Network tab. Filter by WS and Media, then play a round. You will see the initial asset downloads (including the pose model), Firebase calls when a run is saved — small JSON payloads you can click and read — and no media uploads. Watch the request sizes: nothing outbound is remotely large enough to be video.
- Check total upload volume: a webcam stream is megabytes per minute; CamPlay’s outbound traffic over a full session is a few kilobytes.
- For the deepest check, play offline: load a game page, then disconnect from the internet. Pose tracking keeps working — because the thing doing the tracking is already on your machine.
Why we built it this way
Cloud-based pose tracking was never seriously on the table, for three reasons. Latency: a round trip to a server adds tens to hundreds of milliseconds, and a jump that registers late is a jump into a fire pit — motion controls live or die on responsiveness. Cost: GPU inference for every concurrent player would be one of the most expensive architectures imaginable for a free game. And trust: “we upload your camera feed but promise to be careful” is a sentence we never wanted on the privacy page. On-device inference wins on all three at once, which is rare and worth building around.
The same design shows up across the industry for good reason — face unlock, gesture controls and fitness mirrors all moved on-device. Browsers made this possible surprisingly recently: WebAssembly matured, WebGL/WebGPU compute became reliable, and Google shipped production-quality vision models sized for the edge. CamPlay is what those three trends make possible when combined: a real-time, full-body game controller made of software, running in a tab, that keeps every pixel it sees to itself.