Local interaction state
Client state : viewer-local UI bucket
Both getLayout and renderOverlay are viewer-local. renderOverlay's third argument is the global client-state bucket (read-only):
type GlobalClientStateReadView<G extends Record<string, unknown> = {}> = Readonly<G>;
Pieces and spaces read the same bucket through clientState.global (4th positional arg in render()); onMouseEnter / onMouseLeave write through a writable view of the same bucket. Use it for cross-item viewer state ("currently dragging piece X", "hovered space kind Y"). Never on the wire.