Intiaj Islam
←All workCase study 02 / 10

Screen Therapy

A calm Mac companion that tracks screen time, times your breaks and watches out for your eyes

A native macOS menu bar app for people who live at their desks. It measures screen time and focus on the Mac itself, times 20-20-20 eye breaks behind calming full-screen scenes, and, with the camera (only if you opt in), counts blinks, notices tired eyes and a tense brow, and checks that a break really was a break. No account, no cloud, no analytics.

Client
Personal product
Field
Native macOS & On-Device AI
Stack
Swift, SwiftUI, AppKit, Core ML, MediaPipe
Status
In progress
Screen Therapy

Overview

Screen time that looks after you, not just counts you

The problem

Most screen-time tools count hours and stop there. Break timers interrupt mid-sentence, in the middle of a call, or halfway through a drag. And the thing that actually wears people out at a desk — staring without blinking, forgetting to look away, sitting rigid for hours — goes unmeasured, because measuring it means a camera, and nobody wants a camera feed leaving their Mac.

What I built

A native macOS menu bar app that measures your day on the Mac itself, times eye breaks so they arrive at a good moment, and — only if you opt in — reads blinks, focus and posture from the camera with on-device face models. Swift, SwiftUI and AppKit, no account, no server. It averages under 2% of an M1's CPU.

In motion

Fifty seconds through the app.

Built in HyperFrames from the app’s own screens, each one rendered from its SwiftUI views: the menu bar panel, the Screen Score, eye tracking, break scenes, both appearances and the privacy panel that says what never leaves the Mac.

01 — Statistics

Statistics first

Your whole day, in one window.

The main window opens on today: a Screen Score, screen time, breaks, the longest stretch without one and whether eye tracking is on. Below it, six tiles — screen time, balance, breaks, eyes, focus and most-used — each open a review page for today or the week.

Every screenshot on this page follows this switch.
Screen Therapy Statistics dashboard

02 — Menu bar

One click from the menu bar.

The panel puts statistics first: today’s screen time with a trend against yesterday, the Screen Score, the productive/leisure split, a seven-day chart with an average line, and the live break timer. The status item can show an icon, the score, or time to the next break.

  • ⌥⌘BTake an eye break now
  • ⌥⌘LTake a long break now
  • EscSkip a break, or dismiss a reminder
Screen Therapy menu bar panel

03 — Review

Seven pages that explain the number.

A score is only useful if it says why. The Screen Score combines its parts as a weighted geometric mean, so one weak part pulls the total down, and parts with nothing to measure are left out rather than counted as zero — turning the camera off never lowers your score.

Six parts, each out of 100: pacing, movement, balance, focus, eye care and ease. The page says which part cost the most points and how to win them back.

Screen Score review page

Today and the week

Score page for today, with the part that cost the most points opened

Today. Each part against your usual day, and the points you could still win back, on 3D badges.

Score page for the week, comparing one day with the rest

This week. Seven days side by side, with any day comparable against the rest and against last week.

04 — Breaks

20 · 20 · 20

A break screen you don’t want to skip.

Every 20 minutes, look 20 feet away for 20 seconds; after a few of those, a longer break. The break covers every display with one centred Liquid Glass control bar and a breathe in, breathe out cue on a 10-second cycle — six breaths a minute. The scenes are animated mesh gradients chosen from colour research: soft, low-saturation colours, blues and greens for lower arousal, and evening palettes low in the blue light that suppresses melatonin.

Break screen with the Forest Bath scene
Circadian break scene

Circadian

Follows the time of day; warm and dim at night

Forest Bath break scene

Forest Bath

Greens that restore attention

Sea Glass break scene

Sea Glass

Low-arousal blues and teals

Lavender break scene

Lavender

Soft, low-saturation violet

Amber Dusk break scene

Amber Dusk

Evening palette, low in blue light

Moonlight break scene

Moonlight

For late nights

05 — Smart Pause

Breaks that wait for a good moment.

