About the Project Inspiration I kept uninstalling water reminder apps. Every single one had the same design: a notification appears, you tap "done", and both you and the app agree to pretend you drank something. There is zero accountability, which means the habit never forms.

I wanted to build the app I would actually obey. The thesis was simple: what if the alarm literally could not be dismissed until your phone watched you drink? Not a tap, not a swipe, not a promise. Proof. On camera, processed locally, with nothing uploaded.

The name is Filipino slang for water. The product is built for people who know they under-drink and have tried the gentle reminder approach already.

What it does Wattah is a hydration app where the alarm holds your screen hostage until you prove you drank.

You set your glass count (8 to 16) and your waking hours once. The schedule distributes reminders evenly across your day, with a 30-minute buffer after waking and a 90-minute buffer before sleep. When one fires, it takes over the screen. No close button. No escape. The only exit is proof.

Proof works in two stages:

Show the glass. Hold a real drinking vessel in frame for two seconds. The system uses YOLO11s object detection to find cups, bottles, and glasses, combined with a custom optical signature detector that measures achromatic content, specular highlights, and edge density to verify transparent glassware that COCO-trained models routinely miss.

Take the drink. With the glass proven, hold the drinking gesture for five unbroken seconds. Four detectors must agree simultaneously: the vessel is at your mouth, your head is tilted back past baseline, the object is making contact with the mouth region (measured in mouth-widths for scale invariance), and there is real micro-motion in the frame (a still photo scores zero and can never pass).

Everything runs locally. MediaPipe face and hand landmarks via WASM, YOLO inference in a Web Worker via ONNX Runtime, and a hand-built optical glass scanner. Frames are scored and discarded. Nothing is uploaded, stored, or seen by anyone.

On Android, the alarms are scheduled with the OS itself via Capacitor, so they fire whether or not the app is open. The notification is ongoing, non-dismissable, and arrives at max importance on its own channel.

The gamification layer tracks streaks, depth (cumulative glasses framed as descending into the ocean), and achievements. A global leaderboard runs on Cloudflare Workers with KV storage. The entire visual identity is built around real WebGL water: analytic Gerstner waves with physically derived normals, Beer-Lambert absorption, differential-area caustics, and Fresnel reflections. The water level in your glass is literally your progress.

How I built it Next.js 16 with Turbopack, deployed as a Cloudflare Worker via OpenNext Capacitor for the Android native shell (exact alarms, local notifications, camera) MediaPipe Tasks Vision (face landmarks + hand landmarks) running as WASM in the browser YOLO11s on ONNX Runtime Web, running inference in a dedicated Web Worker so the camera preview never freezes Custom optical glass detection using summed-area tables over a single GPU readback per frame, measuring achromatic ratio, specular density, and edge structure Three.js for the live water shader: four Gerstner wave bands with shared parameters driving displacement, analytic normals, caustics, and domain-warped FBM Cloudflare Workers + KV for the leaderboard API Web Audio API for procedurally synthesized alarm tones and interaction sounds Zustand for client state, localStorage for persistence, no accounts, no server-side user data Challenges I ran into Transparent glass detection. COCO-trained object detectors are trained overwhelmingly on opaque mugs. A clear glass against a kitchen counter is essentially invisible to them. I had to build a parallel detection path that looks for what glass does to light rather than what it looks like: low saturation, specular highlights along curved surfaces, and strong local gradients at the rim and waterline. Neither path is sufficient alone; requiring both is what makes it discriminating.

The drink is when every detector is worst. The act of drinking hides the glass behind your face, covers the mouth the system measures against, and occludes the hand carrying the vessel. Demanding continuous proof of the glass at the exact moment it cannot be given was failing real users. The solution was splitting verification into two tests: prove the glass first, plainly, while nothing obstructs it, then prove only the drinking gesture. That split is structural, not cosmetic.

ONNX Runtime blocking the main thread. The WASM backend runs inference synchronously, which froze the camera preview every frame. Moving YOLO into a Web Worker with ImageBitmap transfer (zero-copy) made the camera smooth again. The model preloads while the user is on the home screen, so the alarm never pays the session compilation cost.

Liveness without a server. A photograph held to the camera is geometrically perfect: correct landmarks, correct pose, correct everything. The only thing it lacks is motion. The liveness gate measures inter-frame optical flow and rejects anything below a micro-motion threshold. It cannot be defeated without actually moving, which a printed photo cannot do.

Scheduling across midnight. Users who sleep past midnight (most of them) break naive time arithmetic. The waking window has to wrap correctly, the reminders have to land in the right day, and rollover at midnight has to preserve progress without double-counting.

What I learned That verification is a UX problem, not just a technical one. The hardest part was not making detection work; it was making it work while someone is drinking, which is the one moment all the signals degrade. That moving ML inference off the main thread is not optional for real-time camera apps. The frame budget for smooth preview is 16ms, and even a small model blows past that on WASM. That optical properties (saturation, specularity, edge density) are a surprisingly effective proxy for object identity when the object is defined by being transparent. That "nothing leaves your device" is a product feature that constrains every technical decision downstream, and that constraint is worth more than the features it costs. What's next for wattah iOS build via Capacitor RevenueCat-powered subscription for premium features (calendar history, custom schedules, depth themes) Social accountability: share streaks and challenge friends Wearable integration for passive hydration tracking alongside active proof

Built With

Share this project:

Updates

Submission history