Skip to content
Alpha The designer is real and runs today. Persistence and publishing are not built yet — read exactly what is missing
The product

A canvas with the code underneath it.

Everything on this page runs today. Drag a box and type a number and you have performed the same operation twice — the two views are not a primary and a preview, they are two windows onto one reducer.

Editing surfaces
9
Finished
7
Partly built, and saying which half
2
Account needed to open it
None
Shipping

Two modes, one document

Most visual builders make the canvas authoritative and generate code out of it. You can read that panel; you cannot meaningfully write in it, because the next drag regenerates over the top. That is an export wearing an editor's clothes.

Here both views dispatch into the same reducer. Markup commits on Apply rather than on every keystroke — half-typed markup is invalid markup, and parsing it live would churn the tree through garbage states and destroy your selection on every character. The stylesheet is the exception and applies live, because a browser simply ignores a declaration it cannot parse.

  • Anything the parser cannot represent is reported, never dropped in silence.
  • Round-tripping is the contract: parse(serialize(doc)) must reproduce the document.
  • Undo history is one stack, shared by both modes.
One edit, two spellings ⌘↵ to apply
In the canvas In the code pane Action
Drag the heading right <h1 style="left: 80px"> move
Resize the card <div style="width:320px"> resize
Type a class in the inspector class="card card--wide" setClasses
Drag a section up the rail Move the <section> in source order reorder
The right-hand column is the whole point: one action set, and the two left-hand columns are two spellings of it.
01Everything in the editor

Nine surfaces. Open a row to see what it actually does.

7 of them are finished; 2 say which half is missing rather than claiming to be done. The chips are read from the same file the roadmap page renders.

01 Canvas Shipping

Eight resize handles, an 8px snap, and drag and resize sharing one pointer session with a different anchor. Each move computes the new box from the total delta since the pointer went down — applying incremental deltas accumulates rounding error, and with snapping on the box visibly drifts away from the cursor.

Pointer events with capture, not mouse events: a drag that leaves the element or the window has to keep tracking, and capture is what guarantees the matching pointerup still arrives. Sections resize from the bottom edge only, because their width is the artboard's and their top is derived.

02 Code mode Shipping

Geometry travels as inline style — left, top, width, height — rather than as data attributes, precisely so you can move a box by typing a number. That is the entire point of having a code mode.

The document is a flat run of <section> elements in stack order with no wrapper. Inventing a <div id="root"> to hold them would put a node in your export that exists in neither the model nor the page you ship.

03 Breakpoints Shipping

Desktop 1200 is the base. Laptop 1024, Tablet 834 and Phone 390 are layers that apply at their own width and below — the cascade runs downward, exactly like a max-width query.

Layers store partials, only the fields you changed. Writing a whole box into the phone layer would pin all four numbers, so a later desktop change to width would silently stop reaching phone. Overridden fields are marked in the inspector, and Reset drops the layer so the field inherits again.

04 Classes and theme Shipping

Every element carries a class list, and the stylesheet that gives those classes meaning is one panel away. A builder that exposes only inline style produces documents nobody can restyle: every box holds its own copy of every decision, and changing the button colour means finding forty buttons.

The stylesheet is per project, not per page — a class that exists on one page is an inline style with extra steps. The Theme panel lists any class used in the document that has no rule yet, which is the fastest way to find the thing you named and never styled.

05 Presets Shipping

Navbar, two heroes, feature grid, call to action, pricing and footer. Each carries its own CSS, namespaced cs-, so a preset cannot collide with a class you have already written.

A preset is copied by value. There is no live link back, so editing one you placed changes only yours, and a future release changing a preset cannot alter a page you already built. Every multi-part preset is a flex container with media queries for narrow widths, because absolute geometry cannot reflow.

06 Baselumen components Shipping

The suite's component library renders live in a panel and imports into your document. Previews are iframed, because each component ships a stylesheet written for a whole page — rules like body and h1 that were never scoped to a card in a 258px rail. Rendering that inline would leak every one of them into the editor's chrome.

Imported nodes stay in flow. A component laid out by its own flex, grid and margins would be destroyed by being assigned absolute coordinates it never asked for. They are still selectable, inspectable and restyleable — they simply are not dragged to a position.

07 Block library In progress

Works: save any section to the library and place it on another page. Placement goes through the same path as a paste, so a placed block cannot diverge from a pasted one.

Missing: the store is a module-level array, so blocks last as long as the tab. The tables exist and are not wired. Placing copies by value and records the link, so the product can later answer "this block is used in twelve places" and offer an explicit re-sync — which is the safe version of a live binding that would otherwise change a client's published homepage without asking.

08 Assets In progress

Works: drop an image, place it at its true aspect ratio, and pick it again later from the inspector.

Missing: no storage bucket. Values are data URIs rather than object URLs — these get written into the document and serialised, and an object URL would produce markup carrying a reference that is already dead by the time anyone reads it. The honest cost is document size, which is why the panel reports the byte count of what you dropped.

09 Fonts and the keyboard Shipping

Font choices are written into the document's stylesheet, where they will ship — not into a separate settings state that has to be kept in step. Every stack terminates in a generic family, because an unterminated one falls back to Times the moment a webfont fails to load. That is the commonest reason a design "goes serif" for no apparent reason.

One declarative table drives both the key handler and the shortcuts sheet, so a binding cannot exist undocumented and the sheet cannot describe a key that does nothing. Nothing fires while a field has focus — ⌘Z in the code pane has to undo your typing, not the document.

The keyboard

One table drives the handler and the sheet.

A binding cannot exist undocumented and the sheet cannot describe a key that does nothing, because both read the same declaration. That is the same shape as everything else here: one definition, several renders.

Nothing fires while a field has focus. +Z in the code pane has to undo your typing rather than the document — a design tool that eats a paragraph you were halfway through is a design tool nobody types in twice.

A sample the app holds the full table
+Z Undo, through one shared history
+ +Z Redo
+D Duplicate the selection in place
+ Apply the markup you have typed
Delete the selected node
esc Clear the selection
Six of the bindings, not all of them. The sheet inside the app is generated from the table, so it cannot fall behind it.
02The other half of the page

What it will not do, stated here rather than found later.

Three of these are deliberate and one is simply not built. The difference matters, so it is marked.

Not built

Closing the tab loses the document. The schema is complete — projects, pages, sections and revisions — and the loader is what is being written now. Copy the markup and the stylesheet out of the code pane in the meantime; both are plain text and neither needs this app to be useful.

Deliberate

The designer refuses to open below 1100px. Rather than reflowing into a layout where a drag lands on the wrong element — a design tool that is subtly inaccurate about where you clicked is worse than one that says it needs more room.

Deliberate

Your stylesheet is injected as authored. Not prefixed, not scoped — you are writing the stylesheet your site will ship, and rewriting your selectors would mean what you see is not what you get. The cost is real: a bare p { color: red } also reaches the editor chrome. Moving the artboard into an iframe is the real fix and is on the roadmap.

Deliberate

Nothing is live-bound. Presets and blocks are copied by value on placement, so editing a library block later cannot reach into pages that already used it. Placements are recorded, so an explicit re-sync can be offered instead — the safe version of the same power.

It takes no account to try.

The designer boots with a document already in memory. Move something.

Deployed with Astro and Comlumen