This is a submission for the Presage SmartSpectra SDK Challenge
What I Built
Don't Blink is a horror game you play with your eyes.
The screen is your own webcam image: your room, with you sitting in it. Somewhere behind you, something is standing. It only moves when your eyes are closed. Every blink, it's closer. Hold your stare and it backs off. Keep your eyes shut or look away, and it keeps coming. Last 60 seconds.
The rules are simple. Playing it isn't: you can't stop yourself blinking, and the harder you try, the more your eyes burn.
When it ends, you get a card with:
- your real pulse across the round, with every blink marked on it
- your peak pulse, your longest stare, and how close it came
- a photo of your room with it right over your shoulder
Demo
Three rounds: caught with my face showing, caught with Hide me on, then survived with Hide me on.
Code
zuhairhalawa / dont-blink
A horror game you play with your eyes: blink and it moves closer. Blinks and pulse read from a webcam with the Presage SmartSpectra SDK.
Don't Blink
A horror game you play with your eyes. Your webcam becomes a window into your own room, and something is standing in it. It only moves when your eyes are closed. Each time you blink it is closer, until it is right behind your shoulder.
Your blinks, pulse and breathing are read from an ordinary webcam by the Presage SmartSpectra SDK. Your real heartbeat sets the heartbeat you hear. No wearable is needed.
A game, not a medical device. The pulse and breathing numbers are estimates for fun. Expect flickering light and one sudden loud sound.
Pictures are from rounds played with Hide me on, so the player appears as a silhouette.
How to play
-
Agree to the consent screen. On the get-ready screen, choose whether to read your pulse and breathing (on by default). With it on, sit back so your shoulders and upper chest are…
Setup: npm install, put a free Presage key in .env, then npm run build and npm start. The README covers the rest, including a fix for Electron's install script on some Node versions.
How It Responds to Human Signals
| Signal | From | What it does in the game |
|---|---|---|
| Blinks | Presage SmartSpectra, face.blinking | Each blink onset moves the Watcher one step closer, in a new pose, while the screen's eyelids close |
| Pulse rate | Presage, cardio.pulseRate | Drives the heartbeat you hear and the beating dot on screen; plotted on the end card with your peak and how far it rose |
| Breathing rate | Presage, breathing.rate | Recorded for the round |
Integration. It's an Electron app on @smartspectra/node-sdk 3.4.0:
- The main process calls
bindSmartSpectraIpc(win). - The sandboxed preload bundles the SDK preload.
- The renderer creates
SmartSpectraSDKwith the face, cardio and breathing metric bundles, hands it the cameraMediaStream, and decodes eachmetricsbuffer withdecodeMetrics. - A small tracker turns
face.blinkingstatuses into blink onsets. - Pulse and breathing arrive in separate events, so the game keeps the latest of each.
What testing it on a laptop webcam taught me. I measured before building:
- Blink speed. A probe flashed a red circle at random moments and timed the blinks. Presage caught every deliberate blink. Each detected blink lasted 130–180 ms and arrived about 100–150 ms after my eyes closed, fast enough to feel instant in a game.
- Two gaps. Quick flutters can slip past, and a long eye closure isn't reported as a blink at all. That's a loophole: just keep your eyes shut. So the game also reads eye openness from MediaPipe, on the device, purely to catch held-shut eyes. In one round, Presage reported 3 blinks and MediaPipe 19 closures.
- Looking away. Presage's validation status stayed on "chest not visible" even when I left the frame, so head direction comes from MediaPipe's face pose too. A small person-segmentation model cuts you out of the picture, so the Watcher can stand behind you.
- Framing. Sitting close to a laptop, Presage gave blinks but no pulse while it reported "chest not visible". With my shoulders in view, the first pulse came at about 20 seconds. So the game has a pulse switch: on, it waits for full framing and a first pulse before the round can start; off, it reads blinks only and starts at once.
- CPU headroom. With full-screen effects and two on-device models also running, the SDK reported a processing failure every ~11 seconds and the pulse never arrived. Drawing at 30 fps on a 1280-px canvas and slowing the trackers fixed it, and any failure left is restarted within about 2 seconds.
- Errors. Every SDK error is sorted into "show the player and stop the camera" or "log it and keep playing". In play-tests the SDK twice reported a retryable processing error, and the game rode through.
Prize Categories
Most Creative or Delightful Use.
- The idea. Most camera-vitals apps ask you to sit still and be measured. This one turns an involuntary signal into the threat itself. You can't hide a blink, and you can't fake a racing heart.
- The room. The horror happens in your own room, and the end card proves what it did to your pulse.
- How it plays. Blinking as the main control makes it instantly understandable in a two-minute video, and surprisingly hard to play.
Consent and Data Handling
- Consent first. The camera turns on only after the consent screen, which explains everything below in plain words. Turn off the camera stops it at any time, and so does closing the window.
- Video stays on the device. The SmartSpectra SDK computes blinks, pulse and breathing on the computer. The MediaPipe models (head direction, eye openness, person cut-out) also run locally. No frame is uploaded or saved.
- What goes online. The SDK contacts Presage to check the API key.
- SDK telemetry is opt-in. A checkbox on the consent screen, off by default, sets
enableTelemetry. When it's on, Presage gets an anonymous per-session summary with no video and no readings. - Blocked by design. MediaPipe's library tries to post a usage log to Google when it shuts down. The app's content security policy blocks it, so nothing is sent.
- Hide me. A switch on the get-ready screen turns the player into a dark silhouette in everything the game draws (view and end-card photo; the framing preview is blurred), while blinks, pulse and head turns are still read from the clear camera. Until the person mask is ready, the whole picture is blurred. Rounds two and three of the demo video use it, and so do all the pictures in the README.
- Storage, retention and deletion. Blinks, pulse, breathing and the one end-card photo live in memory for the round, and are gone when the game closes. Nothing is written to disk unless the player clicks Save image, which saves a PNG where they choose. Deleting that file deletes it.
- No AI services, analytics or accounts at runtime.
- Not medical. The game says so on its first screen, and the end card says so too. No diagnosis, no health claims.




