The host owns the chrome. Your space declares pages in the manifest; the host renders the sidebar. Your page teleports content into the toolbar slot; the host shows it. The active page renders into the canvas.
The active page from pages[] renders here — your Vue tree owns the canvas.
Window frame, traffic lights, canvas surface — all Construct. Your space never renders these.
The host reads your manifest and renders one rail icon per page. The default: true page is the landing route.
{
"pages": [
{ "id": "home", "path": "", "icon": "i-lucide-home", "default": true },
{ "id": "boards", "path": "boards", "icon": "i-lucide-kanban" }
]
}
The host renders an empty toolbar slot above the canvas. Your page fills it; the SDK teleports the nodes into the slot.
const tb = useToolbar()
const bc = useBreadcrumb()
bc.set([{ label: 'Boards' }])
tb.actions([
{ label: '+ Create board', onClick: createBoard }
])
The active page component mounts into the canvas. Routing between pages is the host's job; inside a page you own the DOM.
// pages/boards.vue
<template>
<BoardGrid :boards="boards" />
</template>