Inspiration
Every focus app today solves the same problem the same way: block distracting websites. But what happens when a student just picks up their phone? Or falls asleep? Or walks away entirely? Software-level blocking only controls one device — it can't tell if you're actually focused. I wanted to build something that watches the student, not the screen.
What it does
FocusLock uses Gemini 2.5 Flash's vision API to analyze your webcam in regular intervals and determine if you're genuinely studying. It detects phones, sleeping, zoning out, and leaving — but it's smart enough to not flag blinking, stretching, or checking your notes. Everything is gamified. You get lives — lose focus, lose a life. Lose all lives, game over. Sessions earn coins based on performance, which unlock items in a shop (extra lives, focus shields, streak freezes, coin multipliers) and custom flame skins (Frozen, Void, Cosmic, Divine, and more). There are 15 achievements to unlock, daily AI-generated quests calibrated to your personal stats, and a full analytics dashboard tracking focus trends, distraction patterns, best study hours, and a GitHub-style study calendar. The centerpiece is a reactive flame animation that grows when you're focused and sputters when you're not, backed by a real-time canvas particle system that shifts from calm green embers to chaotic red scatter based on your state. Every grade has its own cinematic reveal — S-rank triggers a meteor impact with Minecraft-style block explosion particles, A-rank is a video game level-up, B-rank forges the letter with hammer strikes and sparks, and C-rank glitches the screen like a system error. My favorite feature: when you get distracted, the app captures your exact webcam frame and slams it down in the session summary like evidence — stamped "CAUGHT," shareable as a PNG. And it's not just solo. Real-time multiplayer study rooms let friends compete on focus score with live leaderboards, flying crown transfers when the lead changes, and distraction ripple effects on other players' cards — all synced through Firebase.
How I built it
The entire app is a Next.js 14 project with TypeScript and Tailwind CSS. The AI backbone is Gemini 2.5 Flash — each webcam capture is sent as a base64 JPEG with a context-aware prompt that includes the student's task description, allowed devices, lives remaining, current streak, and distraction count, so the AI adapts its analysis and roasts dynamically. State management uses Zustand with localStorage persistence for user stats, achievements, inventory, and settings. The flame is a Lottie animation controlled by Framer Motion with dynamic scale, speed, and glow based on focus state. The particle system is a custom Canvas 2D renderer running on requestAnimationFrame at 60fps with different particle behaviors per state (calm rise, chaotic scatter, explosive burst, dying embers). Multiplayer runs on Firebase Realtime Database — each player pushes their focus state every few seconds, and all clients subscribe to the room for live updates. Framer Motion's layout animations handle the leaderboard card reordering and crown transfer arc. The grade reveal animations, sound effects (impact thuds, level-up dings, forge clanks, error beeps), and the ambient fireplace loop are all generated with the Web Audio API — no external audio files needed for the core effects.
Challenges
The biggest challenge was Gemini's sensitivity. Early versions flagged blinking as "sleeping" and glancing at notes as "distracted." I rewrote the prompt multiple times, added a confidence threshold gate (only accept distractions above 85% confidence), and added a consecutive-check requirement so only sustained distractions cost a life. Coordinating the animation sequences was another challenge — the S-rank meteor involves a rumble, a streaking particle with trail, an impact flash, screen cracks growing outward, Minecraft block particles with gravity and bouncing, screen shake, the grade emerging through cracks, cracks healing, then confetti — all precisely timed. Managing this with Framer Motion and setTimeout chains required careful orchestration. Firebase real-time sync in multiplayer required throttling updates to prevent hammering the database while still feeling responsive. I settled on syncing every 3 seconds with optimistic local updates. Worst of all. Gemini's API suspended my account after deployment likely due to too many requests being sent during my demo phase. This led to a very rushed demo video and the lag of having multiple requests being sent to my webcam did not help.
What I learned
Prepare earlier for demos, you never know what might happen, and if you need help, ask.
Built With
- canvas-api
- firebase-realtime-database
- framer-motion
- gemini-2.0-flash-api
- howler.js
- lottie
- next.js-14
- react
- recharts
- shadcn/ui
- tailwind-css
- typescript
- web-audio-api
- zustand
Log in or sign up for Devpost to join the conversation.