Hidden information
The three state buckets
Where a value lives decides who can see it and whether it travels.
| Bucket | Scope | Visibility |
|---|---|---|
static |
Per class | Never on the wire. Constants: name, cost, ability text. Read via piece.def.static. |
publicState |
Per instance | Everyone. Tapped flags, counters, damage. |
privateState |
Per instance | Owner only. The server nulls it for every other viewer, so hidden information never leaves the server. |
class Card extends PieceDef<{ tapped: boolean }, { victoryPoints: number }> {
readonly kind = "card";
readonly width = 100;
readonly height = 140;
readonly orientations = [{ imageSrc: GameImage.CardFront }];
protected publicDefaults() {
return { tapped: false };
}
protected privateDefaults() {
return { victoryPoints: 0 };
}
}
new Card({ order: 1 }); // defaults
new Card({ order: 1, tapped: true }); // override public
new Card({ order: 1, privateState: { victoryPoints: 3 } }); // override private
order is required in every constructor call : pieces in a space sort ascending by it.
Framework fields
piece.publicState always carries these, and your PublicState generic must not shadow them:
type PieceDefBaseState = {
order: number;
currentOrientationIndex: number;
isSelected?: boolean;
spaceId?: string;
};
Reading privateState
piece.privateState is PrivateState | null : null means this viewer isn't the owner. Every read must handle null, in your hooks and in your client. That is the mechanism that keeps a hand hidden, so it is not optional.