VizForDocs
The language

Document shape

The regions a vf-HTML document is made of, where a canvas takes its size from, and what a node id is.

One root, one canvas

<vf-doc studio="core" spec-version="1">
  <vf-canvas preset="APP_STORE_6_9" locale="en-US"></vf-canvas>
</vf-doc>

<vf-doc> is the root of every document and draws nothing. It declares which Studio the document belongs to and which version of the format it is written in. Inside it are two regions, of which only the first is drawn:

RegionDrawnWhat it holds
<vf-canvas>yesThe surface. Exactly one, always serialized first.
<vf-brief>noWhy this design is what it is: intent, audience, constraints.

<vf-brief> is a sibling of the canvas rather than a child of it, because canvas content is what gets drawn and the brief is not. It holds <vf-field> elements, each a named piece of text — intent, audience, constraint and rationale are the conventional names, and a Studio may expect its own.

The brief is not decoration. It is versioned and diffed like everything else and loaded into the assistant's context on every turn — so a design carries the judgement behind it, not only its result.

Where the canvas gets its size

A canvas takes either a preset or an explicit width and height, never both. Prefer the preset wherever one exists: it carries the destination's exact pixel size and its safe area, the region the platform guarantees will not be cropped or covered by its own chrome. Writing the size by hand gives a canvas a zero safe area, and then nothing remarks that the design is cropped where it ships. It does still get a margin — padding="safe" falls back to a proportional default when no preset supplies a figure — but a margin is not a guarantee, and nothing checks a design against it.

Every preset, with its safe area →

Two canvas modes render today: fixed (an exact width and height) and flowing (a fixed width, with the height being whatever the content needs and measured after layout). paged is declared and refused — it needs the renderer's PDF output.

Node ids

Every node in a validated document carries a vf-id, and it is minted at parse rather than only when a command creates one. The shape is the Block's type minus the vf- prefix, then a per-type counter: text-0, shape-0, text-1.

Three consequences, and each has cost somebody a debugging session:

  • An id names a node, not a place. Inserting a Block does not renumber the ones after it. An id read in one turn is still valid many edits later.
  • Structure is never derived from an id. text-3 has no parent you can compute and no type you can rely on — the prefix is there to be read, and a node may carry a name a person chose instead. Ask what created a node (vf_apply returns created) or read the outline (vf_get_doc), which reports each node's parent and depth.
  • A literal id in client code is a bug. The canvas is whatever the tree says the canvas is; a parent is whatever the tree says the parent is.

vf-name is the human-readable layer name beside the id, and it is a reserved attribute rather than a Block parameter — see what gets refused for the whole reserved set and what it means that no Block declares them.

Versions and migration

A document declares its format version (spec-version), and a migration module upgrades older documents when they are read. Breaking changes to the format are announced and migrated, not avoided. A document declaring a version this build cannot read or migrate from is refused with unsupported-version rather than being parsed optimistically.

On this page