A break that lands mid-sentence gets skipped, and a skipped break teaches nothing. When one comes due, Smart Pause holds it while you’re in the middle of something, with a quiet note by the pointer that stays out of screen shares. Natural breaks count too: a few seconds of camera check after you stop typing sorts each one into stepping away, resting your eyes, looking down at a phone, or locking the Mac. Meetings count as work, never as breaks.

Holds forWaits
TypingA key in the last 2.5 secondsUp to 90 s
DraggingA drag in the last second, or the button heldUp to 90 s
DictationA dictation app or macOS Dictation has the microphoneUp to 90 s
CallA meeting app is in a callUntil it ends, plus a minute
VideoAnother app is keeping the display awakeUp to an hour
Focus appAn app you chose is in frontUntil you switch away

Typing, dragging and dictation share a 90-second limit, so a held key can’t keep breaks away for good.

06 — Eye tracking

Optional · off until you agree

The camera sees a face. The app keeps a number.

With the camera on, Screen Therapy counts blinks and nudges you when the rate drops, notices a brow held tense, follows tiredness through the day from heavy eyelids, long blinks and yawns, and checks whether you actually looked away during a break. The setup guide shows exactly what it takes: the camera’s picture next to the only thing the app uses — the face mesh, drawn live as a halftone print.

Setup step showing what the camera sees and the halftone face mesh the app uses
The face mesh drawn as a halftone print, blinking and glancing around

The setup guide’s sample face, rendered frame by frame from the app’s own halftone view.

  1. 01

    Camera

    AVFoundation, 15 fps

    Only on the schedule you pick: breaks only, sampled, or continuous — with separate choices on battery and on the charger.

  2. 02

    BlazeFace

    0.29 MB · 0.9 ms

    Finds the face, then sleeps to 2 fps once the mesh is tracking on its own.

  3. 03

    Face Mesh V2

    478 points · 2.7 MB

    3D landmarks including 10 iris points, tracked from frame to frame.

  4. 04

    Blendshapes V2

    52 scores · 1.0 MB

    eyeBlink, browDown, jawOpen, eyeSquint… the movements the face is read as.

  5. 05

    Signals

    Swift, per minute

    Blinks, look-aways, eye rests, focus level, brow tension, yawns. The frame is dropped; only numbers remain.

Posture reminder badge, animated
Posture
Blink reminder badge, animated
Blink

Reminders that wait until you’ve done it.

Small floating badges: chevrons lift for posture, an eye blinks for blink. With the camera, the badge fills as it sees you move or counts your blinks, and closes itself once you have — no timer while it can see your face. A blur halo, a two-tone rim and ripple rings keep it visible on any background, and it can hide itself from screen recordings.

07 — Every setting

Ten pages of settings, none of them a list of switches.

Each page leads with a live preview of what it changes, and every slider is a ruler that lands on round values. Liquid Glass controls on macOS 26, with frosted fallbacks back to macOS 13.

Limits & Alerts settings page
Limits & Alerts
Breaks settings page
Breaks
Auto Pause settings page
Auto Pause
Posture & Blinks settings page
Posture & Blinks
Eye Tracking settings page
Eye Tracking
Nudges settings page
Nudges
Sounds settings page
Sounds
Keyboard Shortcuts settings page
Keyboard Shortcuts
Settings settings page
Settings
About settings page
About

08 — First run

A setup that asks before it watches.

Nine short steps: how long you’re at the screen, how breaks should feel, what stays private, which permissions it needs and why, reminders, the camera (optional, with a preview first) and limits drawn from screen-time guidelines. The app is useful with every optional step skipped.

Setup step: Welcome
01Welcome
Setup step: About you
02About you
Setup step: Breaks
03Breaks
Setup step: Privacy
04Privacy
Setup step: Permissions
05Permissions
Setup step: Reminders
06Reminders
Setup step: Eyes
07Eyes
Setup step: Limits
08Limits
Setup step: Ready
09Ready

