Your code. Your components. Your Studio.
Studio is not a generator that hands you a folder of markup and wishes you luck. A page is a structured document, every block is a typed React component, and the model edits values inside that structure rather than writing code.
Frontend developers
You want the structure to be inspectable and predictable. It is JSON with a fixed schema, not a template language.
Agencies
Set the design system once per client, then produce pages that stay on brand without a review pass for every one.
Product teams
Marketing pages stop queuing behind the product backlog, and what ships still uses tested components.
Freelancers
Turn a scoped site around quickly and hand over something a client can edit without breaking it.
The page document
A page is data. The canvas is a view of it.
One document holds the title, the theme and an ordered list of blocks. The visual editor and the JSON are the same thing seen from two sides — editing either one moves the other.
{
"title": "Pricing",
"theme": {
"primary": "#f5a623",
"font": "inter",
"radii": "rounded",
"spacing": "comfortable"
},
"blocks": [
{
"id": "blk_9f21",
"type": "hero-centered",
"props": {
"heading": "Simple pricing",
"sub": "Every plan includes the editor.",
"cta": { "label": "Start free", "href": "/signup" }
},
"style": { "tone": "dark", "padding": "lg" }
},
{
"id": "blk_a4c8",
"type": "pricing-3col",
"props": { "plans": [ ... ] },
"style": { "tone": "default", "padding": "xl" }
},
{
"id": "blk_c103",
"type": "faq-accordion",
"props": { "items": [ ... ] },
"style": { "tone": "default", "padding": "lg" }
}
]
}Each card on the canvas is one entry in the blocks array. The ids match.
Flat by design
No trees. No nesting. No orphaned nodes.
The blocks array is flat. A block cannot contain another block, so there is no arbitrary-depth tree to reason about, no drag operation that can drop a section inside itself, and no state where a subtree is unreachable.
Reordering is an array move. Deleting is a splice. Duplicating is a copy with a new id. Those are operations a model can perform correctly every time, which is exactly why the structure was chosen.
The whole shape, in four lines
Page { title, theme, blocks[] }
Block { id, type, props, style }
type -> one typed React component
props -> that component's validated inputsFour keys per block. If a document round-trips through the editor, an export and back, it is still the same four keys.
The block contract
Every type maps to a component that already passed review.
A block type is not a hint. It resolves to one typed React component with a declared prop interface, and nothing reaches the canvas that has not been built and tested first.
interface PricingProps {
heading: string;
plans: Array<{
name: string;
price: string;
features: string[];
highlighted?: boolean;
}>;
}
export function Pricing3Col(props: PricingProps) { ... }
registerBlock('pricing-3col', Pricing3Col);Typed inputs
Props are validated against the block interface before render. A prop that is not on the interface does not reach the component.
Tested before you see it
Sections are built, reviewed and made responsive as part of the library, not generated per project and hoped over.
Style is separate from content
The style object carries tone, padding and alignment. Changing how a block looks never touches what it says.
AI editing
The model edits values, never syntax.
When you ask for a darker hero or a fourth pricing tier, the model does not write JSX. It emits changes to props, style, theme and the order of the blocks array. Those changes are applied to the document and validated against the block interfaces.
A model that cannot produce syntax cannot produce a syntax error. That is the entire reason a generated page in Studio survives being edited, where a page generated as raw code usually does not.
Allowed
props.heading = "Simple pricing"
style.tone = "dark"
theme.primary = "#14b8a6"
blocks: move blk_c103 -> index 1Not possible
writing a new component
inline styles or raw CSS
unclosed tags, bad imports
props the interface does not declareEvery applied edit is a saved version, so any state you had is still reachable.
Rendering
Server-rendered, then bundled to something self-contained.
The document is rendered on the server and published as a self-contained page. There is no client-side interpreter shipping to your visitors to reassemble a page from JSON.
Rendered on the server
Blocks resolve to components and render to HTML before the page is sent. Content is in the markup, so crawlers see it.
Bundled per project
Only the block components a project actually uses are included. An unused section costs a published site nothing.
Self-contained output
What gets published is a complete site with its own assets, not a runtime call back into the editor.
Honest scope
What you can do today, and what you cannot.
The developer story above is real and running. The programmatic story around it is not built yet, and it is worth being exact about which is which.
Working now
Section library
Every page is assembled from 33 responsive sections that are tested before they reach your canvas.
Design system
Colour, type, corner radius, shadow and spacing are global tokens. Change one, every page follows.
Publishing
Publish to a live skode.ai address in one click, with HTTPS handled for you.
Version history
Every save is kept, so you can go back to any earlier state.
Not built yet
Studio API
PlannedCreate and update Studio projects programmatically.
GitHub import
PlannedConnect a repository and import its front end.
Template library
In developmentStart from a finished, editable project instead of a blank page.
There is no public API, no repository import and no custom template authoring today. Studio projects are created and edited in the editor.
Read the structure. Then build on it.
The Developer Hub carries reference material across Skode products. Studio documentation lives alongside it.