Playertwo Live Demo
This is a live Pong game running directly in the documentation, demonstrating the playertwo state-first architecture.
Controls: W/S = Left paddle | Arrow Up/Down = Right paddle
How This Works
This demo shows playertwo’s core pattern — even without a network transport:
- State is a plain object: paddles (position + score) and ball (position + velocity)
- Actions process input:
moveactions update paddle positions - Physics runs on the “host”: ball movement, collisions, scoring
- Rendering reads state and draws — no game logic in the renderer
In a real multiplayer setup, you’d replace the shared state with a LocalTransport (for testing) or TrysteroTransport (for P2P WebRTC). The game code stays identical.
// Same game, now multiplayer
import { defineGame, GameRuntime } from '@playertwo/core';
import { TrysteroTransport } from '@playertwo/transport-trystero';
const game = defineGame({
setup: ({ playerIds }) => ({
paddles: Object.fromEntries(
playerIds.map((id, i) => [id, { y: 200, score: 0, side: i === 0 ? 'left' : 'right' }])
),
ball: { x: 300, y: 200, vx: 4, vy: 3 },
}),
actions: {
move: {
apply(state, context, input) {
state.paddles[context.targetId].y += input.dy;
},
},
},
});
const transport = new TrysteroTransport({ roomId: 'pong-room', appId: 'ptero-demo' });
const runtime = new GameRuntime(game, transport, { isHost: transport.isHost() });Embedding in Ptero Docs
Ptero uses MDsveX, so you can embed any HTML via iframes or Svelte components directly in documentation pages. For playertwo demos, the pattern is:
- Build a standalone game HTML page (canvas or Phaser)
- Place it in
static/demos/ - Embed with
<iframe src="/demos/your-game.html" />
For the full multiplayer experience with dual-view testing, use the @playertwo/ide component with the iframe-bridge transport.