EnvironmentDefinition

One canvas environment, on both sides of the system: what authors may write inside it, and how it draws and behaves.

@internote/canvas-sdkInterface
On this page
import { EnvironmentDefinition } from '@internote/canvas-sdk';

The compile side is the name, attributes, vocabulary and body policy the compiler and the semantic pass validate. The render side is the surface, the animation handlers, the toolbar, the footer, the storage declaration and the interpolators. Both halves are one object, so an environment cannot describe itself one way to the compiler and another to the host.

JSX enters in one place, Surface, and in the custom rows of the footer for what no other environment could share. The toolbar and the footer are otherwise data the host merges and draws, animation handlers react to the engine, and state goes through the declared storage tiers.

Build one with defineEnvironment, which checks the shape, and hand it to EnvironmentRegistry to make it available.

#Fields

animation
The environment's animation handlers. The engine calls in; the environment never owns a timeline.
EnvironmentAnimation
attributes
The attributes the environment node accepts, beyond the universal continue:.
Record<string, CanvasAttrSpec>
body
The environment node's body policy. Absent means the vocabulary plus the cue family, or none without a vocabulary.
PolicySpec
compile
A pre-built compile spec, used instead of attributes, vocabulary and body below.
EnvironmentSpec

Keep the spec in a React-free module when a server compiles documents without loading the surface: register the spec there for compiling, and pass the same object here for mounting. Registration with the same object on both sides is idempotent.

displayName
A human-readable name for listings and debugging.
string
freeParameters
Returns the names this environment's expressions use that no control declares. Each becomes a loose parameter in the scene's table, with a slider from −5 to 5.
(ctx: EnvironmentContext) => string[]

The host cannot work these out, because which identifiers in a body are free letters is a vocabulary fact: Q1 on an axis ruled in quarters is a quarter and not Q × 1, and the y in a surface's expression: is the axis it is evaluated over. Called during the host's render, so it may not use hooks. An environment whose attributes hold no expressions leaves it out.

interpolations
Interpolators for value shapes this environment invented, keyed by the interpolation kind its attributes declare with animatable.
Record<string, Interpolator>

The built-in kinds cover numbers, lists, intervals, points, colours and edges. An environment with a shape of its own, such as a map of a plane, declares a kind of its own name and says here how two such values blend. Registering a built-in kind's name replaces it for every environment in the host, so an environment names its own kinds.

nameRequired
The environment name, lower case with hyphens. Authors write <name>{…}.
string
storage
The storage tiers the environment uses. Absent means the session tier with no initial state.
CanvasStorageDeclaration
SurfaceRequired
Draws the environment. Rendered inside the host's stable frame, so hooks and local state survive a step.
ComponentType<SurfaceProps>
tasks
Returns the keys of the parts of this environment's node that ask something of the reader. Each makes the scene a task scene, starts incomplete, and reports where the reader stands through ctx.tasks. Called once, when the host mounts the scene. An environment that asks nothing leaves it out.
(node: CompiledNode) => string[]
toolbar
Returns the environment's toolbar items for the host to draw, and the reserved slots it fills, such as { type: 'view', channel } for the scene's one view group. Data only, no JSX. Called on every render of the host, so it may not use hooks.
(ctx: EnvironmentContext) => ToolbarContribution[]
useFooter
Returns what the environment contributes to the scene's footer right now: readouts for the bar, and key, scale and custom rows for the panel.
(ctx: EnvironmentContext) => FooterContribution

A hook, because what it reports is live — a hover, a caret, a run's output — and those readings are hooks. The host calls it on every render of the scene's footer, in environment order, so it must call the same hooks every time. The host merges every environment's answer: one colour key, one row per distinct scale.

vocabulary
The child elements the environment accepts in its body, keyed by identifier.
Record<string, CanvasNodeSpec>

#Example

export const greetingEnvironment = defineEnvironment({
    name: 'greeting',
    attributes: { size: { type: 'float', default: 1, animatable: 'number' } },
    vocabulary: { wave: { body: 'none', attributes: { colour: { type: 'paint' } } } },
    Surface: GreetingSurface,
    toolbar: (ctx) => [{ type: 'button', id: 'reset', label: 'Reset', onPress: () => reset(ctx) }],
    useFooter: (ctx) => ({ bar: [{ type: 'readout', id: 'waves', text: `${waveCount(ctx)} waves` }] }),
    storage: { tiers: 'session', initState: () => ({ waves: 0 }) },
});

Declared in packages/canvas-sdk/src/environment/types.ts:220.

Last updated