Inspiration
We kept coming back to how much of Reddit runs on "AITA" energy — someone posts a messy, oddly specific situation and the whole comment section splits into camps. There's rarely an objectively right answer, just what the crowd ends up deciding. That felt like a game already. So instead of building something where you're right or wrong, we built something where you're trying to guess what everyone else will think. Juro is basically "can you read the room" turned into a daily habit.
What it does
Every day there's one case, written in full Gen-Z chaos: "Left them on read for 6 hours then posted a story. Guilty?" You vote Guilty or Not Guilty, and you back it with a confidence stake — go big if you're sure, hedge if you're not. As people vote, the case image sharpens up in real time, so the reveal is literally tied to how many people have shown up that day. Nobody's "right" until the votes are tallied at the end of the day and the majority wins. Guess correctly and confidently enough over time and you build a streak and climb the leaderboard.
How we built it
It's Devvit Web underneath — React, Vite, Hono, TypeScript — with Phaser 4 handling the image reveal inside the post. Everything lives in Redis: cases, votes, player profiles, leaderboard, all of it. A scheduled job runs once a day, tallies the votes, decides the verdict, updates everyone's streak and points, and quietly opens tomorrow's case in the same post. We didn't want a new post appearing every day — the whole point was that you come back to the same place. Visually we went all-in on a "public notice" look — dark olive, cream parchment, Playfair Display, a wax seal we built ourselves in SVG. The reveal itself got more attention than we expected going in: feathered edges instead of a hard circle, a bit of vignette, some grain, so it feels more like evidence being uncovered than a progress bar filling up.
Challenges we ran into
Phaser 4 fought us more than expected, mostly because it's new enough that half the Stack Overflow answers don't apply anymore. setMask() just doesn't work under WebGL, so we had to dig into the internal filter-based masking system instead. addWipe wants a number, not a boolean, which cost us more time than it should have. Devvit's Redis client also doesn't have Set commands, so a chunk of our voter-tracking had to get rebuilt around hashes. The nastiest bug was a stale closure caused by React StrictMode double-mounting things while Phaser was still booting asynchronously — the fix ended up being "always read props from a ref at the moment you actually need them, never trust what you closed over earlier." We also had a vignette that looked like a moon crater instead of a smooth fade, because stacking a bunch of semi-transparent circles compounds their opacity instead of blending — swapping that for one canvas gradient fixed it in five minutes once we figured out what was actually happening. And there was a genuinely annoying bug where the verdict screen would reappear after every refresh — turned out the "mark this as seen" request could get cancelled if you closed the tab right after clicking continue, so we moved that call to fire the moment the screen appears instead of waiting for the click.
Accomplishments that we're proud of
Honestly, the reveal mechanic actually working the way we imagined it — where your vote is visibly doing something to the image — was a bigger win than we expected going in. It's a small mechanic but it makes voting feel like it matters in the moment, not just for points later. We're also happy with how the look came together; it went from "generic card with buttons" to something that actually reads as an official notice. And keeping the whole loop inside one recurring post instead of spawning a new thread daily kept things feeling like a ritual instead of a series of one-offs.
What we learned
Treating Redis as the only source of truth for everything forced us into flatter, simpler data shapes than we'd normally reach for — no easy queries, so you plan ahead instead of patching later. We also learned way more than we wanted to about Phaser's async scene lifecycle fighting React StrictMode. And honestly, the biggest lesson was how much small motion details change the feel of a game — easing instead of a snap, a soft mask edge instead of a hard one, a bit of grain. None of that changes what the game does, but it changes whether it feels finished.
What's next for Juro
More cases, first and foremost — 24 hand-written ones get you through a couple weeks, and we'd love that bank to grow from real community submissions instead of just us writing them at midnight. We also want more tension before people vote — showing how split recent cases have been, a countdown to when the verdict drops, that kind of thing, so it starts to feel like appointment viewing rather than something you stumble into. Further out, we like the idea of letting individual subreddits run their own themed docket instead of one global case for all of Reddit.
Built With
- devvit
- react
- typescript

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