Hard problems

Four decisions that shaped the build.

  1. 01

    A machine-learning pipeline that fits inside a menu bar app

    macOS has no ARKit-style face tracking, so every signal is built from plain webcam frames. Google's MediaPipe BlazeFace, Face Mesh and Blendshapes models were converted op by op from TFLite to Core ML with a pinned, SHA-256-checked converter, and each was verified against TFLite to within 0.034 px. They run on the Neural Engine at about 4 ms a frame. Apple's own Vision framework was tried first and cost twice the CPU, so it was cut from the app and kept in a separate lab for comparison.

  2. 02

    Finding the CPU that wasn't ours

    Profiling showed the app at 22–24% of a core with the camera on, and most of it wasn't eye tracking. macOS Reactions were running hand-gesture models on every frame, and an open Settings window was redrawing animated previews at 30 fps while AppKit rebuilt drag regions on every frame. Gestures are now switched off in the bundle, animations pause when the window isn't in front, and the camera preview hands frames straight to the window server. That brought the 1080p preview from 27% of a core to 2.7%.

  3. 03

    Not every look-away is a distraction

    Looking down at the keyboard, or at a second screen while typing, isn't losing focus. Glances under two seconds are ignored, looking away while there's input doesn't count, and anything over 20 seconds counts as an eye rest. Focus is judged minute by minute, and the face is read only as movements (a smile, talking, a yawn, a lowered brow), never as a guess at feelings.

  4. 04

    Private by construction

    There is no account, no server and no analytics. Usage is read from public AppKit APIs (the frontmost app, idle time), never from Apple's private Screen Time stores. 120 days of stats are sealed with AES-GCM under a 256-bit keychain key, each file bound to its own name. Camera frames are analysed in memory and never written down. An early version fetched site favicons, which told every site you'd visited about it; that request was removed.

Performance

Of an M1's CPU, averaged across a working day with sampled eye tracking on
<2%Of an M1's CPU, averaged across a working day with sampled eye tracking on
To run BlazeFace, Face Mesh and Blendshapes on a tracked frame
4 msTo run BlazeFace, Face Mesh and Blendshapes on a tracked frame
Network requests, accounts or analytics. Everything stays on the Mac.
0Network requests, accounts or analytics. Everything stays on the Mac.
Lines of Swift across the app, the shared engine and the lab, with 50 test suites
40KLines of Swift across the app, the shared engine and the lab, with 50 test suites

How it's built

Client
Native Swift 5.9 with SwiftUI and AppKit: a menu bar app with a status item, a popover, a main window, full-screen break overlays on every display and floating reminder badges
Backend
No server. A Swift Package with three targets — the app, a shared EyeTrackingCore engine, and an Eye Tracking Lab used for tuning — and 50 XCTest suites, including snapshot tests for every screen
Data
120 days of stats in Application Support, sealed with AES-GCM (CryptoKit); the 256-bit key lives in the keychain and settings in UserDefaults
Services
Google MediaPipe BlazeFace, Face Mesh V2 and Blendshapes, converted to Core ML and run on the Neural Engine; AVFoundation, IOKit power sources, CGEventSource and NSWorkspace

What shipped

  1. 01A stats-first menu bar panel and a main window with a Screen Score and seven Review pages, for today or the week
  2. 02Full-screen break screens on every display, with nine animated mesh-gradient scenes, six wallpapers and a breathing cue
  3. 03On-device eye tracking: MediaPipe face models converted to Core ML, verified against TFLite, at a few milliseconds per frame
  4. 04Smart Pause, which holds a break while you type, drag, dictate, take a call or watch a video, and sorts each break into stepping away, eye rest, looking down or locked
  5. 05Posture and blink badges that wait until the camera sees you move or blink
  6. 06A first-run setup wizard, encrypted local storage and an Eye Tracking Lab for recording and replaying labelled sessions

Next project

EpicQuest→

A treasure hunt hidden inside a film series — watch, decode, win