| 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
Keeps 3 promises
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
Keeps 3 promises
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
Keeps 2 promises
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
Keeps 3 promises
| 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
Keeps 5 promises
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
buildandverifyfor 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.