Diagram
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.
#The diagram environment
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.
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 with !show background.
#Images and pins
A 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. declares the things and 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.
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; dashed)
}(
flow: down
)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. A box's label: is rich inline — maths, bold and !value all work — and sub: sets a second, smaller muted line beneath it.
#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
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:valuedown stacks layers top to bottom, right runs them left to right. Trees and flowcharts are the same arrangement read in different directions.#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.!cue.to. NO default: an omitted zoom is auto — the content fits the environment — and zoom: 1 written out means exactly the fit.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
)