Skip to content
HomePagesHomePages template kit

First render

Start the dev server and watch the scaffolded section render — in a browser, or from a terminal with no browser at all.

One command, and the section you just scaffolded is rendering — server-side, against sample content, the same way the platform renders it. Leave the server running when you are done: the next page reads the files behind it, and the one after that edits them and watches the render change.

Terminal window
cd my-workspace
npm run dev
> dev
> template-kit dev
template-kit dev — 1 template(s) at http://localhost:5180

That is the whole banner — one line, not a menu. 5180 is the default port, and npm run dev -- --port 5181 moves it. The workspace holds one template, so nothing needs naming on the command line; with more than one, npm run dev -- starter preselects it and the rest are still served. It runs until you interrupt it — it is a server, not a one-shot command. Its flags and exit codes are on its reference page.

While it runs it watches your template files and logs a line every time you save one:

1:45:08 PM [vite] (ssr) page reload templates/starter/sections/main/section.ts

Any preview of that section reloads with it.

Open http://localhost:5180. You land straight on the canvas — your template’s sections inside the platform’s own editor canvas, with the real edit panel and the real typed editors beside them. The panel’s Template selector switches templates, and its footer carries the actions that template’s output class earns — for a website, a View live button that opens the template rendering, the page exactly as it publishes, every section listed on it in template.ts order.

Either surface shows you a single section carrying the headline A typical headline that reads well in a short line — the value fixtures.ts supplies, which the next page reads. Preview with dev covers the rest of the surface: live reload, islands, the media library, content overrides and screenshots.

An agent, or a terminal-only session, can ask the same question of /api/inspect — it answers with each slot’s fill state instead of pixels:

Terminal window
curl 'http://localhost:5180/api/inspect?template=starter&section=main&fixture=typical&format=text'
{
"target": {
"template": "starter",
"section": "main",
"fixture": "typical",
"schemaFile": "sections/main/section.ts"
},
"slots": [
{
"id": "headline",
"type": "text",
"fillState": "filled",
"rendered": true,
"value": "A typical headline that reads well in a short line",
"provenance": { "kind": "authored" },
"at": "section.ts:11"
}
],
"variant": "",
"nullCorpus": [],
"outline": "section.tr-section.bg-background.text-ink\n div.mx-auto.max-w-3xl.px-6.py-12\n h2.text-2xl.font-semibold [slot:headline][leaf] \"A typical headline that reads well in a short line\""
}

(Whitespace added — the server sends it on one line.) Every slot the section declares is listed with where its value came from (provenance), whether it actually reached the markup (rendered), and the section.ts line it is declared on — so a surprise is navigable rather than mysterious.

Two things about that call are worth knowing before you make it again.

The fixture is typical, not base. fixtures.ts authors a key called base, and the kit emits it as a fixture whose runtime id is typical, labelled Typical (base content). base is the authoring word and typical is the runtime one; /api/inspect only takes the runtime one:

Terminal window
curl 'http://localhost:5180/api/inspect?template=starter&section=main&fixture=base&format=text'
dev server error: fixture "base" not found (have: typical)

That is an HTTP 500, and it lists every id the section really has — which is the quickest way to recover from it. /api/catalog.json lists them too, for every template and section at once:

Terminal window
curl http://localhost:5180/api/catalog.json
{"templates":[{"key":"starter","sections":[{"key":"main","fixtures":[{"id":"typical","label":"Typical (base content)"}]}]}],"defaultTemplate":null}

format=text does not return text. It returns the same JSON object with one extra key, outline — an indented tree of what rendered. Decoded, the one above reads:

section.tr-section.bg-background.text-ink
div.mx-auto.max-w-3xl.px-6.py-12
h2.text-2xl.font-semibold [slot:headline][leaf] "A typical headline that reads well in a short line"

That is the fastest proof a slot reached the page: the element it rendered into, and the marker tying that element back to the slot. The other agent-facing endpoints are in Preview with dev.

  • The banner names a port, and the server stays up until you interrupt it.
  • The main section renders — in the browser, or as the <h2> line of the outline above.
  • The inspect call accounts for every slot: headline comes back "fillState": "filled" with "provenance": { "kind": "authored" } — a value written by hand in fixtures.ts, not resolved from anywhere — and "rendered": true, meaning it reached the markup rather than being resolved and then dropped. nullCorpus is ["null_headline"] — the checks synthesize an empty state for every slot the section declares, so the one slot you have is already rendered blank for you.

Read the starter — the three files behind what you just saw.