Skip to content

<layer>

<layer> groups other elements. It draws nothing itself.

src/chrome.ts2
<layer w="fill" h="fill">
<sprite w="fill" h="fill" sprite={Chrome.BACKDROP} tiling />

A layer has a position and a size, clips its children to its bounds, and can be hidden, moved or scrolled as a unit. It is the only element that may contain others.

To group elements without a container — no clipping, no shared position — use a fragment, <>…</>.

<layer> accepts all common props, plus:

  • children: The elements inside this layer. They are drawn in source order, so a later sibling covers an earlier one; a static layer can still land under siblings written before it.
  • direction: "row" or "column". Lays children out one after another along that axis, so you do not position them yourself.
  • gap: A number of pixels between children in a flow container.
  • padding: A number of pixels before the first child in a flow container.
  • scrollWidth, scrollHeight: Numbers. The size of the scrollable area. When larger than the layer, the contents can be scrolled.
  • scrollX, scrollY: Numbers. The initial scroll offset. To reopen where the player left the list, pass a sessionState cell and write the new offset to it when the list scrolls.
  • deferred: A boolean. Leave the definition’s value for this layer’s state-reading props until the state first moves — see common props.

static and rebuildOn are on common props.

  • A flow container needs every child to have a fixed size on the flow axis, and holds elements only (TS2E211). Position those children yourself.
  • Setting scrollHeight does not add a scrollbar. It makes the contents scrollable; the bar is a component you build.
  • Inside a scrolling layer, "fill" and percentages measure the scroll area (scrollWidth, scrollHeight), not the visible box.
  • A rebuild of the region resets the scroll position. See How updates happen.
  • A layer 0 wide or 0 tall over anything that reads state, runs a timer or watches is refused (TS2E252); give it w={1} h={1}.
refused/layer.ts2
<layer w="fill" h={16} direction="row" gap={4}>
{/* the first has no width to add up; the second is a component */}
<text w="fill" h={16} text="Buy" font={Fonts.PLAIN} align="center" color={Colors.AMBER} />
<Tab label="Sell" />
</layer>
src/shop.ts2
<layer x={10} y={42} w={{ fill: 20 }} h={{ fill: 52 }}>
src/reference-arrays.ts2
<layer w="fill" h={14} direction="row" gap={4} padding={2}>
<text w={60} h={14} text="empty" font={Fonts.SMALL} align="center" shadow color={Colors.DIM} />
<text w={60} h={14} text="single" font={Fonts.SMALL} align="center" shadow color={Colors.DIM} />
<text w={60} h={14} text="stacks" font={Fonts.SMALL} align="center" shadow color={Colors.DIM} />
</layer>
src/quest-log.ts2
<layer ref={list} x={2} y={2} w={{ fill: 22 }} h={{ fill: 4 }}
scrollHeight={QUESTS.length * ROW_H}>
{QUESTS.map((quest, i) => (
<QuestEntry name={quest.name} state={quest.state} y={i * ROW_H} />
))}
</layer>

scrollHeight is how tall the contents really are; h is how much of them you can see. Bind a ref if something else — a scrollbar — needs to move the position.

src/chrome.ts2
<layer w="fill" h="fill">
<sprite x="left" y="top" w={CORNER} h={CORNER} sprite={topLeft} tiling />
<sprite x="right" y="top" w={CORNER} h={CORNER} sprite={topRight} tiling />
src/chrome.ts2
<layer w="fill" h="fill">{children}</layer>
</layer>

The slot is created last so it draws over the frame.

src/deaf.ts2
{/* `hide` on the host's parent silences everything under it. */}
<layer x={2} y={2} w={104} h={{ fill: 4 }} hide={hidden === 1}>
<Column title="Hidden while away" />
</layer>

Timers and watches under it pause until it is shown.

Reserving a slot another interface opens into

Section titled “Reserving a slot another interface opens into”
src/integrating.ts2
<layer static ref={walletSlot} x={12} y={44} w={88} h={126}>
<Wallet />
</layer>
<layer static ref={offerSlot} x={112} y={44} w={128} h={126} />

The ref is a module-scope createRef, and its name is the slot’s.

Nothing positions children unless you do. Give each a y, or set direction and gap on the layer.

A layer clips its children to its own bounds. Either make the layer bigger, or set scrollHeight so the overflow becomes scrollable.

The container needs every child sized on the flow axis, and it cannot contain components or conditionals. Position those children explicitly.

Something between the slot and the interface is built at run time — usually a component that reads state, has a conditional, or a handler that captures a local. Move the slot above that part, or take the read out of it.