CASE 01 · 2026 · Founder · Full-stack × ML

MIND PULSE PRO

Real-time behavioral stress detection that runs the model in the browser.

STATUS

SHIPPED PROTOTYPE — ENGINEERING EXPLORATION

RESULT

Browser-native stress scoring — 18.7ms P95 inference, fully offline, zero server round-trip.

LIMITATIONS

Signals captured from a single-user corpus; thresholds are not clinically validated.

FastAPINext.jsXGBoostONNX RuntimeTauriSupabaseWebSocketsWebLLM

⚠ This is an engineering prototype for behavioral-signal exploration — not a medical or diagnostic tool. Predictions require proper validation and informed consent.

01

THE PROBLEM

Stress is invisible until it isn't. Mental-health tools rely on self-reporting, which people game or skip. I wanted a system that reads stress from how you already work — keystrokes and mouse dynamics — without a single wearable.

Under 20ms inference — zero server round-trip

02

THE HARD PART

Getting inference under 20ms in the browser while keeping every prediction explainable — the model had to be small enough for the client, sharp enough to trust, and auditable end to end.

03

WHAT SHIPPED

Browser inference with zero server round-trip, plus a Tauri desktop client and fully offline WebLLM coaching — the whole ML stack runs on the user's machine.

THE FULL STORY


The story


Stress is a physiological signal that shows up in how you type before you'd ever admit

it in a survey. Self-reporting is the default tool, and it's gameable and skipped. The

insight: your keystroke timing, mouse velocity, and typing cadence are behavioural

signals nobody can fake easily.


The first version polled a REST endpoint every few seconds — 900ms of staleness on a

realtime problem. I rewrote the transport to WebSockets, pushed updates under 50ms, and

added mouse dynamics alongside the keyboard features. Then the bigger question: where

should the model run?


The browser won. Exporting XGBoost to ONNX and running it with onnxruntime-web

meant zero server round-trip, zero data leaving the machine, and offline coaching via

WebLLM. Under 20ms per prediction, with SHAP explaining every score. The model got

small enough to trust and auditable end to end — that combination is the real

contribution, more than any single benchmark.


IMPACT

  • Under 20ms inference — zero server round-trip
  • 50+ temporal features per typing session
  • SHAP explainability for every prediction
  • Fully offline coaching — no API keys exposed

THE ARCHITECTURE

Layered, labelled, honest — the system as it actually stands.

01 · SIGNAL CAPTURE

Keystroke timingMouse velocityCadence & drift

02 · FEATURE ENGINE

50+ temporal featuresSession windowsPrivacy filter

03 · INFERENCE

XGBoost → ONNXonnxruntime-webTreeSHAP explainer

04 · EXPERIENCE

Next.js dashboardTauri desktopWebLLM coach

SYSTEM FLOW

01Keystroke & mouse capture
0250+ temporal features
03XGBoost → ONNX
04Browser inference <20ms
05SHAP + WebLLM coach

WHAT IF …

Ask the project a different question. The architecture has to defend itself.

What if the model ran on the server, not the browser?

Latency would drop from 20ms to ~80ms on good networks (and much worse on Jio-tier mobile), privacy dies (keystroke patterns leave the device), and WebLLM's offline coaching becomes impossible. The browser was the constraint that forced the best architecture — 20ms inference with zero server cost and zero data leaving the machine. The trade is a ~1.5MB ONNX payload; I'd accept it again.

What if 10× users (10M typing sessions/day)?

The stateless design saves us: features are computed client-side, so load scales with the dashboard, not the model. I'd add: session-level feature stores with TTL, a clickhouse-style analytics sink for SHAP aggregates, and edge-cached onboarding — but the inference core stays client-side. Cost cliff: none for inference; infra spend stays ~flat.

DIVE DEEPER

Built it — now the descent. Each question opens the next layer: why, why this architecture, what broke, what I'd change.

01Why FastAPI + WebSockets?

Stress scoring is realtime by nature — polling added ~900ms staleness. WebSockets pushed updates under 50ms, and FastAPI kept the whole backend in one typed codebase.

02Why XGBoost instead of deep learning?

We extract 50+ tabular features from keystroke/mouse dynamics. XGBoost matched the accuracy of a small NN at a tenth of the latency, and ONNX made it run in the browser.

03What went wrong?

The first prototype polled a REST endpoint and overfit on keyboard-only features. I rewrote the transport to WebSockets and added mouse dynamics + SHAP so every prediction is auditable.

04What would I do now?

Distill to a smaller model, run federated feature extraction, and validate thresholds with a proper user study instead of my own typing.

THE REPO, INSIDE

Not a screenshot — a live iframe pulling this repo's README straight from the CDN.

THIS PROJECT LIVES IN A PRIVATE WORKSPACE