DocsLayout & seats

Layout

A zone says what a region means and how its contents behave — but not where it is. That lives in layout. The layout block holds two things: the seats around the table, and a placement for every zone — its position and size on the felt.

Layout is deliberately kept separate from the zone definitions. Zones carry meaning; layout carries geometry. Because they’re separate, your hand-tuned positions survive regeneration — re-running the pipeline can rewrite a zone’s role or contents without throwing away where you placed it.

Every coordinate here is in abstract table units, with the table origin at its centre. Only the ratios between things matter — pixel scaling happens at render time.

The table

Every game is laid out on the same table. There is no per-game size or shape to pick: the felt fills the whole window, and the default view frames a fixed 1500 × 1000 area centred on the origin. Keep anything players need at a glance — hands, decks, the board — inside that rectangle. You can place things beyond it (the felt keeps going, and players can zoom out to reach them), but nothing will point them there.

The table also takes an optional surfaceAsset — a felt or board image painted across it — and an optional viewMode controlling how the scene orients for each player: fixed (default when omitted) locks the board upright for all players; seated rotates the scene so the viewer's seat faces the near edge — use it for directional board games where territory or orientation matters.

The felt colour

The table is taybl green unless you say otherwise. Select the Table and pick a Felt colour — one of the presets (walnut, midnight, burgundy, slate, charcoal) or any colour at all from the picker beside them. It is stored as feltColor on the table, and Reset puts the classic green back.

The colour covers the whole surface, not just the framed 1500 × 1000 area — so it is also what fills the margin around surfaceAsset art. Pairing a board image with a felt drawn from it is the usual way to make the table look like one continuous surface rather than a picture sitting on green.

Text drawn on the felt — zone labels, board coordinates, the tag showing who is holding a card — flips to dark ink by itself when you choose a pale colour, so nothing becomes unreadable. The colour is purely visual: it changes nothing about how any piece behaves.

Open play — letting the felt itself hold things

Open play (openPlay on the table) is on for every new game, and it makes the felt a surface like any other: a component released outside every zone stays exactly where you dropped it. It is the digital version of just putting a piece down on the table — useful for a staging area, a pile of "cards I am thinking about", or any game whose rules assume there is table space to spread out on.

Untick it and the bare felt stops being a place. Drag a card to the empty space between the board and the discard pile, let go, and it snaps straight back where it came from — only zones accept a drop. Worth doing for a game that should feel strict about where things belong; most games want it left on.

The felt reaches well past the framed 1500 × 1000 area. Anywhere a player can zoom out to, they can drop on — so a game that needs room to sprawl has it, and nobody hits an invisible wall part-way out. The framed rectangle is still what the default view shows, so keep anything players need at a glance inside it and treat the space beyond as somewhere they choose to go.

Open play changes only what happens on bare felt. Every zone keeps all of its own behaviour — capacity, what it accepts, snapping, arrangement, which way cards land, who can see them — because a drop over a zone still lands in that zone. Nothing about your existing layout changes.

Switching it back off is safe: anything already resting on the felt stays put and can still be picked up and moved into a zone. Only new drops onto bare felt stop being accepted.

What a placement holds

Each zone has exactly one entry in layout.zones, keyed by zone id:

FieldTypeMeaning
spacetable | seatLocaltable = absolute table coordinates; seatLocal = relative to a seat, with one copy instantiated per seat, rotated to that seat
x / ynumber (table units)Position of the zone box (origin = table centre)
w / hnumber (table units)Zone box width and height (both positive)
rotationnumber .optional()Box rotation in degrees, clockwise about its centre. Does not swap w/h — those stay the box’s own axes — and the contents are counter-rotated back upright. To simply turn a zone on its side, use Turn 90° instead (see below)
layernumber .optional()Draw order when zones overlap
fitContentsboolean .optional()Scale contents to fill the box. Default lets the renderer pick: card zones fit, piece/dice/token trays don’t. Set true for a single-component zone you want to resize by resizing the box
lockedboolean .optional()Designer-only: the editor ignores the box’s own click/drag (handy for a big background board) — contents stay interactive; ignored at runtime
traySpanCols / traySpanRowsint ≥1 .optional()Tray zones only — when a zone lives in the bottom hand tray or the supply, its zones render as a grid of uniform square tiles (up to 4 per line). These let one zone span multiple columns / rows of that tile grid (a colspan / rowspan). The cap is asymmetric: the cross axis stays ≤4 per line — columns for the supply, rows for the hand tray — while the main axis is unbounded, so a supply tile can be many rows tall and a hand-of-cards tile many columns wide to fill and scroll the tray. Absent ⇒ an automatic tile box sized from what the zone holds — a fanned hand fills the tray’s height and spreads a few cards wide, a deck fills the height at one card’s width, a pile of pieces takes half. Set them per axis: pinning Columns leaves Rows automatic. Ignored for table zones, and the ≤4 cap is applied at render to whichever axis is that tray’s cross axis
bySeatrecord .optional()seatLocal zones only: per-seat geometry overrides keyed by seat index. A seat with no entry uses the base geometry, so the zone stays symmetric until you reposition one seat

How to edit in the Studio

Open your game → Layout tab. The table is drawn to scale; drag a zone to move it, drag its handles to resize, and use the Zone inspector to set rotation, layer, fitContents, and lock. The inspector also has a Turn 90° button beside Bring to front / Send to back: it swaps the zone’s Width and Height and leaves rotation at 0, which is what “make this zone horizontal” usually means. Prefer it to typing 90 into Rotation — once a zone is rotated, its Width and Height are the box’s own axes rather than the width and height you see, so the two controls stop meaning the same thing (the corner-drag follows the rotated box, the number fields do not). Switching a zone to seatLocal space mirrors it to every seat at once; nudging one seat’s copy writes a bySeat override for just that seat. The Table inspector sets the surface shape, size, and image. For a full tour of the canvas, panels, and gestures, see the Layout Editor.

Arranging several zones

The editor snaps, aligns, and matches zones for you — marquee-select a group, then align, distribute, or Match their sizes. See arranging zones on the felt for the full gesture set.

Already have a set of zones that drifted out of line — a tableau of slots, a row of supply piles? Ask Pip to arrange or even out them: it reads where each zone currently sits, works out the tidy positions (lining up rows and columns, evening the gaps), and proposes the moves (positions only — sizes stay as you set them), which you review and Save like any edit.

Pip can also add pieces from the component library“add four red meeples to the supply”, “give me a d20” — so a missing piece takes one sentence rather than a trip to the Components tab. Ready-drawn catalogue objects need no uploaded art, which is why Pip can author them at all: there is no image id for it to guess at. Naming the zone in the same breath places them; leaving it out still creates the piece, ready for you to place.

Deleting a zone or component

Zones and components are referenced all over a game — a setup placement, a deck’s member list, a table-menu action, a setup step’s destination. When you delete one, Save clears the pointers that were left behind and tells you what it cleaned up, so a delete never leaves you unable to save. If a save is genuinely rejected, the message names the place to fix it — "Setup step 2", "Zone “Player Hand”" — rather than a raw field path.

Sign in to ask Pip about building games.
Sign in