Skip to content
HomePagesHomePages template kit

What you're building

What the platform does, where your code sits in it, and why that makes your renderer a pure function.

Five minutes of reading, no commands. By the end you should know what a template is, who supplies the content it displays, and why the component you write is a pure function of its props — the one constraint most of this guide is downstream of.

A template is a set of sections, laid out across the pages of one site. A one-page site is declared exactly as a five-page one is. A section is a folder, and the three files in it divide the work cleanly:

  • section.ts — what content the section has, and where each piece should come from.
  • Renderer.tsx — how that content is laid out, as a server-rendered component.
  • fixtures.ts — sample content to preview against while you work.

Notice what is not in that list: the words and photographs of any actual home. You describe the shape of what a page needs. At the moment you author a section, the property it will one day render does not exist yet, so there is nothing to write about and nothing to fetch — which is exactly why the shape is declared in files a machine can read rather than decided inside your component.

The rest of this guide builds one section with a single slot — enough to show every part of the contract without burying it. To see the same pattern at production scale, scaffold a real 12-section listing template anytime, from outside any workspace you already have:

Terminal window
npm create @homepages/workspace@latest my-example -- --example spw-essential

That’s spw-essential. Read it for conventions rather than mutating it.

An estate agent hands the platform a property’s raw material — photographs, a listing document, floor plans, a voice memo, a few typed basics — and the platform normalizes all of it into one structured account of that property: its facts.

Then it reads your declarations and produces a value for every piece of content the section has: AI-written prose where you asked for AI, the property’s own data where you asked for a fact. Your component is never called during this stage — only the declarations beside it are read. See AI fill.

The filled draft opens in a content-only editor. The agent rewrites a headline, swaps a photo, hides a section — content, not layout, because the layout is yours. What they are looking at while they work is your section, re-rendered on every change.

When they publish, the finished content is rendered one last time to static markup, and that markup is what a buyer loads. There is no server application running behind a published page.

Put those three stages together and read them from your component’s point of view. It runs on our servers, never on your machine. It runs for content you never see, belonging to properties that did not exist when you wrote it. And it runs at a time you are not present — months later, with nobody to ask what you meant.

Nothing about that arrangement leaves room for a component that decides things for itself. It gets props and returns markup: no fetching, no browser globals, no clock, no random number, no state read at the moment of render. Same props in, same markup out.

That is not house style. The published page and the editor preview are two renders of the same section, at different times and on different machines; anything that answers differently between them is a bug the agent only discovers after publishing. Purity is what makes the preview trustworthy rather than approximately right. See Server and client for where interactive code goes instead — it is relocated, not banned.

Nothing to run. You are ready for the next page when you can say, in your own words:

  • Where your code runs. On the platform’s servers, at two moments — once when a deliverable is published, and again on every change while an agent edits.
  • Who supplies the content. The platform does, from the property’s facts. You supply the declarations that tell it what to produce.
  • One consequence of the renderer being pure. For example: a section cannot look up anything at render time, so everything it displays has to be declared in section.ts first.

If the third one is still fuzzy, read The pipeline — it is the same story at concept depth, with the stage-by-stage table.

Install — create a workspace and meet the files this page has been describing.