📡 Cozy Parrot OpCodes
Wire contract (10 Hz). Index · Architecture · Runbook
Client → Server
| Op | # | Payload | Notes |
|---|
Move | 1 | { x, z } | clamp ±ARENA; ignored in result |
Grab | 2 | {} | play only; nearest token ≤INTERACT_RADIUS; noop if holding |
Throw | 3 | {} | play only; must hold + ≤INTERACT_RADIUS of hopper |
Server → Client
| Op | # | Payload |
|---|
GameUpdate | 1 | { state: CozyParrotMatchSnapshot } |
Snapshot: { players, tokens, targetPrompt, phase, timer, winnerId }
| Field | Shape |
|---|
players[id] | { id, x, z, score, holdingToken, heldWord } |
tokens[id] | { id, word, x, z } |
targetPrompt | { text, blanks[], filled[] } |
phase | lobby | countdown | play | result |
timer | remaining ticks |
winnerId | top score id | null |
Scoring
| Event | Δ | Rule |
|---|
| Correct word @ hopper | +1 | heldWord === blanks[filled.length] |
| Prompt complete | +3 | all blanks filled → new prompt |
| Wrong word @ hopper | -1 | floor 0 |
[IDEA] @ hopper | fill | wildcard writes expected blank (+1 / +3 as above) |
Phase machine (tickRate=10)
| Phase | Ticks | ≈sec | Transition |
|---|
lobby | — | — | ≥2 players → countdown |
countdown | 30 | 3s | timer≤0 → play |
play | 600 | 60s | timer≤0 → result (tokens every 20 ticks) |
result | 50 | 5s | → lobby (re-countdown if ≥2) |
<2 players during countdown/play → lobby.
Interaction constants
| Const | Value |
|---|
COZY_PARROT_ARENA | 10 |
COZY_PARROT_INTERACT_RADIUS | 1.5 |
COZY_PARROT_HOPPER | { x: 0, z: 0 } |
COZY_PARROT_IDEA_TOKEN | [IDEA] |
Source anchors
| Role | Path |
|---|
| Shared SSOT | shared/src/CozyParrot/index.ts |
| Match handler | matchHandlers/cozyParrot/index.ts |
| Client manager | CozyParrotMatchManager.ts |