A version-isolated multiplayer platform for phone remotes, handheld play, and shared browser/TV displays. Each game ships as an independent cartridge; the platform owns discovery, rooms, pairing, realtime transport, device shells, and immutable release verification.
The source catalog contains six cartridges: Turbo Circuit 0.12.5, Flight Trainer 0.4.3, Sky Strike 0.4.3, the downhill-bike racer Ridge Rush 0.5.11, the 1v1 fighter Clash Arena 0.4.3, and Ibu-Ibu Telur Gulung 0.1.1. Source versions do not imply that production or an already-open room has upgraded. Historical releases for removed games stay byte-immutable but are retired from new-room selection.
Live app · Agent onboarding · Architecture · Game SDK · Submit a game · Deployment · Security
The home interface uses a one-viewport console layout with Play/Rooms tabs, a real game viewport
and a horizontal cartridge selector. On phones, Set up room opens the focused setup task. Use QR sign-in on a new screen and Pair device on an already-authenticated one.
Approval is explicit, short-lived, single-use and bound to the requesting browser. See
device sign-in. The signed-in phone can scan with its camera, read a QR
photo locally, or enter a code with ordinary/smart dashes and spaces. For older televisions, open /tv.html before assuming
the built-in browser can run the current 3D engine. The lobby baseline and game-rendering
requirements are separate; missing WebGL 2 cannot be fixed with a JavaScript polyfill.
Playable visuals are not concept-art placeholders. 3D player characters/vehicles use versioned runtime model assets; 2D playable entities use spritesheet atlases with explicit animation metadata. Clash Arena now uses generated GLB fighter assets as the first enforced implementation. See the playable-asset contract and run pnpm assets:check.
The default Play Together controller is deliberately Tier 0: one left stick + ABXY + Menu/Start. L1/L2/R1/R2 are not recommended by default and only belong in a game when playtesting proves the extra inputs are genuinely necessary. Ridge Rush 0.5.11 and Clash Arena 0.4.3 both ship with Tier 0 mobile controls; Clash Arena uses them for character select as well as match play. Menu and How To are platform actions placed beside Start in landscape and above Start in portrait; hold controls suppress text selection/callouts. Advanced shoulders remain hidden by default. Touch, keyboard and standard-mapped physical gamepads share input ownership and focus-loss cleanup. Read the gameplay development guide for the controller-tier contract and per-game mappings.
Library filters now keep previews and room setup on the same game, including empty results. Account controls support keyboard focus and clear selection states. Crashed room workers can recover on reconnect, new rooms remain visible in busy directories, and cache-storage failures no longer discard successful network responses. See release verification.
Turbo Circuit 0.12.3 fixes finish-line progression, primary-control drift/recovery, boost-pad activation and stale track pickups. The shared landscape console gives every game bounded thumb rails and a separate system-action row; Turbo HUD/setup now use the actual game-container dimensions. Static scenery batching, a pixel budget and snapshot-owned scene updates reduce rendering work. See the review and verification criteria.
The library adds device-local favorites, title search, party-size filtering and a random pick that respects those filters. Active play requests a screen wake lock where supported. How To derives keyboard aliases directly from cartridge control metadata.
Turbo Circuit starts cruise on a gas tap; brake cancels it and rescue/reset clears it. Flight Trainer adds checkpoint and landing coaching, Sky Strike shows targeted incoming-missile distance, Ridge Rush shows next-checkpoint/finish distance, and Clash Arena exposes active juggle, guard, stun and Surge readiness. See release verification for actual delivery status and limits.
The portal supports native sharing and copy-link recovery, same-site pasted invitations, game recommendation links and missing-cover fallback. Covers and short motion previews are captured from real gameplay with per-game scenarios. Player counts and supported modes come from catalog metadata. See portal quality review.
All five games have refreshed model details and world dressing. Flight Trainer shares course geometry between visuals and scoring; Ridge Rush preserves a level camera horizon; Clash Arena uses corrected GLB colors and an unobstructed arena. Removed aircraft, projectiles and fighters release their owned GPU resources.
- A host creates a room from the current active Convex catalog.
- Remote mode shows a pre-game lobby and QR invite. Phones scan the exact room URL and join as controllers.
- Handheld mode mounts the pinned game display and controls on the same device.
- The host starts the room. Only then are realtime tickets, game workers, and game frames created.
- Realtime presence automatically keeps communal games shared or composes per-player games into up to four display viewports.
- Existing rooms stay pinned to their exact immutable game version and manifest digest.
retiredstops new rooms but preserves already-pinned rooms; emergencyblockedimmediately revokes live exact-release sessions and prevents new tickets/reconnects without rewriting bytes.
The platform never decides how a concrete game works. A game never owns QR pairing, split-screen orchestration, Convex auth, or platform navigation.
The live engine has no hardcoded game list or mechanic map. Convex is the durable playable release/presentation catalog; host release policy distinguishes active/retired/blocked versions, while Redis only mirrors blocked identities transiently for immediate cross-instance revocation. Each immutable manifest owns controller/modules/assets/runtime dependencies, and the frame is a generic verified interpreter. game-registry.json exists for tooling/previews only. Large shared browser libraries use versioned engine ABI surfaces such as three@0.185.1+pt3, so 3D cartridges stay small without weakening SHA verification.
apps/web browser shell + feature slices + sandboxed game frame
apps/realtime transient authoritative WebSocket/worker runtime
convex durable control plane and public endpoint facades
packages/contracts wire/manifest/ticket contracts
packages/game-sdk stable game runtime boundary
packages/browser-runtime verified browser asset/realtime client runtime
games/<id> one isolated game vertical slice
scripts release, registry, docs, security and architecture gates
e2e user-flow scenario slices + shared support
releases/game-cdn immutable generated cartridge releases
Dependency direction is enforced by pnpm architecture:check. Maintained implementation files have a 200-line budget; split by cohesive ownership instead of adding generic dumping-ground modules.
apps/web/src/app composes providers/routes. User capabilities live under features/<slice>, with page composition, model/hooks, components, and styles colocated. Cross-feature primitives belong in shared; sandbox/game-frame concerns belong in frame. Feature slices must not import sibling feature internals.
Public Convex paths stay stable in files such as convex/rooms.ts and convex/templates.ts; business logic lives in private domain modules. Realtime room state is split into worker lifecycle, validated client protocol routing, client registry/backpressure, distributed coordination, release control, and bounded observability. Public packages export small domain modules through explicit facades.
Each games/<id> folder owns its authoritative server, display renderer, declared controls, runtime assets, and tests. Rich games split internally by real concerns such as server/model, server/combat, display/scene, display/hud, or display/vehicleRenderer rather than moving game logic into the platform.
| Concern | Source of truth |
|---|---|
| game identity/controller/current presentation | games/<id>/game.config.json |
| immutable release history + host release policy | releases/game-cdn/catalog.json → Convex |
| wire + manifest schemas | packages/contracts |
| runtime game interfaces | packages/game-sdk |
| durable room/auth/template data | Convex |
| generated portal discovery | apps/web/public/game-registry.json |
| immutable executable release | releases/game-cdn/games/<id>/<version>/manifest.json + SHA-256 |
| app visual tokens | apps/web/src/styles/tokens.css |
| game-frame visual tokens | apps/web/src/frame/styles/tokens.css |
| game submission agent prompt | docs/game-submission-prompt.txt |
| verification commands | root package.json |
Do not add compatibility shims, duplicate APIs, placeholder modules, copied prompt text, game-specific host heuristics, or second registries.
Requirements: Node.js 22+, pnpm 10+, Docker Compose v2, and Chromium/Chrome for E2E.
git clone https://github.com/rahmanef63/play-together.git
cd play-together
pnpm install
pnpm stack:bootstrapOpen http://localhost:4173. stack:bootstrap creates ignored local secrets, starts self-hosted Convex, publishes discovered game releases, deploys Convex functions, registers manifests, and starts web/realtime services.
Stop without deleting durable local Convex data:
pnpm stack:downDo not use docker compose down -v unless local data should be destroyed intentionally.
Read docs/submitting-games.md and docs/game-sdk.md. The repository exposes bounded MCP/MSO operations (game.list, game.get, game.create, game.update, game.validate, game.publish, game.release_status, game.registry, game.prompt). Published cartridge bytes are immutable: any byte-changing update requires a greater semantic version.
pnpm game:publish:one <game-id>
pnpm game:publish:convex:one <game-id>Production registration is performed only by verified main CI. Project tools create/validate local releases; they do not bypass deployment gates.
pnpm verify # lint + architecture + types + tests + builds + smoke + security audit
pnpm verify:stack # realtime smoke + browser multiplayer E2E
pnpm test:e2e # 10 end-to-end user scenarios split by capability
pnpm game:previews # recapture game preview thumbnails from a running stackE2E covers QR join, Start-gated lifecycle, public/private/password admission, remote/handheld surfaces, the shared SVG console across gamepad/racing/flight/arcade/touch layouts, independent cartridges, automatic shared/split display, room CRUD, PWA/ops layout, authoritative realtime, concurrent final-slot admission, half-open WebSocket recovery, reconnect state continuity, and WebGL frame recovery.
- Player app + immutable game CDN: Dokploy VPS,
https://game.rahmanef.com - Realtime: same-origin
/api/realtime, coordinated across instances through Redis with hydrated live release revocation and fixed-cardinality instance telemetry - Durable control plane/auth: Convex Cloud
- Private commercial template source: Vercel Private Blob + Convex entitlement
See docs/deployment.md before shipping and docs/security.md / SECURITY.md for trust boundaries.
Start with AGENTS.md, then docs/agent-onboarding.md. The onboarding guide maps common tasks to their owning slice, lists files that must not become SSOT, and defines the smallest valid verification gate before merge.
Contributions follow CONTRIBUTING.md and the Code of Conduct. Security reports follow SECURITY.md, not public issues.
MIT © 2026 rahmanef63
