sitereal
v0.1

Getting started

How sitereal works

site.sitereal, the engine, and the real Astro files that ship.

Three things make up a sitereal project: one document that holds what the builder knows, an engine that turns that document into files, and the files themselves — which are the site.

One file: site.sitereal

Everything the visual interface needs lives in a single JSON document at the project root: site settings, the design system, variables, global styles, installed fonts, components, templates, snippets, content types, media metadata and every page's tree.

site.sitereal
{
  "format": "sitereal",
  "version": 1,
  "site": { "name": "My site", "lang": "en" },
  "framework": { "enabled": true, "config": { "...": "..." } },
  "variables": [],
  "styles": [],
  "components": [],
  "templates": [],
  "snippets": [],
  "pages": { "index": { "route": "index", "root": [] } }
}

It is committed with the project. It replaced a .strata/ folder of sidecar files, which drifted apart, got half-committed, and made "is this folder a project?" a guess. One file moves, copies, versions and diffs as a unit.

The site never reads this file. Nothing emitted may import or fetch it. Delete it and astro build still produces the same site — you lose visual editing, not the site.

The engine

Opening a project starts a local server. It is the only writer of site.sitereal, and it owns emitting: when you save a page it writes that page's .astro file and its CSS; when you change something project-wide — the design system, variables, global styles, templates, snippets, site settings — it re-emits every page, because those things reach into all of them.

Its port and pid go in .sitereal/engine.json, which is gitignored: it describes one process on one machine, not the project.

The same engine serves the builder UI, the MCP tools an agent uses, and the offscreen render the project manager photographs for a card. There is one implementation of every operation.

What a page is

A page is a tree of nodes. One node looks like this:

{
  "id": "section-hero",
  "tag": "section",
  "name": "Hero",
  "classes": ["hero"],
  "attrs": { "builder-data-element": "section" },
  "children": []
}
  • id is stable. It is what the canvas selects and what per-element CSS is keyed to.
  • name is the layer name — what the tree shows, and what BEM class generation reads.
  • attrs holds every attribute except class, including builder-data-element.
  • text is text content; html is raw inner markup, for things that own their markup (an SVG, a highlighted code sample).

The page tree becomes the <main> of the emitted file. A template supplies whatever wraps it.

What gets written

PathWritten byYours to edit
src/pages/<route>.astroevery page saveno — rewritten
src/components/<Name>.astrocomponent saveno — rewritten
src/styles/generated/framework.cssdesign-system saveno — rewritten
src/styles/generated/global.cssglobal styles saveno — rewritten
src/styles/generated/pages/<route>.csspage saveno — rewritten
src/styles/generated/templates/<id>.csstemplate saveno — rewritten
public/scripts/{nav,motion,overlay}.jswhen a page needs oneno — rewritten
public/robots.txt, public/sitemap.xmlSEO settings, while marked as generatedno
src/layouts/PlainBase.astroscaffold, onceyes — it is your file
everything else in the repoyouyes

The rule is simple: anything under generated/, plus emitted pages and components, is written from the project document. Everything else is yours, and sitereal will not touch it.

Why builder-data-element

Every element carries an attribute naming what it is — section, container, heading, nav-link. The design system styles those attributes:

:where([builder-data-element="section"]) {
  padding-block: var(--section-space-m);
  padding-inline: var(--gutter);
}

Two consequences worth understanding. First, structural styling never depends on a class you might rename — the attribute is the contract, your classes stay yours. Second, :where() contributes zero specificity, so any class or id you write overrides the design system without !important and without caring about source order.

The loop you actually work in

  1. You edit on the canvas or in a panel.
  2. ⌘S sends the page to the engine.
  3. The engine writes site.sitereal and emits the files.
  4. Astro's dev server, if you have one running, hot-reloads what changed.

There is no build step of ours in that path, and no cache to invalidate.