DocsComponents

Shapes, behaviors & value bindings

Beyond the kind-specific fields, every componentpiece, card, die, token — shares a set of optional rendering refinements. Each one defaults to today’s plain behaviour when absent, so you only add them when an object needs a non-rectangular outline, snap rotation, an attached marker, or a live number.

These are still table-as-scene fields: they change how an object is drawn and handled, not what is legal. In particular a value’s min / max / step are display hints — taybl never clamps the number.

How to edit in the Studio

Open your game → Layout tab and select the component. The Behaviors section exposes the Flippable, Rotatable, and Stackable toggles. The finer refinements — shape, footprint, rotationStep / orientations, attachable, and valueBinding — are produced by the generation pipeline into the GDL and don’t have a dedicated inspector control yet; adjust them by editing the generated definition.

Shape — the outline within the size box

A component’s shape is the outline drawn inside its size bounding box — it sets the hit-area, the colour fallback, and how tiles tessellate. It is a discriminated union on type. Absent → rect.

typeExtra fieldsWhat it draws
rectA rectangle (the default)
circleA circle with diameter min(w, h)
hexorientation: pointy or flatA hexagon, point-up or flat-top
polygonpoints: array of { x, y } (≥ 3)A free outline; each point is 0..1 of the size box (0,0 = top-left, 1,1 = bottom-right) — used for meeple silhouettes

Background colour — a surface behind transparent art

