Inspiration
Every study tool we'd used measured the same wrong thing: minutes elapsed. You can stare at a PDF for an hour, absorb nothing, and your Pomodoro app will still congratulate you. Meanwhile the research is unambiguous — you learn by retrieving, not by re-reading — and none of our timers knew the difference.
The four of us had also both had the experience of "studying" for three hours and discovering, the night before an exam, that almost none of it stuck. We wanted something that would tell us during the session, not after the grade.
So we built the app that takes your notes away and asks you to prove it.
What it does
Facedown runs you through rounds of study → recall → feedback → break, dealt as hands at a blackjack table.
Study. Upload a PDF or notes. Gemini extracts the specific learning objectives and the key points each one expects. A tutor sits beside your document and answers questions grounded in your source, citing page numbers — and every page it cites is validated against the document before you see it, so it can't invent a reference.
Recall. The timer ends and the document disappears. You write everything you remember into an empty box. The tutor refuses to help — and that refusal lives in the backend, not just the interface. Being able to look things up is the one thing active recall exists to prevent, so we made it structurally impossible rather than merely discouraged.
Feedback. The AI compares what you demonstrated against what the document says you should know, concept by concept: nailed it, half there, off the mark, didn't come up. It quotes the evidence from your own answer, then writes a short lesson from the gap. Mastery is stored per concept, so your next session automatically drills what's weakest.
Break. Throughout the round, a webcam reads facial expression and eye openness. Sustained stress or microsleeps make your next break longer, automatically. The app adapts to you instead of to a fixed 25/5.
And it locks the screen down while you work — releasing the moment a break starts.
How we built it
Backend — Python, FastAPI, SQLAlchemy. Owns the entire study loop as a state machine, plus auth (JWT), document parsing (PDF/DOCX/Markdown), and every AI call. AI — Google Gemini, with structured JSON schemas for objective extraction, recall assessment, lesson generation, and tutoring. Biometrics — the Presage SmartSpectra SDK, running as a child process of the desktop app, computing stress and drowsiness on-device and posting a per-round summary to the backend. Frontend — Next.js 16 and React 19, statically exported and served by the app itself over loopback. Desktop — Electron, with kiosk lockdown, a native file picker, and the camera process lifecycle. Storage — SQLite locally; Vultr Managed MySQL and Vultr Object Storage are both supported as drop-in backends. CI — GitHub Actions builds signed-for-distribution Windows and macOS installers on their own runners and publishes them to a release.
The central design decision: the backend owns the loop. The UI never runs its own timer or decides when a round ends — it reads the phase and deadline from the server. That's what lets the desktop app, a browser tab, and the camera process all agree about what round it is.
Challenges we ran into
A timer that never moved. Our countdown corrected for clock differences between browser and server. The correction cancelled out algebraically — deadline − (now + (server_time − now)) reduces to a constant — so the clock rendered its starting value and froze. Every backend test passed, because the backend was right. Only driving the actual UI in a browser exposed it. The fix was to stop mixing clocks entirely: measure the remaining time on the server's clock, measure elapsed time on the browser's, and never compare the two.
An installer with no camera. electron-builder silently excludes node_modules from extra resources. Our first Windows build looked complete and died on launch with a missing SDK. We now assert the native library exists before packaging — a build that would ship a broken camera fails instead.
Merging a teammate whose git broke. One of us had to hand over work as a zip of a different repo, with no shared history. We diffed the trees file by file, and found their credentials committed in plaintext to a public file along the way.
Lockdown that fought back. An early version stole focus and stayed always-on-top. It locked a teammate out of his own machine twice — force quit, Activity Monitor, switching to a terminal, all useless — and cost two hard reboots. We tore it out and added an emergency exit that bypasses everything and is registered before lockdown can ever engage.
Accomplishments that we're proud of
The enforcement is real. Recall isn't a UI convention we ask you to respect — the server rejects tutoring requests during it and hides your attempt history. The honesty of the feature is in the architecture.
The AI can't bluff. Assessment evidence must appear verbatim in your own answer or the response is rejected and retried. Cited pages are validated against the real document. Lesson markdown renders as React nodes, never raw HTML, so a malicious PDF can't turn "your lesson" into script execution.
The biometrics actually change behavior. Plenty of projects display a stress number. Ours feeds a real decision: a hard round earns a longer break, without you asking.
It's genuinely installable. Windows and macOS installers, built in CI, with the UI bundled — not a dev server and a README full of caveats.
What we learned
Testing an API is not testing an app. Our frozen clock passed 18 backend tests. Fifteen minutes with a real browser found it immediately. We now have a test that walks the exact call sequence the UI makes, in order.
Two clocks are one bug. Any time two machines both have opinions about "now," the fix is to never compare them — only compare differences measured on the same clock.
Say what your product doesn't do. No ordinary app can block Cmd+Tab; that's deliberate OS security design. Our stress numbers are heuristics over expression confidences, not a medical measurement. We documented both plainly in the repo, and we'd rather a judge trust the claims we do make.
A committed virtualenv breaks everyone but its author. 6,101 files with one machine's absolute paths baked in, which is why one teammate's environment never worked.
What's next for Facedown
Spaced repetition. We already track mastery per concept with timestamps and attempt counts — the data for a real forgetting-curve scheduler is sitting there. Next is surfacing a document for review the day before you'd forget it.
Course-level sessions. Today a session covers one document. Semesters don't work that way.
Scanned notes. We currently reject image-only PDFs rather than silently generating objectives from nothing. OCR would open up handwritten notes and photographed slides.
Calibrating the stress model. Our thresholds come from a handful of sessions with ourselves. They need real users across real lighting, skin tones, and cameras before we'd trust them further.
A signed macOS build, so the first launch doesn't need a right-click past Gatekeeper.
Built With
- bash
- computer-vision
- electron
- fastapi
- github-actions
- google-gemini
- javascript
- jwt
- mysql
- next.js
- node.js
- presage
- pydantic
- pytest
- python
- react
- smartspectra
- sqlalchemy
- sqlite
- tailwindcss
- typescript
- uvicorn
- vultr
Log in or sign up for Devpost to join the conversation.