Host

For the application embedding a canvas, not for the environments in it: the document and scene hosts, and the adapters they are given for storage, code execution and plugins.

@internote/canvas-sdk@internote/canvas-sdk/host24 exports

#Components

CanvasDocumentHost
packages/canvas-sdk/src/host/CanvasDocumentHost.tsx:512
Mounts a compiled document on a headless host and draws one of its scenes.

Builds the host with createHeadlessCanvasHost — rebuilt when the document, files or assets change, since each manifest arrives after the first render — and disposes it on unmount. It renders a CanvasSceneView for sceneIndex, clamped to the last scene, and nothing when the document has no scenes. The reading view mounts CanvasSceneView directly, with its own host.

Also takes className. Any other prop is passed to the rendered element.

assets
Uploaded image assets, file name → public URL — what an environment drawing an uploaded picture resolves against. null while the manifest is still arriving.
Record<string, string> | null
db
Database-tier backend for session+db environments; a no-op store when absent.
KeyValueStorage
documentRequired
The compiled + refined document.
{ body?: unknown; data?: Record<string, ChalkDataset> }
environments
Types to register before mounting (idempotent).
EnvironmentDefinition[]
files
The internote's uploaded text files by name, where attached dataset CSVs and geometry are read from. null while still loading; the host is rebuilt when it arrives.
Record<string, string> | null
internoteId
The internote's id, the first part of every environment's session key.
string
onStepChange
Called after the shown scene's step changes, with the new step and the scene's index.
(step: number, sceneIndex: number) => void
renderBlankElement
Draws blank-canvas content, such as renderBlankElement from @internote/canvas-library.
BlankElementRenderer
renderToolbar
Draws the host toolbar with the embedder's own buttons, in place of the minimal built-in one.
(toolbar: HostToolbarState) => ReactNode
resolveAssetUrl
Resolves a relative image source to a URL for blank-canvas content; null when it cannot.
(fileName: string) => string | null
sceneIndex
Which scene to show (index into the document's scenes).
number
Default0
CanvasSceneView
packages/canvas-sdk/src/host/CanvasDocumentHost.tsx:147
Draws one scene of a headless host: one toolbar, the scene's blocks in source order, one footer.

The canvas holds the scene's detail in the order the author wrote it — an environment's surface where they put one, a run of blank content (drawn by renderBlankElement) where they put that — with a hairline between every adjacent pair. A two-environment split is arranged by the scene's direction/ratio; a direction: auto split (the schema default) stacks here and goes side by side while presenting, where the canvas has the whole screen.

There is one toolbar per scene and one footer: the bar carries the system tier plus EVERY environment's declarative items, and the footer carries every environment's two bands under one chevron. Embedders draw the bar through renderToolbar with their own design system (the reading view draws the app's buttons); the built-in fallback is deliberately minimal.

Presentation is a drive mode: while presenting, the arrow keys and space move through the steps and Escape leaves. The embedder stages it (a fullscreen overlay, or this element's own fullscreen via manageFullscreen); the view only drives the steps. Mounting resets the scene's clock.

Also takes className. Any other prop is passed to the rendered element.

files
Uploaded text files (attached dataset CSVs), handed through likewise.
Record<string, string> | null
hostRequired
The headless host the scene was mounted by; supplies datasets, focus and presenting.
HeadlessCanvasHost
manageFullscreen
Whether this view fullscreens its own element when presenting. Embedders that stage presentation themselves (overlay) pass false and keep the keyboard drive.
boolean
Defaulttrue
onPresentingChange
Called when presentation starts or ends — the toolbar's toggle, Escape, or leaving fullscreen — with the new state.
(presenting: boolean) => void
onStepChange
Called after the scene's step changes, with the new step.
(step: number) => void
presenting
Controlled presentation state; omit for internal state.
boolean
renderBlankElement
Library-provided renderer for blank-canvas content.
BlankElementRenderer
renderToolbar
Embedder-drawn host toolbar (the app's own buttons).
(toolbar: HostToolbarState) => ReactNode
resolveAssetUrl
Asset resolution handed through to blank renderers.
(fileName: string) => string | null
sceneRequired
The scene to draw, from host.scenes.
HeadlessScene
step
Drive the step timeline externally (the reading view's narrative scroll-spy). Presentation keyboard advance still works; the two meet at the same StepController.
number | null

#Hooks

useStepRevision
packages/canvas-sdk/src/host/use-step-revision.ts:34
Re-renders the calling component on every step change and on each animation frame for a while after it.
(steps: StepController, options?: StepRevisionOptions): {
    revision: number;
    step: number;
    pulse: () => void;
}

Returns a revision that bumps on every step transition and keeps bumping on animation frames for tailMs after each transition (and after mount), so over: keyframe transitions and compound time offsets (at: 3 + 1.5s) resolve smoothly on screen. The tail is a bound, not a schedule: choreography that runs longer calls pulse to restart it.

Returns revision, the current step, and pulse to restart the tail.

#Functions

createHeadlessCanvasHost
packages/canvas-sdk/src/host/headless.ts:183
Mounts a compiled document without React or a DOM: step controllers, environment runtimes, session storage and toolbar resolution, exposed for direct use.
(options: HeadlessHostOptions): HeadlessCanvasHost

Registers options.environments, runs the canvas semantic pass, folds attached CSVs into the datasets, then builds a StepController per scene and an EnvironmentAnimationRuntime per environment, applying continue: handoffs before each environment's initial state. The React CanvasDocumentHost renders on top of this same host; tests assert against it directly.

The document must already be compiled and refined (the wasm compiler and refineInternoteDocument run upstream; in tests, feed a captured compile or a hand-refined fixture).

loadEnvironmentFromManifest
packages/canvas-sdk/src/plugin/loader.ts:38
Validates a plugin manifest, imports its code and registers the environment it defines.
(
    manifest: CanvasPluginManifest,
    options?: CanvasLoadOptions,
): Promise<EnvironmentDefinition>

Only runtime: 'module' loads; 'worker' is reserved for a sandboxed runtime and throws.

Returns The plugin's environment definition.

resolveCanvasLayout
packages/canvas-sdk/src/host/layout.ts:99
Splits a compiled scene's detail into canvas environments and blank-canvas content, and reads the scene's direction and ratio.
(scene: CompiledNode): CanvasLayout

A scene detail holds at most two canvas.<name> nodes (the semantic pass enforces the cap; this function does not); their order is primacy. Everything else is blank-canvas content, kept in source order. direction is returned as written — auto included, since only the render host knows whether it is presenting — so pass it through resolveSplitDirection at render. A missing or non-positive ratio reads as 1.

resolveSplitDirection
packages/canvas-sdk/src/host/layout.ts:42
The concrete axis a split lays out on.
horizontalvertical

auto stacks (vertical) while the canvas shares the page with the prose — the canvas column is far narrower than it is tall, and two side-by-side halves of it are unreadable — and goes side by side (horizontal) in presentation, where the canvas has the whole screen and the height is what is scarce. An explicit horizontal/vertical is honoured in both.

#Interfaces

CodeRunner
packages/canvas-sdk/src/runner/index.ts:67
Runs code for environments that declare runnable:, injected by the host.

The SDK defines only this seam: a transport-agnostic service the host may provide (HeadlessHostOptions.runner, exposed as ctx.runner), as the database tier is provided through db. The SDK itself never executes anything — without a runner, runnable environments render with running unavailable.

The shape is an event stream rather than a result: runs are long relative to a frame, output interleaves stdout and stderr, and the reader can stop one mid-flight.

availabilityRequired
A method, not a value — hosts answer live (auth settles after load).
CodeRunAvailability
notifyUnavailable
The reader pressed Run while it was unavailable. The button stays pressable on purpose — a disabled control cannot explain itself — and this is where the host raises its own prompt (the app shows its sign-in alert). Absent = the press is silently ignored.
void
runRequired
Resolves when the stream is fully consumed or aborted; rejects on transport failure.
Promise<void>
CodeRunRequest
packages/canvas-sdk/src/runner/index.ts:35
One program for a CodeRunner to run.
codeRequired
The full program: setup chunks + exactly what the reader sees (their fork, once forked).
string
fileName
The name the environment gives its code (title:, or the language's default) — the entry file runs under it, so tracebacks read exercise.py, not a scratch name. Hosts sanitize; absent falls back host-side.
string
identityRequired
The environment asking, so the host can attribute and scope the run.
EnvironmentIdentity
inputs
Reserved: named inputs (@data datasets, files). Always undefined in v1.
Record<string, unknown>
languageRequired
Canonical language name ('python' in v1).
string
signal
Aborts the run when the reader presses Stop.
AbortSignal
BlankRenderContext
packages/canvas-sdk/src/host/CanvasDocumentHost.tsx:56
What a blank-element renderer receives alongside the node.
datasetsRequired
The document's @data datasets, by id — what a data: #id binding resolves against.
Record<string, ChalkDataset>
files
Uploaded text files by name, where an ATTACHED dataset's CSV is found: the compiler emits such a dataset as a { src } pointer and does not inline its rows (§2.3). null while the host is still loading them, which a consumer must distinguish from {} — a wait, not an absence.
Record<string, string> | null
resolveAssetUrl
Host asset resolution for relative image sources, when available.
(fileName: string) => string | null
revisionRequired
A tick that changes on every step change and animation frame, so memoised renderers re-render.
number
runtimeRequired
The scene's runtime over its blank-canvas content, for presence and attribute values.
EnvironmentAnimationRuntime
stepRequired
The scene's current step.
number
CanvasLayout
packages/canvas-sdk/src/host/layout.ts:59
A scene's canvas split into its environments, its blank-canvas content and the split's arrangement.
blankRequired
Blank-canvas content: every detail element outside the canvas nodes, in source order (the legacy elements — the free migration path).
CompiledNode[]
directionRequired
Split arrangement as declared — only meaningful when environments.length === 2. Pass through resolveSplitDirection for the concrete axis: auto is not an axis.
autohorizontalvertical
environmentsRequired
The environments in primacy order — 0, 1 or 2 of them.
CompiledNode[]
itemsRequired
Every detail element in SOURCE ORDER, tagged — what a render host draws from.
CanvasLayoutItem[]

The two lists below are the same nodes sorted into their kinds, which is what the headless host and the semantic pass want: one animation runtime over all the blank content, one mounted environment per canvas node. Only this list remembers that the author wrote a table above the graph rather than below it, which is the order they meant.

ratioRequired
First environment's share over the second's (refined ratio, default 1).
number
CanvasLayoutItem
packages/canvas-sdk/src/host/layout.ts:51
One block of a scene's canvas: an environment, or an element of its blank-canvas content.
kindRequired
Which of the two lists below this node also appears in.
environmentblank
nodeRequired
The detail element itself.
CompiledNode
CanvasLoadOptions
packages/canvas-sdk/src/plugin/loader.ts:16
How loadEnvironmentFromManifest imports and registers a plugin.
importModule
Imports the plugin entry in place of a dynamic import() of manifest.src, for tests and hosts.
(src: string) => Promise<{ default: EnvironmentDefinition }>
register
Whether to register the loaded definition with the EnvironmentRegistry.
boolean
Defaulttrue
HeadlessCanvasHost
packages/canvas-sdk/src/host/headless.ts:142
A mounted document: its scenes and environments, the shared session store and the semantic diagnostics.
datasetsRequired
The document's @data datasets, by id, for consumers that bind one.
Record<string, ChalkDataset>
diagnosticsRequired
What the canvas semantic pass reported about the document.
SemanticPassResult
disposeRequired
Detaches every runtime from its step controller and clears the session store.
void
environmentByIdRequired
The environment with this id — the author's #id, else its instance id.
HeadlessEnvironment | undefined
focusEnvironmentRequired
Focus management: single focused environment, host-owned.
void
sceneAtRequired
The scene at index.
HeadlessScene
scenesRequired
Every scene in the document body, in order.
HeadlessScene[]
sessionRequired
The session store behind every environment's session tier.
SessionStore
setPresentingRequired
Sets isPresenting on every environment's context.
void
HeadlessEnvironment
packages/canvas-sdk/src/host/headless.ts:78
One mounted canvas environment in a headless host.
ctxRequired
The context its surface, footer and toolbar receive; the host keeps step, focus and presenting current.
EnvironmentContext
environmentNameRequired
The bare type name (graph, not canvas.graph).
string
identityRequired
Its session key: internote, scene and environment id (the author's #id when given).
EnvironmentIdentity
nodeRequired
The compiled canvas.<name> node.
CompiledNode
runtimeRequired
Its animation runtime, the same object as ctx.animation.
EnvironmentAnimationRuntime<EnvironmentContext>
toolbarItemsRequired
The environment's declarative toolbar contribution, validated.
ToolbarItem[]
HeadlessHostOptions
packages/canvas-sdk/src/host/headless.ts:35
What createHeadlessCanvasHost mounts and the services it hands each environment.
assets
The internote's uploaded image assets, file name → public URL; null while the manifest is still arriving. Handed to each environment's context untouched — resolution is the reading type's job.
Record<string, string> | null
clock
Injectable clock for deterministic time-anchor tests.
() => number
db
Database-tier backend for session+db environments (defaults to a no-op).
KeyValueStorage
documentRequired
The compiled + refined document. data is the @data datasets key (docs/design/chalk-data-and-references.md §3): inline datasets arrive with their columns and rows, attached ones with only a src filename — their CSV is deliberately not inlined into compiled output (§2.3), so a consumer that wants the rows fetches them.
{ body?: unknown; data?: Record<string, ChalkDataset> }
environments
Types to register (idempotent when already registered with the same object).
EnvironmentDefinition[]
files
The internote's uploaded text files by name — where an attached dataset's CSV and a boundary .geojson are both found. Attached CSVs are folded into datasets here so no consumer downstream has to know the difference; geometry is handed on as text for the type that reads it.
Record<string, string> | null
internoteId
The internote's id, the first part of every environment's session key.
string
Default'headless'
interpolations
How keyframed values blend; the shared built-in registry when absent.
InterpolationRegistry
runner
Code execution service for runnable: environments (absent = running unavailable).
CodeRunner
source
The chalk source, when available — sharpens semantic diagnostics.
string
HeadlessScene
packages/canvas-sdk/src/host/headless.ts:94
One scene of a mounted document: its step timeline, layout and environments.
blankRuntimeRequired
Animation runtime over the blank-canvas content (everything in the detail outside the canvas nodes) — cue constructs in blank content are scoped to it exactly as an environment's are to the environment.
EnvironmentAnimationRuntime
environmentsRequired
The mounted environments in primacy order; an unregistered type is skipped.
HeadlessEnvironment[]
layoutRequired
The scene's canvas split into environments and blank-canvas content.
CanvasLayout
nodeRequired
The compiled scene node.
CompiledNode
sceneIdRequired
The scene's instance id, or scene-<index> when it has none.
string
stepAnimationMsRequired
How long each step's own choreography runs, in ms measured from that step's entry, indexed by step (0..stepCount). Steps partition a scene's animation, so this is what the playback control is scoped to: the reader replays the partition they are reading. Index 0 also carries the time-anchored span, which runs on the scene clock the scene starts.
number[]
stepCountRequired
How many === step markers the scene body holds.
number
stepRevealOnlyRequired
Whether each step's choreography is nothing but plain cue reveals — content fading in or out on its anchor — indexed like stepAnimationMs.
boolean[]

Everything else is false: a cue.draw's strokes, an attention cue, a cue.type, a cue.parameter sweep, a !cue.to keyframe chain, an environment that moves on the scene clock of its own accord. The distinction is what a transport is FOR — a reveal has nothing to scrub through, so a short one does not earn a control (see CanvasDocumentHost).

stepsRequired
The scene's step controller, shared by its environments and blank content.
StepController
timeAnimationMsRequired
When the scene's time-anchored animation finishes, in scene-clock ms — 0 when everything is step-anchored.
number
HostPlaybackState
packages/canvas-sdk/src/host/host-state.ts:33
The playback control's state — null on a step with nothing to play, where the host draws no control at all.

Steps partition a scene's animation, and the control is scoped to the step the reader is on: it plays, pauses and replays that step's choreography, not the whole canvas. A scene with no steps has one partition, so its control is the whole scene's transport — which is what the control used to be everywhere.

Null covers two cases, and the second is the reason this is a state rather than a duration: a step that animates nothing, and one whose whole choreography is a brief plain-cue reveal. Neither has a middle for the reader to stop in.

finishedRequired
The current step's animation has run out (replay is what is on offer).
boolean
pausedRequired
Whether the scene clock is paused.
boolean
progressRequired
0..1 through the current step's animation.
number
replayRequired
Play the current step's animation again (the scene's, with no steps).
() => void
toggleRequired
Pauses the scene clock, or resumes it when paused.
() => void
HostToolbarState
packages/canvas-sdk/src/host/host-state.ts:47
Everything an embedder needs to draw the host toolbar.
advanceRequired
Moves to the next step.
() => void
backRequired
Moves to the previous step.
() => void
itemsRequired
The focused (or sole) environment's declarative environment-tier items.
ToolbarItem[]
playbackRequired
The playback control's state; null when the current step has nothing to play.
HostPlaybackState | null
presentingRequired
Whether the scene is being presented.
boolean
stepRequired
The scene's current step.
number
stepCountRequired
How many steps the scene has.
number
togglePresentRequired
Enters or leaves presentation.
() => void
StepRevisionOptions
packages/canvas-sdk/src/host/use-step-revision.ts:14
Options for useStepRevision.
tailMs
How long to keep animating after a step transition (ms).
number
Default3000

#Types

CodeRunAvailability
packages/canvas-sdk/src/runner/index.ts:18
Whether running is possible right now.
{
    ok: true;
} | {
    ok: false;
    reason: string;
    kind: "auth" | "unavailable";
}
CodeRunEvent
packages/canvas-sdk/src/runner/index.ts:23
One frame of a run, in arrival order.
BlankElementRenderer
packages/canvas-sdk/src/host/CanvasDocumentHost.tsx:85
Draws one element of a scene's blank-canvas content (everything in the detail outside the canvas environments).
(node: CompiledNode, ctx: BlankRenderContext) => ReactNode

The host handles cue wrappers itself, fading their content with the step timeline, and calls the renderer for each element inside them.

SplitDirection
packages/canvas-sdk/src/host/layout.ts:31
direction as the author wrote it.
autohorizontalvertical

Last updated