youros

How it worksChanging it

Building

Three ways a page gets drawn, one renderer for all of them:

where runs from today
the editing pane the released editor the machine's files, through the files service the editor, for notes
the site's build the renderer at the commit the repo, in CI to come: the site has its own build
built-in publish the same renderer the @published version (D-34) later

One renderer, pinned by the commit

The renderer is the editor's: parseMarkdown, then PageView drawn to static HTML, as editor/publish.ts does for a page now. The site's build becomes publishing a folder: each file through the renderer, inside the site's layout. The site's components (<Serves />, <Parts />) become editor components, and the blocks the reader keeps as written (tables, quotes, HTML) render through one function in both. A component that needs the whole folder, such as a promise's proof, reads a context worked out from the folder's files (the trace), so the pane, which can read the folder, works it out too. Test results aren't in the folder; until they are a file, both say not run.

While only we use it, the renderer is a module in the repo, not a package, and the commit is its version. The pane runs the released editor, so CI renders with both and fails on a difference. The switch is checked the same way: the site is built by the old build and the new, and the old is deleted when they agree.

MDX as structure

The files are a dialect of MDX: markdown, and components as tags, which may hold blocks:

<Row gap="2">
  <Card title="Machines">
    Reach a shell or a file on any of your machines.
  </Card>
  <Card title="Files" />
</Row>

Props are literal values, as in the text form (editor/textform.ts); import, export and {…} expressions are not part of it, so a file draws the same wherever it is read and runs nothing. The reader keeps the lines each block was read from, as now, and nesting extends that: an edit reprints only its own span.

Layout is components with allowlisted props whose sizes are tokens: Stack, Row, Grid and Box, with gap, align and span. A screen's rectangles are those; its words are the markdown inside them; how it looks is the style layers, the file's own and the folder's.

Components from files and from code

A file component is an MDX file in a folder's components/, made of other components, with <Slot name="…" /> where an instance's blocks or props go. It is data, so a folder's file components load wherever the folder is opened, by anyone allowed to read it: the made components of compose/new, kept in a file instead of a page. Code components (Tabs, a terminal, the window manager) are code in the editor's registry, from a release; a page names them and passes literal props.

The line between the two is behaviour. A list drawn from data, a condition, a fetch: those are code components that take props, and the file says where they go.

Two frames, and any CSS

frame for script network
document pages, published pages, the browser's copy of a site none: sandboxed without allow-scripts none: default-src blob: data:
live islands, app previews released code only, on an origin of its own the node, by message

The shell writes the document frame's DOM from outside, as the browser copy does, and finds elements by id and source map, so editing needs no script inside it. Images and fonts arrive as ids the files service or the node minted and are held as blobs. Inside it, CSS can't draw outside the frame or fetch anything, so any CSS is allowed: a page's or a folder's stylesheet, in a layer after the style layers. The allowlist (style/allowlist) stays for what an edit writes, a person's or an AI's, and for anything drawn in the shell's own realm. The inspector reads the computed style and the rule that set it inside the frame: an allowlisted property is edited as structured style; anything else opens the stylesheet at that rule.

Offline, nothing changes: the renderer is in the released editor, cached by the service worker, and reads the folder's docs from this device when it holds them (D-28). A folder only on a machine needs a pipe to it, which today is set up through the relay even when the machine is on the same network. App code is compiled, on the node holding the working tree for a preview; a release is built only in CI (trust.md).

Apps

An app is a folder in the repo: its screens as MDX, its styles, its code components, and fixtures, states to draw it in (empty, full, an error). Its preview draws a screen with a fixture in a frame on an origin of its own, rebuilt from the machine's working tree on each save, so a throw or a loop stays in the frame (recover/trial). Code is edited as text beside the preview; MDX and styles are edited in place, as a note is. Each element carries where it came from: file and block for MDX, file and line for code, from the JSX transform.

Nothing edited reaches the running shell. Shipping is commit, CI builds with the same renderer, and the release goes through trust.md's tiers; devices run only released builds (browser/approved-releases).

Where it breaks

  • Most of the shell isn't boxes and words. The window manager, the terminal and the editor are code throughout; MDX gives them their settings pages, empty states and chrome text, not their insides.
  • A screen built from data maps back to its code, not to the data; the data is edited where it lives.
  • The released editor lags the commit. CI says so; the pane loading the renderer from the folder itself would end it, at the cost of running the folder's code in a frame.

Later

  • Built-in publish: moving @published; a node we host builds and holds it (D-34). Static and islands first.
  • The renderer for anyone's site: a package with build and verify for their CI, and a plugin that adds the source map to other frameworks' output.
  • Sites with servers: the site's dev server in a box on a node (D-26) for the pane, against preview data kept in the folder.