← Back to blog
Sep 12, 20265 min readthree.jswebcodecspwaproductvolleyball

Tempo — teaching volleyball in 3D, straight from the browser

Turning a coach's whiteboard scribble into an animated 3D play and a shareable video, without installing anything. Notes on Three.js authoring, in-browser video export, and designing for the gym.

I play volleyball. I have also spent enough time in gyms to know exactly where tactics go to die: the whiteboard.

A coach draws a serve-receive rotation with arrows. It makes sense for about forty seconds. Then players rotate, the drill starts, and the drawing — with its overlapping arrows and ambiguous labels — is forgotten. The gap between the idea and the execution is a communication problem, and hand-drawn diagrams are a terrible medium for motion.

Tempo is my attempt to close that gap. It is a browser-based 3D play designer: author a play on an accurate court, animate it, record it as video, and present it from a phone at the net.

Nothing to install. That constraint shaped every technical decision that followed.

Why the browser

Coaches do not administer software. They use a phone, a tablet, or a laptop that already works, often on gym Wi-Fi that barely works. Asking them to install a game engine build — or to trust a download from an unknown vendor — is the end of the funnel.

A browser app means:

  • A link is the install. Send a URL in the team chat and everyone has it.
  • The same code runs on a phone on the sideline and a laptop at home.
  • A PWA makes it feel native without an app store.

That ruled out a native engine and made Three.js/React Three Fiber the obvious foundation. The court is a real 18 × 9 m floor with a 2.43 m net, 3 m attack lines, antennas, and rotation zones 1–6. Accuracy matters: if the court is wrong, coaches notice immediately and stop trusting the tool.

Authoring: fast path first, control when you want it

Coaches have two modes of thinking, and the tool should too.

Quick play is for the idea that arrives between drills. You start already on the court: drag the receive formation, tap three ball targets, pick who receives, sets, and spikes, choose the block count, mark the spike, and watch natural curved runs animate. Save a custom formation at any time. Undo/redo works everywhere with Ctrl+Z.

The full editor is for the details. A keyframe timeline records player positions and poses. Ball trajectories are authored as Catmull-Rom bezier paths per action — serve, pass, set, attack, block, dig — so the ball moves like a ball without a physics engine. You can scrub, retime, slow down, and step frame by frame.

There is a deliberate choice in there: authored motion, not simulation. A physics engine gives you unpredictability and cost. A coach wants a diagram that moves the way they meant. Deterministic bezier paths look intentional, run at a stable frame rate on a phone, and always produce the same video. That is what teaching needs.

Players: procedural fallback plus real models

Out of the box, players are procedural mannequins with poses for ready, pass, set, serve, approach, jump, spike, block, dive, and celebrate. They are clear, fast, and always available.

If you want realism, you can load any Mixamo/skinned .glb, map its animation clips to those twelve poses, auto-scale it, and strip root motion. The fallback is not a degraded mode — it is what keeps the tool functional when someone inevitably brings a model that does not map cleanly.

Video export is the killer feature

A play the team can watch is worth ten diagrams. But exporting video in the browser used to mean either a server render farm or a fragile screen capture.

Tempo does both capture paths client-side:

  • MediaRecorder captures the canvas for instant sharing — good enough for a quick clip.
  • WebCodecs (H.264/VP9) with mp4-muxer renders frame-perfect video through an in-browser background queue. Because the render loop is decoupled from real time, a 30-second play exports as a clean 30-second MP4 regardless of device performance.

Presets are tuned for where the video will live: WhatsApp, Instagram, Presentation, Slow-mo, GIF. An ffmpeg.wasm fallback covers browsers without WebCodecs, and GLB export exists for anyone who wants the 3D scene itself.

The presentation mode is the other half: a full-screen /present/:playId route with a chapter bar, drill mode that hides and reveals ball paths phase by phase, public read-only links, and QR codes. The coach casts or hands over a phone, taps through phases, and the whole team sees the same play, exactly as drawn.

A scorecard, because the game has state

Tempo grew a match scorecard because coaches asked for one place to run practice. It handles rally scoring, sets, rotation tracking, and substitutions, with a configurable timeout countdown (5–600 s), a match clock, and a general timer.

The rules of volleyball are mostly about state, and the state is fussy: teams switch sides at the end of every set and at 8 points in the deciding set. Positions map to zones 4–3–2 and 5–6–1 based on the rotation. Substitutions are player-for-player, and per-player stats — service points, rallies on court, subs in, best serving run — must survive the swap. Getting this right meant modeling the game as a state machine instead of bolting counters onto the UI.

Match reports export as print/PDF or JSON, and history can be restored.

The rules reference

The last piece is deliberately low-tech: 45 seeded rules across scoring, rotations, faults, contact, net, serve, and libero, each with a court diagram for visual learners, plus the official FIVB Volleyball Rules 2025–2028 bundled as a PDF.

Rules arguments at practice are real, and having the diagram and the official document in the same place ends them faster. Not every useful feature is a novel one.

Engineering lessons

  • Constrain the install. "Runs in a browser" eliminated an entire class of support problems and made sharing the product a link.
  • Author motion, don't simulate it. Determinism made the editor, the video export, and the demos all simpler.
  • Frame-perfect export is a UX feature. If the exported video stutters, coaches blame the tool, not the device.
  • Design for the gym. Portrait phones, one hand, bad Wi-Fi, bright light. The responsive dashboard and PWA install matter more than desktop polish.
  • PGlite is a gift. Running the same PostgreSQL dialect embedded means git clone && pnpm dev works with no Docker, while production runs real PostgreSQL 16.

Tempo is MIT-licensed and under active development. If you coach, play, or just want to see a 3D authoring tool that exports its own video, take a look — and tell me which play I should author next.

github.com/Pranesh-Selvaraj/Tempo