Skip to content

The layout system

You’ll find it at ACP → Appearance → Layout Editor. A page’s structure is a stored document, not compiled markup: for each template, an ordered list of blocks in each region. The Style Editor decides how things look; the Layout Editor decides what goes where.

Core ships a fixed set. A layout rearranges pages that already exist; it never creates routes. Plugins can register templates for their own pages (the forum does).

Template Renders at Regions
home / main · aside
article.index /articles main · aside
article.detail /articles/:slug main · aside
page.detail /p/:slug main · aside
profile /u/:username main · aside
members /members main · aside
chrome.header the site header, on every page header
chrome.footer the site footer, on every page footer

main is the page body (the editor labels it “Body”) and aside is the rail beside it. The login screens and the whole ACP are left out on purpose: you should never be able to rearrange the screen you’d need to fix a broken arrangement.

  • You see edits right away. The preview is the real page in an iframe, and the editor pushes the document into it before anything is saved.
  • The draft autosaves about 700 ms after you stop. There’s no save button.
  • Publishing is explicit and covers the whole site. It promotes every pending draft. Open tabs pick up the change within seconds over the style-version SSE stream, without reloading.
  • Reset puts the template back to its built-in default. You can’t undo it.
  • Drag wherever you like: in the structure tree or straight in the preview, and between regions. The / buttons are there for the keyboard. Hover a block to see its outline and type; click it to select it and open its settings.
  • Block settings are generated from each block’s Zod schema, so nobody hand-writes forms.
  • Required blocks (logo and userMenu in the navbar) can be moved but not deleted. Both the editor and the API enforce that.

None of these can take a site down:

  • A stored document that fails validation: the built-in default renders, and the ACP shows a warning.
  • An unknown block type (a plugin got disabled, a block was retired): we skip that block and render the rest. The block stays in the document, so re-enabling the plugin brings it back exactly where it was.
  • A block that throws: it renders nothing, and the blocks around it are fine.

A .xttheme is a zip of layout documents, tokens, a stylesheet and assets. Never code.

manifest.json id, name, version, vendor, minXentiumVersion, appearance
tokens.json the design tokens, by scope
styles/tokens.css the global tokens as :root custom properties
styles/custom.css the theme's own stylesheet (optional)
layouts/<template>.json one document per template
assets/ images and fonts

A theme is one look, light or dark; the manifest says which. Export packages what’s currently published. Import checks everything before it writes anything, so a package with one broken layout doesn’t apply at all. Installing a theme adds it to the site’s theme library, and we ask you whether to switch to it. Since there’s no executable code, reviewing a theme means reading JSON and CSS.

Need a block the catalogue doesn’t have? That’s a plugin, not a theme. See docs/plugin-blocks.md, and docs/style-system.md for how themes and tokens fit together.