Views and actions

A schema describes what a kind of object is. Two more things can be attached to it: how its objects are drawn, and what they can do.

Together they turn a schema from a storage format into something closer to a small application. A character has a character sheet and a "write a voice line" button; a recipe has a recipe page and a "shopping list" button. Neither needed any code.

Both are properties of the type, not of one object. You decide once, on the schema, and every object of that schema has it.

Views

A view is a template: markup over a fixed vocabulary of components, with {{field}} bindings that fill in from the object being shown.

Views live on the Views tab of the schema editor, and each is a file in the project, so they diff in git and travel with the folder like everything else.

A schema with no view still opens — the form generated from the schema is the fallback. A view is an override, and it is allowed to show fewer fields than the schema has. A character sheet that puts the secret on its own tab and leaves three bookkeeping fields out entirely is doing its job.

Boxes

A view is written for a box — the kind of place it will be inserted into:

Box Where it goes
page A full page: the Page tab of the object, and a dock tab of its own.
card A compact card in a list.
panel A side panel.

The list of boxes is fixed. A box is a contract about how much room there is and what surrounds it, so boxes are something Zero provides and a template chooses — a box nobody knows how to draw would just be a rectangle.

One view per schema per box. Once every box is taken, the editor stops offering New view.

Today the page box is the one that renders. Views written for card and panel are stored and checked, but nothing displays them yet.

Writing a template

The syntax is HTML-shaped, and the vocabulary is Zero's own. There is no div and no class: layout is made of named primitives, so the set is finite, the result is predictable, and a template cannot break the surrounding page.

Layout — stack, row, grid, split, card, divider, spacer, scroll.

Content — field, image, list, table, link, button, tabs/tab, if, note.

Text — h1, h2, h3, p, text, b, i.

A small example:

<row gap="lg">
  <image of="portrait" size="lg" />
  <stack gap="sm">
    <h1>{{name}}</h1>
    <text muted="true">{{role}}</text>
    <if when="status" is="Missing">
      <note kind="warn">Missing. The table has not been told yet.</note>
    </if>
    <button action="voice-line">Voice line</button>
  </stack>
</row>
<table of="ties">
  <item>
    <b>{{who}}</b>
    <text>{{note}}</text>
  </item>
</table>

A few rules worth knowing before you start:

The editor has a check that resolves every path and action against the schema as you type, which is where a typo shows up.

What is checked and what is not

Zero checks references: that a field path exists, that an action exists, that a list is a list. It deliberately does not check tag names. The vocabulary belongs to the part of Zero that draws the page, so an unknown tag renders as a small flagged box rather than being rejected — which is also how new components can appear without anything else having to change.

Actions

An action is a button on every object of the schema. Pressing it runs a workflow with that object as its single input row.

It is deliberately a binding to an existing workflow, not a scripting language. A workflow is already a function whose signature Zero works out for itself, and its input is rows of {variable: value} — an object is exactly one such row, as soon as something says which field feeds which variable. That something is the action's bind.

Actions live on the Actions tab of the schema editor. Each has:

A bind points at a field path (appearance, traits.might) or at one of the two reserved tokens $name and $guid, which address the object's identity rather than its data.

The binding is checked when the schema is saved, not when the button is pressed: a renamed field or a deleted workflow surfaces in the editor, while you are looking at it.

Running one

Pressing an action starts an ordinary background job. It appears in Jobs, it counts against the same spending budget as any other run, and it can be stopped from the button itself.

Two things are worth knowing:

An action produces — a file, an asset, a chat. Writing a result back into a field of the object is not possible yet.

Not yet

Three things are deliberately absent rather than forgotten: