Inspiration
What it does# ReFramed
Inspiration
A stupid bet with a friend about who could nail the Vitruvian Man pose. We spent 20 minutes taking bad photos of each other, and I thought — why isn't this a game? Claude can actually look at two photos and tell you whose arms are at the wrong angle. That's the whole idea.
How I Built It
Next.js + Supabase + Claude. Players share a 4-letter room code, get 5 seconds to study a reference pose, 15 seconds to recreate it on camera, then Claude scores both attempts and roasts whoever flopped.
Every game state (lobby, preview, capture, scoring, results) maps to a single column in the database. When the host advances the state, Supabase Realtime pushes the change to both phones and they redirect themselves — no peer-to-peer, no sockets to manage manually.
Countdown timers are synced from a server timestamp so both phones show the same number regardless of when they loaded:
$$t_{\text{remaining}} = \max\left(0,\ T - \left\lfloor \frac{t_{\text{now}} - t_{\text{start}}}{1000} \right\rfloor\right)$$
The scoring prompt weights body geometry only — silhouette (20 pts), arms (25 pts), legs (25 pts), torso (20 pts), head/neck (10 pts). Clothing, background, and lighting are explicitly ignored.
Challenges
Mobile WebSockets die. iOS Safari kills long-lived connections when the screen locks. Added a polling fallback alongside Realtime — inelegant but it works.
Claude returns malformed JSON. Under tight token budgets it occasionally wraps output in markdown fences or truncates. Fixed with a fence-stripping parser and two automatic retries before a neutral fallback.
The mirror problem. Front cameras show a mirrored preview by convention, but the actual captured image isn't mirrored. The canvas capture re-applies scale-x: -1 before encoding so the saved photo matches what the user saw — otherwise left and right arms are swapped in the comparison.
What I Learned
The prompt is the product. "Compare these poses" gives inconsistent garbage. Explicit criteria with score bands and a JSON schema gives something that actually feels fair. The model is capable — you have to tell it exactly what to measure.
Built With
- next.js
- sonnet
- supabase
- tailwind
- typescript

Log in or sign up for Devpost to join the conversation.