Allowed keys

Quick lookup for what may appear in content/*.json, styles/theme.json, and manifest.json. This page summarizes the author contract; the matching JSON Schema under schema/ is normative when they differ.

Workflow: skim the section you are editing → open the schema file (nodes, styles + visual_primitives, or manifest) → copy shapes from the Catalog instead of inventing layout or CSS-like fields.

Topic walkthroughs: Text · Images · Tables · Layout · Theme and fonts.

Agents also use the compact mirror in fields.md inside the skill folder.

Node (content/*.json)

Fields

Keys
Requiredid, role, content
Optionalvariant, layout, modifiers, break_inside, break_before, keep_with_next, column_span, colspan, preserve_whitespace
list_item onlyRequired list_id; optional depth (default 0), marker_type (default bullet)

colspan is table-cell occupancy only. Container children may be omitted (empty).

Never on a node

Do not put theme or paint on a node: color, font_size, font_family, padding / padding_pt, self_align, text_align, box_decoration, x, y, or similar. Those belong on the role in styles/theme.json.

content.type

TypeNotes
textDefault body copy, headings, code as text (role: "code")
mathDisplay or inline LaTeX in value
imagevalue.src (not path), width, height in millipt — Images, ex_image.json
containerchildren + optional layoutLayout
tableInline table — Tables
form_fieldFillable blank or checkbox — see below

This authoring path does not use code_block or table_reference (schema-legal elsewhere). See package.md.

Root rule: content/root.json must omit layout or use a vertical stack only. Put grid, overlay, columns, or a horizontal stack on a nested child.

Layout type: stack | grid | overlay | columns (omit type → stack). Grid rows is optional; omit → auto rows. fr / pt row tracks must be written explicitly. Contract: nodes.schema.json.

Form field (content.type: "form_field")

Reserved box: empty value still occupies space; filling must not reflow following nodes.

RuleDetail
roleform_field
kindtext | multiline | checkbox
widthOmit in a vertical stack or {fr:1} cell; required as a horizontal-stack child
Forbidden on nodelayout, modifiers
BreakSet break_inside: "avoid"
PlaceholderMetadata only — not painted
Do not fake blanksNo ____, /, or spacer images in body text

Copy ex_form.json. Minimal shape:

{
  "id": "app.name",
  "role": "form_field",
  "variant": "underline",
  "break_inside": "avoid",
  "content": {
    "type": "form_field",
    "value": { "kind": "text", "value": "", "placeholder": "Full legal name" }
  }
}

Modifiers (text nodes)

Required: range, type, intent. range is UTF-8 bytes (\n = 1 byte; CJK and emoji are multi-byte). Always run python scripts/modifier_range.py --text "<exact value>" --find "…" from the skill directory. intent must exist under theme.modifiers.styles[type]. Example nodes: ex_modifiers.json.

Catalog recipes

Copy catalog JSON into your package’s children. Do not invent CSS-like keys. Full index: Catalog.

Layout and page structure

GoalExampleNotes
Horizontal dividerex_rule.jsonrole: "rule" in a vertical stack at default align_items stretch — not inside a hugging align_items: start title stack; sibling the rule or nest the title group separately
Title + logo / space-between rowex_split_bar.json2-col {fr:1} + {auto:true}; right cell may be an image — not overlay
Magazine image + copyex_media_row.json{pt:N} + {fr:1}
Trailing-edge block (sender / right-flush)ex_end_block.json
Cover (logo + nested title groups + year)ex_cover.json
Filled page (invoice, CV, poster, slide, one-pager)ex_filled_page.json, ex_poster_shell.jsonRole page_shell; set height to the content box
Bleed header + inset bodyex_banner_header.json--margin 0; page_shell flush + nested page_shell — no negative margin
Grower for leftover spaceex_poster_growers.json{fr:1} on figure/dense cards, not a short quote
Background image under contentex_overlay.jsonImage child first — not page_config
Glass cardex_glass.jsonvariant: "glass" (catalog theme)
Dark band on a light documentex_on_dark.jsonvariant: "on_dark" on existing roles
Fillable blanksex_form.jsonform_field — never underscores in body text
Badge / pillex_badge.jsonStack wrapper (grid ignores self_align on a direct child)
Running header / footer splitcatalog/manifest.jsonPlaceholders {{page_current}} / {{page_total}} only
Numbered display mathex_math_numbered.jsonNot \tag

Tables

GoalApproach
Cell vertical centervariant: "center" on the cell
Numeric right-alignvariant: "end" (text_overrides in theme, not node text_align)
Dense metrics gridex_table_dense.jsoncompact + weighted fr
Three-line (ruled) tableTable variant: "ruled" + header row bottom
No colspan — edge rulesExtra columns + cell variant: "hbar" / "bottom"ex_table_edges.json
Composite cell (title + list / icon row)ex_table_composite.json
Row/column spacingrow_gap / column_gap optional (omit → parent gap)

Typography and spacing (nodes vs theme)

TopicRule
Small capsNo font_variant; use uppercase + role letter_spacing_pt
Line height vs gapLine box = role line_height_mult; space between siblings = parent gap (no node margin)
Centered text scopetext_align: center on a role is the content box (page minus margins), not the physical sheet
Overlay sizingOverlay children shrink to content unless that layer sets width / height

Theme role (styles/theme.jsonroles)

default requiredfont_family, font_size, line_height_mult, color
InheritanceOther roles inherit any omitted text field from default (container / rule / image roles need not repeat typography)
Optional on roleletter_spacing_pt, first_line_indent_pt, text_align, bold, italic, self_align, box_decoration, list_style, image_fit, variants

Variants: keys are only box_decoration, self_align, text_overrides, list_style, image_fit. Put bold, color, text_align, and font_size under text_overrides, not at the variant root.

box_decoration: values are named primitive strings (background, border, corner_radius, shadow, blur) except padding_pt (millipt number, per-edge object, or [top,right,bottom,left] like page margin). Applies to any node using the role (badges, table cells, warnings, code). Inline fill/border objects on a role fail compile (UNKNOWN_PRIMITIVE). Define names under primitives.

list_style: marker_box_width_pt, marker_gap_pt, depth_indent_pt, marker_align, bullet_glyph, number_suffix (omit → starter defaults).

image_fit: contain | cover (omit → contain).

Theme modifiers: nest modifiers.styles as typeintent → patch — not flat keys. Example: "emphasis": { "strong": { "bold": true } }. Starter: starter/styles/theme.json.

Contracts: styles.schema.json, visual_primitives.schema.json. Walkthrough: Theme and fonts.

Manifest (manifest.json)

Typicaltitle, canvas_mode: "paged", page_config (width, height, margin), engine_version
Optionalauthor, created_at, generated_by, running_blocks (text or grid node)
No sheet background in manifestPage fill is the root role’s box_decoration.background (full page, including margins)

Running blocks and page sizes: manifest.schema.json, package.md.

See also

  • Catalog — all ex_*.json files and theme labels
  • Format spec
  • schema/ — do not copy schema files into an author directory (UNEXPECTED_PATH)