Inspiration

Nathan, James, and Stephen have been best friends for years, and just like the three brothers in We Bare Bears, we do everything together. The show has always been our favourite and it captures what our friendship feels like: three bears who stick together through every adventure, no matter how chaotic. When one of our teammates, Stephen, couldn't make it this weekend, so we decided to build something in his honour. Bearlympics is our way of making sure we always have a game we can play together, anywhere and on the go. All we need is screen and our phones and let the games begin.

What it does

Phone Party is a party-game console that runs entirely in the browser. A laptop or TV hosts the room and renders the 3D scene; everyone else scans a QR code and their phone becomes a motion controller. No app install, no pairing.

Stack: Next.js 16 + React 19 on Vercel, three.js / react-three-fiber for the scenes, Socket.IO on Railway for the realtime room, TypeScript throughout.

Phones as Wii-style remotes

  • DeviceOrientation for aim, DeviceMotion for gestures — swing, shake, jab
  • Gestures are detected by projecting acceleration onto the gravity vector rather than a fixed axis, so a swing reads the same whether the phone is held upright, angled or flat — and it survives Safari and Chrome reporting opposite signs for the accelerometer

One generic protocol, six games The core design decision: the server never learns a single game's rules. It relays one generic gameAction event to everyone in the room, including the sender, and every client — TV and phones alike — runs the same reducer over the same action stream.

  • Turn order, scores and timers are derived on each device, not broadcast
  • Anything random is seeded from values everyone already shares (round number, player id, arrow number), so the archery crosswind and the entire 30-second salmon run are identical everywhere without streaming a single position over the wire
  • Anything timed resolves against the server's timestamp, since phones and the TV don't share a wall clock

The payoff: a new game touches one folder and one line of a catalog file — no server changes, and several people can build games in parallel without stepping on each other. We shipped five: Apples, Shake, Archery, Salmon and Beer pong.

The bug we're weirdly proud of Players kept reporting that the beer pong ball went in but the cup stayed. The sink test sampled once per frame, but the cup mouth is only 7cm across and a 5 m/s throw covers 8cm per frame — the ball was tunnelling straight through the opening between samples. Measured against a fine-grained reference sim, 17% of genuine makes weren't counting. Substepping the simulation took that to 2%.

Challenges we ran into

The gyro was by far the hardest part. Phone motion APIs are gimmicky and inconsistent:

  • Safari and Chrome report opposite signs for the accelerometer
  • The orientation angles go unstable near vertical, which is exactly how you hold a phone when aiming at a TV
  • Integrated position drifts within seconds
  • Worst of all, a wrong axis never crashes. It just makes the game feel subtly backwards, so we kept shipping "working" code that was inverted

So we stopped guessing and built a sandbox mode. It records raw orientation and accelerometer frames straight off the phone, tags each clip with the gesture it is meant to be (bear hit, beer pong flick, bear swipe), and stores them so we could replay and compare.

Once we had real traces, we could see what a swing actually looks like next to a shake, and derive the thresholds instead of inventing them:

  • Peak acceloration
  • Where in the motion the action lands
  • The gate that separates a real gesture from a wobble

Those numbers feed straight back into each game. Defining a new movement became a matter of recording it a few times, rather than tweaking magic numbers until it felt right.

What we learned / Accomplishments we're proud of

The gyro teaches you to stop trusting your intuition.

  • Reason with quaternions, not raw alpha/beta/gamma. Euler angles go unstable at exactly the angle people hold a phone at
  • Never assume an axis sign. We derived ours from the math, then checked it against two known positions (upright should aim at the TV, flat should aim at the floor)
  • Calibrate relative to a pose the player picks. Absolute orientation is meaningless when everyone is sitting somewhere different
  • Motion bugs fail silently. Nothing crashes, the game just feels wrong, so we learned to test the math directly instead of squinting at the screen

Two people can ship a lot if the architecture keeps them apart.

  • Because the server never learns a game's rules, each game lives in its own folder and touches exactly one shared line
  • We built two games at once and merged without conflicts
  • The one time we broke each other, it was in shared motion code, and it silently inverted a game that had already shipped

Built With

Share this project:

Updates

Submission history