Independent browser game

06 / 12

Tiny Volley

A playable browser volleyball game with local multiplayer, AI, mobile controls, and peer-to-peer online rooms.

Role
Independent Developer · Apr — May 2026
Problem
Online play had to preserve the same match state on two browsers without turning rendering or network timing into the source of truth.
Strategy
The game advances a pure deterministic simulation from synchronized input frames. Phaser renders the resulting state, while the networking layer handles room and peer lifecycle without changing game rules.
Outcome
Released a playable Cloudflare-hosted browser game with local, AI, mobile, and peer-to-peer online modes.

Live independent build · 2026

01

Problem definition

Why this problem had to be solved

Tiny Volley is a small browser volleyball game. Local play, AI, rendering, and online matches all use the same TypeScript match simulation.

What users and the system were facing

  • Game rules, physics, controls, rendering, and networking could drift if each mode owned a different version of match state.

  • Peer-to-peer play needed room lifecycle, signaling, disconnect, timeout, and reconnection feedback—not only a DataChannel connection.

  • Desktop keyboard, local two-player, mobile touch, and persisted controls had to share one readable setup experience.

Frontend ownership

As an independent build, I designed and implemented the game client, deterministic simulation, AI, responsive controls, WebRTC lockstep, and the Cloudflare Worker signaling service.

  • Pure TypeScript match simulation separated from Phaser rendering

  • Local two-player, single-player AI, and mobile touch controls

  • WebRTC DataChannel lockstep and room lifecycle

  • Cloudflare Workers, Durable Objects, localization, and automated tests

02

Solution strategy

A system strategy carried into production

The game advances a pure deterministic simulation from synchronized input frames. Phaser renders the resulting state, while the networking layer handles room and peer lifecycle without changing game rules.

System model

Both peers exchange input frames through WebRTC, advance the same deterministic simulation, and render the resulting match state independently.

Implementation decisions

  • Kept authoritative rules and physics in a deterministic simulation so local and remote peers could advance the same inputs through the same state.

  • Built room creation, shareable codes, signaling, heartbeat, timeout, disconnect, and explicit STUN-only connection failure states.

  • Added remappable persisted controls, multiple game modes, sound and effects settings, and ten interface languages.

  • Tested simulation, input, protocol, and room behavior independently from the Phaser renderer.

03

Outcome

What changed—and what I learned

  • Released a playable Cloudflare-hosted browser game with local, AI, mobile, and peer-to-peer online modes.

  • Passed 101 automated tests across 18 files, the production game build, and the Worker type check during the Jul 2026 portfolio audit.

  • Exposed the current STUN-only limitation honestly instead of implying that peer-to-peer rooms work across every network.

Learning

Realtime frontend reliability comes from making simulation, rendering, transport, and connection lifecycle separate systems with explicit contracts.

Today

I would lazy-load the Phaser game runtime after the setup route and add an optional TURN service for networks where direct peer connectivity fails.

Built with

  • TypeScript
  • Vite
  • Phaser
  • WebRTC
  • Cloudflare Workers
  • Durable Objects
  • Vitest

Public links

Work together

Need this level of frontend ownership?

Contact me