Glyphs

The legend maps keys used in pieces to visual definitions. Each entry is either a sheet piece name (like piece or meeple), a glyph object with transforms and colours, or an array of glyph objects composited into one piece.

Player-owned pieces should set colour to a player number (1, 2, …) so user colour settings apply. Use hex colours or colour functions only when the colour is fixed.

See the contact sheet for every available sheet piece name.

Simple glyphs

A legend entry can be a plain string (the sheet piece name) or an object with name and optional properties:

"P1": { "name": "piece", "colour": 1 }

Example games: Arimaa, Go

Composite glyphs

An array of glyph objects is drawn bottom to top — the first entry sits underneath later ones. Each layer can have its own name, colour, scale, rotate, and other properties. Layers without a colour keep the artwork from the sheet.

Example games: Alfred's Wyke, Cannon

Gradients

colour and colour2 accept linear gradients with stops and optional x1/y1/x2/y2 (0–1, relative to the glyph bounds).

Colour functions

Colours throughout render JSON (glyphs, markers, board fills, and more) can use colour functions instead of a literal hex value or player number.

Function Purpose
flatten Blend a semi-transparent foreground over a background into one opaque colour.
lighten Lighten or darken a base colour by saturation (ds) and luminance (dl) deltas.
bestContrast Pick the most readable colour from a list against a given background.
custom Use a game-specific default while still respecting player or context customizations.

flatten

Returns the fully opaque colour equivalent to painting fg at opacity over bg.

{
  "func": "flatten",
  "fg": "_context_fill",
  "bg": "_context_background",
  "opacity": 0.25
}

lighten

Adjusts saturation and luminance. Positive ds/dl lighten; negative values darken. Arguments can themselves be player numbers, hex strings, context tokens, or nested functions.

{
  "func": "lighten",
  "colour": 3,
  "ds": 3,
  "dl": 1
}

bestContrast

Chooses the entry from fg with the best contrast against bg.

{
  "func": "bestContrast",
  "bg": "_context_background",
  "fg": ["#000", "#fff"]
}

custom

Ties a default colour to a palette value (player number or _context_* token). The renderer uses default when the user has not customized that palette slot; otherwise it uses palette. Set paletteType to "player" or "context" when palette is itself a function.

Patterns and colour functions

When a player assigns a pattern to a palette slot (for accessibility), colour functions degrade gracefully instead of erroring:

Function When an operand is a pattern Fallback
lighten colour Return the pattern unchanged.
flatten fg Return the pattern unchanged.
flatten bg only Compute flatten using hex fg over _context_background.
bestContrast bg Use _context_background as the contrast reference.
bestContrast fg entry Ignore pattern entries; if all fg values are patterns, use _context_strokes.
custom either branch Resolves to hex or pattern directly.

Pattern player slots apply to fills (data-playerfill). Strokes on those elements fall back to _context_strokes.

Patterns as colours

Named patterns are valid colour values anywhere a hex string or player number is accepted:

microbial, chevrons, honeycomb, triangles, wavy, slant, dots, starsWhite, cross, houndstooth

"PATTERN": { "name": "piece", "colour": "dots" }

Use custom to offer a pattern default while still honouring player palette overrides:

{
  "func": "custom",
  "default": "chevrons",
  "palette": 1
}

Colour value types

Any colour property accepts one of:

Form Example Notes
Player number 1 Uses that player's palette slot (hex or pattern per user settings).
Hex string "#ff6633" Fixed colour.
Pattern name "dots" Fixed black-and-white fill pattern.
Context token "_context_strokes" Resolved from the active colour context (strokes, fill, background, borders, labels, annotations, board).
Gradient { "stops": […] } Linear gradient; see Gradients above. Pattern stops use _context_strokes as a stand-in.
Colour function { "func": "lighten", … } See table above.

Rotated glyphs

Example games: Crosshairs, Pikemen

Stacked pieces (stacking-offset)

Example games: Abande, Accasta

Dice and text

