Dev.to · 4 min read

Slow-Breath Coach: your webcam scores how well you breathe along

Slow-Breath Coach: your webcam scores how well you breathe along

Challenge entry for the Presage SmartSpectra SDK Challenge. Code: https://github.com/474443481/slow-breath-coach 💡 The idea Most breathing apps count seconds and assume you followed along. Slow-Breath Coach does not assume anything: it watches your chest through a plain webcam with the Presage SmartSpectra SDK, measures your actual breathing waveform, and scores how well you tracked the pacer after each session. The target is 5.5 breaths per minute — the resonance pace where six seconds in and six seconds out line up with heart-rate rhythms. The pacer circle expands as you inhale, contracts as you exhale, and the score tells you how close your real chest motion came to that rhythm. 🎬 Demo ▶ Watch the 30-second demo: demo.webm — 10 MB, webm, direct play (Also committed at github.com/474443481/slow-breath-coach — pacer circle, live waveform and the follow score, recorded straight from the app's own /demo canvas.) 30 seconds, canvas-rendered, self-recorded by the page itself (/demo?record=1). The demo replays a synthetic breathing signal through the exact same scoring function used on live camera captures, so the UI is honest even without a face in frame. 🧠 How it works Three metric channels from the SDK (requestedMetrics: [0, 2, 15]): the chest breathing trace, breathing rate, and pulse. Frames go from the browser (JPEG, 15 fps) to a local Node server, which decodes them and feeds the SDK through a forked worker process over IPC. Two SDK quirks ate most of my debugging time — worth documenting for the next person: Timestamps must be epoch microseconds, and they must be gap-free. I first passed process uptime. The SDK silently treated the frames as days old, stalled the pipeline, and the session died at exactly 151 frames — every single time. Then real-world browser capture jitter (a dropped frame here, a 40 ms stall there) trips the SDK's gap detector: SmartSpectra detected a gap between camera frame timestamps. The fix: a virtual 15 fps clock, +16 667 µs per frame, re-anchored to Date.now() * 1000 on every new worker. IPC must use serialization: "advanced". A plain child_process.fork turns Uint8Array frame buffers into plain objects on the other side, and sendFrame rejects them with a confusing type error. The score. Every second the server takes the last 30 s of the smoothed upper-chest trace and computes a normalized cross-correlation against the pacer's cosine reference, maximized over lags of ±half a period (a steady lag is fine — you may breathe slightly behind the circle — but the rhythm must match). That blends with a rate gate from zero-crossings: score = 100 × (0.6·corr + 0.4·rateGate). A noise-only trace can fake a high correlation, but the rate gate kills it. Validated on synthetic signals from perfect following (1.00) down to pure noise (0.12). Survivability. The native SDK pipeline wedges in long real sessions, so the HTTP server never loads the SDK itself. The worker is a disposable fork that self-recycles (no face for 140 frames, no metrics for 400, 9 s of silence) and a tiny supervisor respawns it — the dashboard websocket never dies with the SDK. 🛠 Run it git clone https://github.com/474443481/slow-breath-coach cd slow-breath-coach npm install @smartspectra/node-sdk jpeg-js PRESAGE_API_KEY="" node coach_server.mjs http://localhost:8815/ — camera capture page (consent gate, then keep the tab in the foreground) http://localhost:8815/dashboard — pacer circle + live waveform + score http://127.0.0.1:8815/demo?record=1&secs=30 — the canvas demo above, and it records itself Free API key: physiology.presagetech.com (100 credits on the free tier). 🔐 Consent and Data Handling Consent first. The capture page shows a blocking consent notice explaining what is captured and where it goes; nothing starts until you press I agree. What leaves your machine. JPEG frames go to the local Node process and are forwarded to the Presage cloud API for physiological inference — that is the SDK's architecture (see Presage's Telemetry and Privacy documentation). The SDK also reports anonymous usage telemetry to Presage. What is stored. Nothing, anywhere. The server keeps a bounded in-memory ring buffer for the live chart and discards it on restart. No frames, no video, no waveforms are written to disk. Closing the capture page stops the stream. No medical claims. This is a breathing-pacing toy, not a diagnostic device. Its numbers are not medical measurements and it makes no health claims. 🎯 What I learned Camera pipelines are 20% vision and 80% plumbing. This week a webcam was held hostage by a QQ video call, then by the Windows Camera app, then by a quietly stopped Frame Server service, then by zombie device handles inside Edge — and underneath all of that, the SDK wanted a frame clock more regular than any real camera delivers. The virtual clock fixed the SDK; the process firewall fixed everything the SDK still throws at you. The nicest surprise: once the timestamps were honest, the correlation between "am I following the circle" and "what the SDK sees in my chest" was immediately visible on the waveform — no calibration, no tuning.

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Cybersecurity News