Have more questions? Join our Discord

Hidden information

The platform hides what a seat may not see. The game logic never filters a view itself: it puts each secret where the visibility rule hides it.

Who sees what

Part Seen by
a piece's public_kind and public_state everyone
a piece's private_kind and private_state the piece's owner; if it has none, its space's owner; if neither, nobody
a space's public_state everyone
a space's private_state the space's owner
a player's public_state everyone
a player's private_state that player
meta_data everyone

A spectator sees only public parts. A secret nobody may see yet, such as the order of a deck, is a private part with no owner.

To show a card to its holder only, put it face down in a space the holder owns:

table.add_space(
    Space::new(format!("hand-{player}"), "hand")
        .collection()
        .owned_by(player)
        .with_pieces(vec![Piece::new("back").hiding("queen-of-hearts")]),
);

To turn a card face up for everyone, set its public kind: table.set_public_kind(space_id, index, &face).

Collections hide order

A space is Ordered by default: every viewer sees every piece in its true position, with the private parts they may not see removed.

A space made with .collection() lists, for each viewer, the pieces that viewer can see first, in order, and then the hidden pieces grouped by their public part. A viewer cannot follow a hidden piece through a collection, so a hand of face-down cards gives nothing away when its holder sorts or plays it.

A click on a hidden piece

When a seat clicks a hidden piece in a collection, it cannot tell that piece from the others of the same public part. Boardweaver picks one piece of that group, which the seat cannot predict. The game logic receives the picked piece's index, never the clicked position.

Reveals

A step is a reveal when its result depends on something the seat cannot see: drawing the top card of a deck, taking a card from another hand, looking at a hidden tile. Mark its offer:

Offer::new(
    Action::PieceClick { space_id: hand(opponent), index },
    Intent::Confirm,
    format!("Take a card from player {opponent}"),
)
.revealing()

A reveal ends the seat's decision (Offers, intents and decisions), and the board shows its result only after Boardweaver applies it. An unmarked reveal can show the player a result that then changes.

The game logic also runs on a view

offers and apply_action also receive the seat's own view, where every private part the seat may not see is missing. Write them so they work on a view:

  • Read private parts with Option handling, not expect. On another seat's hidden piece, private_kind is None.
  • Read private maps with types whose fields all have defaults. A hidden map reads as {}.
  • Mark every step whose result needs a missing part as a reveal. Boardweaver then applies it with every part present.

Log lines and labels

  • A log line is shown to every viewer, so its text, link keys, kind and player name only public facts (Changing the state).
  • An offer's label goes only to the seat that receives the offer, so it may name that seat's own hidden cards.