Inspiration
The average knowledge worker spends ~40% of their day in actual focused work, and it takes around 23 minutes to recover from a single interruption. The tools built for this problem are terrible. Pomodoro timers just count to 25 with no idea if you're actually locked in. Webcam proctors ship your face to the cloud so your boss (or your school) can judge you. Nothing in the middle.
We wanted a focus tool that was honest with YOU: watches what's actually happening, runs entirely on your machine, and nudges you back when you slip.
What it does
Drift is a web app plus a small USB desk pod that reads six live signals and fuses them into a focus score from 0 to 100.
The six signals:
- Typing rhythm (WPM, consistency, backspace surges)
- Gaze (yaw direction from 468 FaceMesh landmarks)
- Facial expression (eye-aspect ratio, blink rate, lid droop)
- Head pose (pitch drift is a microsleep tell)
- Room noise (KY-037 analog mic)
- Ambient light (LDR)
A six-state classifier runs in real time. It reclassifies you as active typing, thinking pause, reading, distracted, fatigued drift, or unknown, and re-weights every signal to match what you're actually doing. A typing pause means thinking if your eyes are on the screen and drifting if they're not. Same signal, different meaning.
The pod has a rotary knob for three modes: Study, Reading, and Presentation. Each mode swaps the fusion weight table, so reading (where typing is irrelevant) scores you differently from coding (where it's central).
Feedback is closed-loop: an OLED mirrors the score, an 8-pixel WS2812B strip runs a smooth red→amber→green HSV gradient mapped to your score, and a piezo buzzer nags when you really drift.
How we built it
Front end: React 18 + Vite + Tailwind 4, recharts for the session timeline.
Vision: MediaPipe FaceMesh (468 landmarks) in the browser. Webcam frames never leave the browser, MediaPipe is WASM-local, and the pod has no WiFi.
Bridge: WebSerial API (Chromium only). Zero drivers, zero servers.
Firmware: Arduino / ESP32-S3-WROOM-1 in C++. Libraries: Adafruit_NeoPixel, SSD1306 for the OLED, direct GPIO for the KY-040 encoder and KY-037 mic. The LED color is computed by feeding a 0–100 focus score into ColorHSV() through gamma32() for a perceptually smooth gradient.
Fusion: A 45-second personal baseline locks in YOUR WPM, blink rate, eye-aspect ratio, and head pose. Every later sample is a delta against that personal snapshot. Low blink rates get a 1.5× weight because microsleep-adjacent staring is the dangerous direction, not blinking a lot.
Protocol: Browser pushes FOCUS:<0..100> every 1 second (dedup'd on integer change). Pod pushes DATA:<noise>,<light> and MODE:<study|reading|presentation> on knob commits.
Challenges we ran into
- Signal noise. A one-second typing pause could be a sip of coffee, a thought, or a full zone-out. The state machine resolves it by cross-referencing gaze. That cross-reference is most of the magic.
- Cadence. Our first cut only sent FOCUS to the pod every 10 seconds, so the LED felt dead. We split the snapshot cadence from the push cadence (1 Hz with integer-change dedupe) and everything snapped into real time.
- Fatigue as a delta, not a snapshot. A slow typer isn't fatigued. Someone whose WPM fell 25% against their own baseline is. Getting the baseline window (45 s) long enough to be stable but short enough to be practical took real tuning.
Accomplishments we're proud of
- Genuinely private by design. No cloud, no WiFi, nothing phones home.
- Real hardware in the feedback loop, not just a pretty web demo.
- Six states, six weight tables, live. Most "focus trackers" are a single heuristic with a nice chart. Drift actually reclassifies your behavior.
- A single rotary knob changes the definition of focus to match what you're doing.
What we learned
- How to fuse noisy, asymmetric signals without letting any one of them dominate.
- ESP32-S3 pin planning (which pins are strapping, which ADC channels survive WiFi).
- WebSerial pacing and the cost of over-talking to a microcontroller.
- MediaPipe's FaceMesh is wildly powerful but needs aggressive smoothing to not jitter.
- Piezo buzzers are so much more motivating than screen notifications you'll ignore.
What's next for Drift
- Per-user learning across sessions, so the baseline improves every week.
- Shareable focus history as an exportable local file, never a cloud account.
- More modes (coding, writing, video-call) with their own weight tables.
- A mobile companion so the pod can live in a backpack, not just a desk.
Built With
- adafruit-neopixel
- arduino
- cpp
- esp32
- html5
- javascript
- mediapipe
- react
- recharts
- ssd1306
- tailwindcss
- vite
- webserial
Log in or sign up for Devpost to join the conversation.