Build Webstudio Cloud
KINDAback to the verdict
A visual site builder whose hard problems are a document format that survives the editor being rewritten, a publish that is atomic and reversible, and an accessibility gate that runs before the site goes out rather than after somebody complains.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the editor, the renderer and the publish command.
Get it nodejs.org or your version manager. open ↗
Verify
node --version prints v22 or higher - have readyfree to a few units of currency a month
Why The whole argument of this build is that the output is ordinary files, and that is only true once you have served them from something that knows nothing about your builder.
Get it Any static host, or a small server with a web server in front of the release pointer.
Verify
A published release is reachable and rollback changes what is served - decidefree
Why A gate assembled from whatever was easy to check is a gate people switch off, and the list belongs in the README rather than in the implementation.
Get it Read the current WCAG text, pick the criteria this builder can actually break, and write the list down with levels. open ↗
Verify
Each listed criterion has a test and appears in the README - installfree
Why Contrast ratio arithmetic is easy to get subtly wrong and a gate that passes failing text is worse than no gate.
Get it A small maintained library implementing the published ratio formula.
Verify
It reproduces the published worked examples - have readyfree
Why Builders designed against imaginary content produce editors that only build the demo, and the missing component always turns up on the second real page.
Get it Take a page you already have and rebuild it in the editor as the first test of the format.
Verify
The rebuilt page renders and passes the gate
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- projects(id, name, created_at, document_version, token_set_id) · document_version drives the migration on load - pages(id, project_id, path, title, description, doc_path, updated_at, published_hash) - the page document itself: node(id, tag, props, style_refs, children) in a file, which is the source of truth and of which the editor is one view - styles(id, project_id, name, declarations_json, breakpoints_json) · named, reusable, and the default path for every change - assets(id, project_id, filename, bytes, width, height, alt, sha256) · alt is a column rather than an optional property, which is the whole argument - releases(id, project_id, at, dir, page_count, bytes, gate_report_json, rolled_back_at) · the gate report is stored with the release it gated - redirects(id, project_id, from_path, to_path, code) · because renaming a page is the most common way a small site breaks
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
CONTENT_DIR | required | ./content | Page documents, styles and the token set. This directory is the site. |
ASSETS_DIR | required | ./content/assets | Images and files, referenced by hash from documents. |
RELEASES_DIR | required | ./releases | One directory per publish. The pointer decides which one is live. |
RELEASES_KEEP | required | 5 | How many previous releases survive. Enough to roll back twice. |
DATABASE_PATH | required | ./data/builder.db | Project metadata, release history and gate reports. Never the documents. |
MAX_OVERRIDES_PER_PAGE | required | 12 | Above this a page blocks publish until acknowledged. |
PAGE_BYTE_BUDGET | required | 200000 | Transferred bytes per page. Publishing above it fails with the offending pages named. |
The build, in order
A document that does not need the editor
A page is a file with a version, and a command line renderer turns it into HTML.
The editor should be replaceable without the site being lost.
Files
src/document/schema.tscontent/pages/If it only runs inside the editor, the editor owns the site.
Files
src/render/cli.tstests/render-parity.test.tsterminalnpm run render -- --page home
A migration that overwrites the only copy is a gamble.
Files
src/document/migrate.tstests/migrate.test.ts
done when · tick each as it passeswatch out- Keeping the page in a database blob that only the editor can parse means the day the editor has a bug your site is unreachable to you, and this is the reason most abandoned visual builders leave people stranded rather than merely annoyed. Put the document in a file with a version field, write the renderer as a separate command, and treat the editor as one consumer of the format rather than its owner.
Styling that is still editable in six months
Changing the heading colour is one edit, not forty.
The override is the exception and should feel like one.
Files
src/styles/apply.tssrc/editor/StylePanel.tsxScan the rendered CSS in a test rather than trusting the editor.
Files
src/render/css.tstests/tokens.test.tsDrift is invisible until somebody counts it.
Files
src/styles/overrides.ts
done when · tick each as it passeswatch out- Letting every element carry its own declarations is the fastest route to a good-looking first screen and the reason the site becomes unmaintainable, because the tenth heading has drifted from the first and nothing tells you. Make the named style the default path, keep overrides available but counted, and refuse to publish a page above a configured override count until somebody acknowledges it.
A gate that runs before the site goes out
Publishing is blocked by checks that name the criteria they enforce.
A check without the exception is a check people disable.
Files
src/gate/targets.tssrc/gate/focus.tstests/gate.test.tsA gate that blocks on everything gets bypassed by everyone.
Files
src/gate/run.tsSo a question about last month has an answer.
Files
src/releases.ts
done when · tick each as it passeswatch out- Running an HTML validator and calling it accessibility testing checks something that is explicitly no longer a success criterion, since 4.1.1 Parsing was removed in WCAG 2.2, which reached Recommendation on 12 December 2024 and added the criteria a drag-and-drop builder is most likely to break: 2.5.8 Target Size at 24 by 24 CSS pixels and 2.4.11 Focus Not Obscured. Implement those two by name, including 2.5.8's spacing and inline exceptions, and read the current text before you write the thresholds.
Publishing you can undo
A publish either fully happened or did not happen at all, and the previous release is one command away.
Verification before the swap is what makes the swap safe.
Files
src/publish/render.tssrc/publish/verify.tsRolling back should not require a rebuild.
Files
src/publish/swap.tstests/publish-crash.test.tsRenaming a page is the commonest way a small site breaks.
Files
src/redirects.tstests/redirects.test.ts
done when · tick each as it passeswatch out- Rendering over the live directory means a crash halfway leaves a site that is part old and part new, with pages pointing at assets that no longer exist, and the quickest fix under pressure is usually publishing again on top of the mess. Render into a new directory, verify it, swap a pointer, and keep enough previous releases to roll back twice rather than once.
Handing the site to somebody elseproduct builder
The project exports as plain files, someone can edit the words without touching the layout, and pages that need no script ship none.
Anything less is a backup nobody has restored.
Files
src/export.tstests/roundtrip.test.tsThe handover is the moment a builder either works or does not.
Files
src/editor/ContentMode.tsxA static page should be a static page.
Files
src/render/script.tssrc/publish/budget.ts
done when · tick each as it passeswatch out- A builder that ships its own runtime on every page makes a five paragraph article depend on a framework, and the person you hand the site to then discovers it cannot be hosted on the plain static host they already pay for. Render to HTML and CSS by default, emit script per component rather than per site, and put the byte count per page in the release report so the number is visible rather than assumed.
That is the whole plan for Webstudio Cloud. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Multiplayer editing with cursors and comments.
- Managed hosting, domains, forms and analytics.
- A template marketplace.
- Arbitrary code components pasted into pages.
- CMS collaboration and client handoff
- managed hosting, forms, and analytics
- general-purpose visual editing
- large template and component libraries
- A content collection type, once you have two pages that differ only in their words
- A visual diff between the current documents and the live release, which is the review step this build lacks
- Automated screenshots per breakpoint stored with each release, so a regression has a before
Need the files? The project pack on the verdict page hands your agent the whole brief · more website builders.