Example games: Cephalopod, Cubeo, Boom & Zoom

Text glyphs use orientation: "vertical" so labels stay legible when the board rotates.

Glyph object properties

Each glyph object in the legend supports these properties. name and text are mutually exclusive.

Property Type Default Description
name string Sheet piece id (no whitespace). Searched across loaded glyph sheets.
text string Short text rendered as a glyph instead of sheet artwork.
colour colour Primary fill (or player colour when a number). Applied to elements tagged data-playerfill.
colour2 colour Secondary fill for elements tagged data-playerfill2.
scale number 1 Proportional size; values below 1 shrink, above 1 enlarge.
opacity number 1 0 (transparent) to 1 (opaque); applied to player-tagged fills and strokes.
rotate number | null 0 Degrees, −360 to 360. Negative is counter-clockwise.
orientation "fluid" | "vertical" "fluid" After rotation, "vertical" keeps text upright.
flipx boolean false Mirror horizontally.
flipy boolean false Mirror vertically.
nudge { dx, dy } Offset from centre in cell units; negative dx/dy move left/up.
fontFamily string CSS font family for text glyphs.
fontWeight string | number CSS font weight for text glyphs.

The legend also supports polymatrix entries (arrays of arrays for the polyomino renderer) and isoPiece entries (isometric renderer). See Engines.

Isometric face overlays

When renderer is isometric, an isoPiece legend entry may layer contact-sheet glyphs onto solid faces:

Property Use on Meaning
top cylinder, hexp, hexf, hex lintels Array of glyph objects stacked on the top face (bottom to top), same fields as flat legend glyphs.
decor cube, cube lintels (lintelNlintelEW, …) Map of intrinsic face (top, north, east, south, west) to glyph arrays. Uses the same N/E/S/W convention as faces on multi-colour cubes—not screen left/right.

Glyphs are isometrically projected with the active board.projection preset and rotate with piece yaw like face colours. Include the sheets that define overlay artwork in render options (for example piecepack); the default sheet list is unchanged.

Face decor is centered on each face using the glyph viewBox (square use, same idea as flat legends) and sized to fill the visible face square (viewBox-uniform fit to the long side). The legend entry’s scale multiplies that budget (default 1; use e.g. scale: 0.75 to shrink decor while keeping piece size unchanged). Sheet glyphs are fitted from their viewBox into the visible face region (cube/lintel parallelogram inset, cylinder/hex projected top silhouette). Per-glyph scale on each layer still multiplies that baseline. Overlays use the same face transforms as the painted mesh (no separate clip mask).

Rotation and orientation (sheet name vs text):

Kind Default orientation: "vertical" orientation: "fluid"
Sheet glyph fluid vertical (no board bake on iso tops) fluid
Text vertical (no board bake on iso tops) same as default fluid

Top faces only (top on cylinder/hex, decor.top on cubes/lintels): board.rotate and render rotate affect orientation. On the isometric renderer (which does not spin #board like flat layouts), fluid glyphs get +board.rotate baked into the overlay so they stay aligned with board edges; vertical / default text get no board rotation bake — cube yaw and the top-face projection already reorient the face so labels stay aligned with board edges (north at 0°, east at 90°, etc.). Flat legend layout still counter-rotates upright glyphs (-board.rotate) so screen orientation stays fixed when #board is spun. Cube/lintel side decor (north/east/south/west): art stays in default face-UV orientation; board spin only changes which side is visible (piece yaw), not rotation on the side. Set rotate: null on a glyph to disable rotation for that layer.

Domino-style blocks: place complementary cube lintels in adjacent cells (for example lintelE and lintelW) with different decor per cell so shared edges are omitted but each half keeps its own face art.

Schema reference — legend

Contact sheet

All sheet piece names (piece, piece-square, meeple, d6-1, chessmen, and so on) are listed in the contact sheet, grouped by sheet:

Contact sheet

The image is maintained manually in the renderer repo (docs/contact-sheet.svg) and updated when new pieces are added. See Adding pieces for contributor workflow.