Beta

New and still settling — attributes and behaviour may change.

canvas.diagram

canvas.diagramNode

A diagram environment on the scene's canvas: an uploaded image annotated with pins, a flowchart, a simple tree. Its image: names an uploaded asset by file name — canvas.diagram:cell.jpg is an annotated image with no child node needed — and a flowchart environment simply omits it. Boxes are arranged by the environment, layered along flow:, so a flowchart is written as what connects to what; pins carry their own coordinates. Positions here are fractions of the content frame with the origin at the TOP LEFT and y running DOWN — 0.62, 0.31 is 62% across, 31% from the top, the way a position is read off an image — unlike the graph's y-up mathematics. The frame is a camera: focus: (a point, or #id of a box or pin) and zoom: (a multiplier over the fitted frame) are both animatable with !cue.to, so one keyframe on each glides into a feature as the narrative reaches it.

Writing with it:Selecting canvas content

#The diagram environment

canvas.diagram holds the pictures that are neither plots nor maps: an uploaded image annotated with pins, a flowchart, a simple tree. Its implicit attribute is image, an uploaded asset named by its file name — canvas.diagram:cell.jpg is an annotated image with no child node needed — and a flowchart environment simply omits it.

The environment compiles whether or not the asset is there: an image: naming nothing renders a message in place of the picture, saying which file name it looked for. A diagram is therefore written and compiled against the coordinates first, and the picture uploaded after.

Positions are fractions of the content frame with the origin at the top left and y running down: 0.62, 0.31 is 62% across and 31% from the top, the way a position is read off an image. This is deliberately not the graph's y-up mathematics — a free-form coordinate drawing belongs in canvas.graph with !show background.

#Images and pins

A pin is a labelled point on the image: a dot on the feature, a short hairline leader, the label beside it. at: is its implicit attribute; side: places the label, defaulting to whichever side has room. Cues gate pins exactly as they gate graph marks, so annotations arrive with the narrative.

canvas.diagram:cell-micrograph.jpg{
    pin#nucleus(at: 0.62, 0.31; label: Nucleus)

    cue{
        pin(at: 0.28, 0.55; label: Mitochondrion)
    }(
        in: 1
    )
}

#Boxes and arrows

A flowchart is written as what connects to what, never as coordinates. box declares the things and arrow the relations between them — endpoints are #ids of boxes or pins in the same environment — and the environment arranges the result in layers along flow:, down by default or right. A tree is the same arrangement with the arrows all pointing one way.

A run longer than the environment has room for wraps rather than shrinking: it continues on a further line, reading back the other way, and the arrow between the two turns at the edge. So a box is always the size its text needs — a chain of fourteen steps sets the same type as a chain of three, on more lines. The arrows are routed through the space between the layers and down the sides, never across a box, and each label sits on its own run.

canvas.diagram{
    box#sample:terminal{Sample collected}
    box#pcr{
        PCR amplify
        30 cycles
    }
    box#check:decision{Enough DNA?}

    arrow(from: #sample; to: #pcr)
    arrow(from: #pcr; to: #check)
    arrow(from: #check; to: #pcr; label: no; dashed)
}(
    flow: down
)
The arrangement is computed over the whole environment, cues included: a cue controls when a box is seen, never where it sits, so nothing shifts as steps fire. A hidden: box keeps its place for the same reason. cue.draw strokes an arrow in along its own length; a dashed: arrow fades instead, since a dash pattern and the draw reveal cannot share one stroke.

#Shapes

shape: carries the flowchart conventions a reader already knows: box (the default rounded rectangle), decision (the diamond), terminal (the pill) and ellipse. It is the implicit attribute, so box#check:decision{Enough DNA?} reads as the diamond it draws. A box's text is its body, rich inline — maths, bold and {{…}} all work — and the body keeps its source lines: the first is the label, every further line a smaller muted line beneath it. Text wider than the widest box wraps rather than spilling.

#Placing a box by hand

A box with at: sits out of the arrangement at that fraction of the frame — a legend beside a flowchart, a caption box on an image. Everything else still arranges around it.

#focus, zoom and the glide

The frame is a camera. focus: takes a fractional point or #id naming a box or pin the environment already draws, and zoom: multiplies over the fitted frame — omitted, the content fits the environment. Both are animatable, so one !cue.to on each glides into a feature as the narrative reaches it; interactive additionally hands the reader wheel-zoom and drag, with a double-click back to the authored frame.

canvas.diagram:cell-micrograph.jpg{
    pin#nucleus(at: 0.62, 0.31; label: Nucleus)
}(
    focus: 0.5, 0.5 !cue.to{#nucleus}(at: 1; over: 800ms)
    zoom: 1 !cue.to{3}(at: 1; over: 800ms)
)

#Attributes

imageImplicit
Also written: src, sourceThe uploaded image the environment draws under its pins, named by its file name exactly as the block image names one. Normally written in the head, canvas.diagram:cell.jpg. Omitted, the environment's frame is the arranged extent of its boxes.Can be written as shorthand: canvas.diagram:value
flow
downright
Which way the arrangement runs: down stacks layers top to bottom, right runs them left to right. Trees and flowcharts are the same arrangement read in different directions. Either way the arrangement wraps rather than shrinking: a run longer than the environment continues on a further line, reading back the other way, so boxes keep the size their text needs.
Defaultdown
The caption set over the top-left of the environment, on the environment's own ground.
focusAnimatable
Where the camera looks: a fractional point, or #id naming a box or pin this environment already draws — so a frame aimed at a feature it also labels states that feature once. Animatable with !cue.to; absent, the frame centres.
zoomAnimatable
A multiplier over the fitted frame, animatable with !cue.to. NO default: an omitted zoom is auto — the content fits the environment — and zoom: 1 written out means exactly the fit.
interactive
Reader exploration: wheel-zoom about the cursor, drag to pan, double-click to reset. The explored camera overrides the authored or keyframed one once touched.
Defaultfalse
continue
Inherit an earlier diagram environment's state: continue: #that-environment. The reader's explored camera carries forward; every authored attribute is the new environment's own.

#Allowed content

#Allowed in

#Examples

canvas.diagram:cell-micrograph.jpg{
    pin#nucleus(at: 0.62, 0.31; label: Nucleus)
    pin(at: 0.28, 0.55; label: Mitochondrion)
}(
    focus: 0.5, 0.5 !cue.to{#nucleus}(at: 1; over: 800ms)
    zoom: 1 !cue.to{3}(at: 1; over: 800ms)
)
canvas.diagram{
    box#sample(label: Sample collected; shape: terminal)
    box#pcr(label: PCR amplify; sub: 30 cycles)
    box#check(label: Enough DNA?; shape: decision)
    arrow(from: #sample; to: #pcr)
    arrow(from: #pcr; to: #check)
    arrow(from: #check; to: #pcr; label: no)
}(
    flow: down
)