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

GitHub logo 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

The Watcher reaches toward the player, shown as a silhouette in their own room

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.

The Watcher leaning in behind the player The Watcher reaching for the player, live pulse 88 bpm at top right

CAUGHT end card: blinks, longest stare, peak pulse and the pulse chart with blinks marked SURVIVED end card

Pictures are from rounds played with Hide me on, so the player appears as a silhouette.

How to play

  1. 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 SmartSpectraSDK with the face, cardio and breathing metric bundles, hands it the camera MediaStream, and decodes each metrics buffer with decodeMetrics.
  • A small tracker turns face.blinking statuses 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.