Inspiration
Most mobile games reset when you leave. Reddit doesn't. A thread you commented on last night grows overnight — people replied, argued, built on what you left. We wanted a game with that exact property, so we started from one sentence and refused to let go of it:
The board remembers everyone.
The mechanical inspiration is curling and shuffleboard; the social inspiration is Reddit itself.
What it does
Knockit is asynchronous multiplayer curling for a subreddit. Every day there is one shared physics board, resetting at midnight Central. You get three stones — four if you're on a 3-day streak. Drag, release, and your stone slides with real physics, knocking other players' stones as it goes.
Scoring has two layers:
- Live score — the ring value of your stones right now (gold 3 · middle 2 · outer 1). Other players can take it from you.
- Banked score — accrues for every hour your stones survive in the rings, and it's permanent: a knockout stops the clock but never robs the bank. Camping is worthless; surviving is everything.
Then the hook: knock someone's stone out of the rings and they get a revenge shot with your name on it. Knock out your own attacker with that shot and the game crowns it — REVENGE SERVED — with a bonus banked on top.
The board is alive while you watch: presence shows who's on the rink, other players' shots replay on your screen as they happen, every stone is tappable ("u/whoever · 2 pts · surviving 3h 12m"), and at midnight the day settles — champions posted to the subreddit, a fresh board spawned, seven layouts rotating through the week.
How we built it
Fun first, backend second. Milestone 1 was a deliberately throwaway, client-only Phaser prototype with one job: prove that flicking a stone into a cluster feels satisfying. It did — chain reactions sold it — so we kept the feel and inverted the architecture.
In the shipped game the client never simulates a shot. It sends only $(\theta, p)$ — launch angle and drag distance. The server clamps power into a velocity,
$$v = \min(p \cdot k,\; v_{max})$$
rebuilds the entire board from Redis, runs a headless Matter.js simulation, banks survival accrual, detects knockouts, grants revenge, persists, and returns the trajectory — the client just plays back frames. One source of truth; zero client-side cheating surface.
Concurrency without websockets: simultaneous shots serialize through a per-board Redis lock (15s TTL) with jittered client retry — players never see the collision. A daily scheduler settles the closing day idempotently, rolls scores into the all-time board, posts numbered results threads, and creates the next day's post automatically.
Stack: Devvit Web · Phaser 4 · Matter.js (headless server-side) · Hono · Redis.
Challenges we ran into
- Tunneling, and the fix that wasn't. Fast stones can pass through walls between physics steps. The "obvious" fix — raising Matter's
positionIterations— did nothing: our headless test harness showed stones tunneling at ~120 px/step whether iterations were 6 or 20. The real fix was substepping the simulation 4× plus a server-side speed cap 6× below the tunneling threshold. Measure the failure before trusting the folk remedy. - A lock on an undocumented return value. The Redis
SET NXtypes don't document what a failed acquire returns — and a distributed lock built on ambiguity is a corrupted-board bug waiting for launch day. We rebuilt on atomicINCRwith a self-healing TTL, so even a crashed lock-holder can't deadlock a board. - Shared mutable state vs. player rage. "Someone moved my stone" is the hook and the biggest design risk: if later players could erase your reward after you log off, charm becomes rage. Two-layer scoring is the answer — your time on the board can never be stolen.
- Platform constraints as design pressure. No websockets, no streaming, 30-second endpoint budget, no client persistence. Every constraint pushed the design somewhere cleaner.
Accomplishments that we're proud of
- The core loop verified numerically end-to-end: in testing, one player's shot moved another player's persisted stone 261 pixels — the game's emotional hook, reproduced in code.
- A full shot — lock, board rebuild, physics simulation, accrual banking, knockout detection, persistence — completes in ~21 ms against a 30-second budget.
- Three real users on three devices sharing one live board, leaderboard updating as they knocked each other around.
- We killed our own favorite assumption with data (the
positionIterationsnon-fix) before it shipped.
What we learned
Validate the fun with a disposable prototype before writing backend. Server-authoritative design doesn't just stop cheating — it dissolves the multiplayer consistency problem: when only the server's simulation counts, stale client views become a UX detail instead of a correctness bug. Test physics claims numerically and headlessly. And milestone discipline is a feature — one milestone at a time, each gated by a real phone test.
What's next for Knockit
- Parallel rinks — 16-player boards with sticky daily assignment, same layout everywhere: many tables, one game.
- Community boards — a grid editor with community voting; the day's board credited to its creator in the daily post.
- Champion flair — yesterday's #1 wears the crown in every comment they write.
The board remembers everyone.
Built With
- devvit
- hono
- matter-js
- node.js
- phaser.js
- redis
- typescript
- vite
- webaudio
Log in or sign up for Devpost to join the conversation.