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
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.
| 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 |
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.
Canvas
Eight handles, an 8px snap, one pointer session.
Code mode
Writable HTML above, the project stylesheet below.
Breakpoints
Four widths, cascading down, storing only the difference.
Classes and theme
One stylesheet per project, one panel from the canvas.
Presets
Seven sections, namespaced, copied by value.
Baselumen components
The suite library, rendered live in a panel.
Block library
Save a section and place it elsewhere — until you reload.
Assets
Drop an image at its true ratio — into the document, not a bucket.
Fonts and the keyboard
Stacks that terminate, and one table behind every binding.
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.
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.
| ⌘ +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 |
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.
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.
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.
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.
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.