Card and component art is often a transparent PNG. By default nothing is painted behind it, so the transparent areas show the table felt. Set backgroundColor to a hex colour (e.g. #ffffff) and taybl paints that solid fill behind the art — it shows only through the transparent pixels, giving a clear card asset a proper white surface. An opaque asset simply covers it, so the fill never appears; absent → no fill (transparent art shows the table).

Edit it in the Layout tab: select a component and use the Appearance → Background colour picker (with a clear button to remove it). Select many components to set them all at once — the multi-select panel has the same control — or ask Pip to "give all my cards a white background".

FieldValuesDefaultWhat it does
backgroundColorhex colour string (#rrggbb).optional()Solid fill painted behind the art, visible only through transparent areas

Padding — breathing room inside the cell

By default a component fills its cell edge-to-edge, exactly like an uploaded image. Set padding to inset the art — it is a fraction (0..0.45) trimmed from each side, so 0.1 leaves a 10% margin all around and pulls the piece in. Use it to give a die, meeple, or token a little air in a large cell, or leave it at 0 for tiles that should tessellate. Board tiles laid on a tessellating lattice ignore padding and always touch.

Edit it in the Layout tab: select a component and drag the Padding slider — or ask Pip to "add some padding to the dice".

FieldValuesDefaultWhat it does
paddingnumber 0..0.45 (fraction inset per side).optional() (fills the cell)Breathing room around the art inside its cell

Footprint — multi-cell pieces

A footprint lets one component cover several grid cells (a domino, a polyomino, a 2×2 building). It is { cells: { col, row }[] } — integer offsets from the anchor cell, which is the cell a placement or move names. The anchor { col: 0, row: 0 } must be present; the covered cells are derived at render time, so no runtime state changes. Absent → the component occupies a single cell.

Behaviors — how a component can be handled

Every card, piece, and token is flippable and rotatable. The physical table lets you turn any bit over or spin it, so these are not opt-in: a component flipped to a back with no art shows a generic back (a neutral felt square with a ring, matching a card’s back), and a rotate with no snap config cycles freely. The behaviors object only narrows or annotates these affordances. flippable/rotatable are kept for legacy definitions but no longer gate anything, so the inspector no longer shows them as checkboxes; stackable is still an opt-in checkbox.

FieldValuesDefaultWhat it does
flippabletrue.optional()Legacy flag. Every card/piece/token is flippable regardless — this no longer gates flipping
rotatabletrue.optional()Legacy flag. Every card/piece/token is rotatable regardless — this no longer gates rotation
stackabletrue.optional()Copies can be stacked into a pile
rotationStepnumber > 0 (degrees).optional()The rotation snap increment (e.g. 90 → four orientations). Absent → free rotation. Ignored whenever orientations is present
orientationsarray of angles in degrees.optional()Explicit allowed angles (e.g. [0, 90, 180, 270]). When present this is the full set of legal angles and overrides rotationStep. Each entry is wrapped into [0, 360) and de-duplicated

States — multi-state components

A states array gives one component 2+ switchable states, each with its own art and properties — a tile that upgrades village → city → metropolis, a creature that transforms, a board with several printed sides. The runtime object remembers which state is active and a player flips between them with the switch state action; the renderer draws the active state’s face. The first state is the default. This is not the same as a card’s variants, which expand into separate cards — states keep one object whose face changes. Absent → a single-state component, exactly as before.

FieldValuesDefaultWhat it does
states[].idtext (snake_case)Unique state identifier within this component
states[].nametext.optional()Display name for the state
states[].faces{ front, back } bindings.optional()Art for this state; falls back to the component’s own faces
states[].propertieskey/value record.optional()Property overrides applied while this state is active

Attachable — pinned markers

attachable: true lets a component be pinned onto another object instance — a +1/+1 counter on a creature, a damage marker on a card. A pinned marker follows its host when it moves and is removed or captured with it; the engine handles that ripple, and the renderer draws the marker as an overlay on the host. Absent → not attachable.

FieldValuesDefaultWhat it does
attachabletrue.optional()This component may be pinned onto another object instance

Attach slots — named positions on a host

When a host component declares attachSlots, markers that attach to it can target a specific slot instead of the generic anchor (corner / center / edge). Each slot has fractional x / y coordinates within the host's bounding box (0,0 = top-left, 1,1 = bottom-right), an optional label, an accepts filter, and a capacity (default 1). The renderer draws the marker centred at the slot's position. When no slotId is provided on attach, the engine auto-assigns the first slot with available capacity.

FieldValuesDefaultWhat it does
attachSlots[].idtext (snake_case)Unique slot identifier within this component
attachSlots[].labeltext.optional()Display name shown on hover
attachSlots[].x0–1Horizontal position as a fraction of the host width
attachSlots[].y0–1Vertical position as a fraction of the host height
attachSlots[].acceptsarray of kinds.optional()Which component kinds may attach here (omit = any)
attachSlots[].capacityinteger > 01Maximum markers this slot holds

Value binding — a live number on a component

A valueBinding renders a runtime number on the component — a life total, a money count, a dial. The renderer reads key from either global or the owning player’s state. As with every taybl field, the bounds are advisory: min / max / step shape the spinner widget but the engine does not enforce them. Absent → no number is drawn.

FieldValuesDefaultWhat it does
scopeglobal playerWhether the number lives on the table or on the owning player
keytextWhich state value to read and display
displaynumber dial.optional()A numeric badge (default) or a dial widget
minnumber.optional()Display-only lower bound for the spinner — not enforced
maxnumber.optional()Display-only upper bound for the spinner — not enforced
stepnumber > 0.optional()Spinner increment size — display hint only

Stat block — per-instance properties a player adjusts

Where a valueBinding shows one table- or player-scoped number, a statBlock gives a component an ordered set of per-instance properties — a creature card with HP, MP, Attack, and Defense, a relic with Charges and an Element. Each declared property’s initial is seeded onto every copy when it is placed and is also the default the play menu resets to; from then on each copy tracks its own value: damage one Hero and the others are untouched. Every property has a type — a number stepper, a bar (with a max ceiling and a fill), a short text value, or an on/off toggle — and an optional icon. Pinned properties show inline on a frosted strip welded to the piece’s art (capped at the table’s statStripMax); the rest collapse into a +N pill that opens the stat menu. Players can also add an ad-hoc property (say crit) to a single card at the table. Values live in the object’s property bag, so a face-down or hidden card shows nothing. Edit properties in the Layout tab’s Properties inspector section. As everywhere, min / max / step are display hints — the engine never clamps a value. Absent → no properties.

FieldValuesDefaultWhat it does
statBlock[].keytextThe property key this value lives under
statBlock[].labeltext.optional()Badge label; absent → the key
statBlock[].typenumber bar text togglenumberValue kind + control shape
statBlock[].icontext.optional()Curated glyph key; unknown → 2-letter badge
statBlock[].pinnedbool.optional()Show inline on the piece (capped at statStripMax)
statBlock[].initialnumber/text/bool.optional()Value seeded onto each copy; the reset default
statBlock[].minnumber.optional()Display-only lower bound — not enforced
statBlock[].maxnumber.optional()Display-only upper bound / bar ceiling — not enforced
statBlock[].stepnumber > 01−/+ increment size — display hint only
statBlock[].displaynumber dial.optional()A numeric badge (default) or a dial
  • Components overview — the shared fields and kinds
  • Tokens — the most common home for a valueBinding counter
  • Pieces — meeple silhouettes via shape: polygon
  • Grids — the cells a footprint covers
Sign in to ask Pip about building games.
Sign in