Menu

D60. Charts and diagrams: blocks that each say one thing, drawn at build time, moved by the player, in step with the voice (23 Oct 2026)

On this page

The founder asked which charts courses need, how far authors should build them by hand, and what agents should get to make their own charts as carefully as ours. Research on the charts e-learning uses and visual prototypes came first (23 Oct 2026); the founder approved the direction: native blocks with small forms, Mermaid diagrams drawn by Pele, and agent-made charts as free objects built on the same kit. Reviewing the prototypes, the founder found the springy hover too sudden, asked for predict to be unscored by default, and for voice beats to dim what the voice is not talking about. Authors and agents read the result in Charts and diagrams.

Weighed:

  • One generic chart block with a type switch and every option. Its form would have to adapt to every kind of graph. Rise has three chart types with one series, and users still ask for what it cannot do. Rejected.
  • A chart library in the player (ECharts, Chart.js, Vega-Lite). They weigh 70–370 KB. Chart.js and ECharts’ default renderer draw text into a canvas, so it is not translatable, searchable or read aloud. ECharts refuses CSS variables (its issue #19743). Vega-Lite has no mark animation. Rejected for native blocks.
  • Idea blocks: about a dozen built-in blocks, each saying one kind of idea, with 3 to 6 props and a data table, drawn at build time as HTML and SVG from the course’s tokens, and animated by a player behaviour. Chosen.

The blocks

Type What it says Items
key-figures 2–4 numbers to remember items[]: figure, label, count, was
bars A ranking: what dominates rows[]: label, value, note
donut A whole in 2–6 parts parts[]: label, value
trend A change over time, and what explains it points[]: x, y; note; mode: "predict"
proportion “1 in 10” as an icon array of, part, figure, label
before-after Who moved, and who moved least items[]: label, before, after
levels A funnel (values) or a pyramid (levels) items[]: label, text, value; shape
process A short procedure items[]: title, text
cycle A loop of stages items[]: title, text; center
matrix Items placed on two axes items[]: label, x, y, text; quadrants; x; y
milestones Dated events items[]: date, title, text
diagram A flow, a decision, a map of ideas mermaid (its source), labels, beats

Common props.

  • takeaway (required): the sentence the chart proves, shown as its title. “Most incidents start with an email”, not “Incidents by origin”. Research on signalling (Mayer) and data storytelling (Knaflic) says a learner reads the title first.
  • context: one line under it.
  • source: a footer.
  • highlight: the id of the item that carries the idea. It takes the accent; the others step back in tints of the course’s ink (color-mix, so there is no palette to choose).

Every item has an id. Highlights, beats and translation units name items by id, and an item keeps its id when it moves.

Drawn at build time

  • Rendering. The core renders each block to HTML and SVG (packages/core/src/charts/), with D3’s DOM-free modules (d3-scale, d3-shape, d3-array; ISC, about 12 KB) and the course language’s number formats (Intl).
    • Words are HTML wherever they must wrap.
    • Geometry is laid out in percentages and viewBox units with non-scaling strokes, so a chart is right at any width without script.
    • Narrow containers (under 560 px) change layout through container queries instead of shrinking.
  • What it gives. Packages, fit checks, captures, the Document export and the canvas see the final chart with no JavaScript. Every chart carries a data table for screen readers.
  • Fallback. Exports and detach fall back to a text block: the takeaway, then a Markdown table of the data.

Moved by the player

The chart behaviour (packages/player/src/charts/) adds motion, hover and keyboard to that markup. It never changes layout. Motion follows the player’s rules (D58, player.css « Motion »), reread for charts:

  • Entrances are rare and may be playful.
    • They run once, when the block is first shown or scrolls into view, in reading order: bars grow, the line draws itself, icons arrive in a wave.
    • They last about one second, with a stagger of 40–90 ms, and finish with the “focus pull”: every item stands, then the highlighted one takes the colour.
    • An overshoot is allowed only on small pieces that arrive (a pin dropping, a dot appearing).
  • Answers to the learner are soothing. Hover, focus and tap:
    • 180–240 ms on --t-ease-out, with no overshoot and distances of a few pixels;
    • a fade on ease for what must be seen;
    • the other items fade back to 40 %.
    • The value bubble (.t-chart-tip) glides to its next item only while it is still visible; when it was hidden, it appears in place.
  • Less motion asked: the chart is shown at once, with a short fade; hover changes only colour and opacity.
  • The pointer is magnetic. The nearest item answers, not only the one exactly under it. A tap does the same on touch. Arrow keys walk the items, and a live region reads each item and its value.

In step with the voice

Each item may take at, an anchor like a timing’s (a line, a word: { "line": "l2", "word": "phishing" }). At that moment the item appears and becomes the one the voice talks about: the others step back as on hover (signalling). It stays so until the next item’s moment, or until the block’s spotlightEnd. Without spotlightEnd, it lasts until the end of the line where the last item came; then every item stands and the highlight takes the colour.

  • Spotlight only. revealOnBeats: false shows every item from the start and only moves the spotlight.
  • The trend. Its points take at too: the line draws up to each point as the voice reaches it, with its value riding at its head.
  • The diagram. It takes beats: [{ "node": "B", "at": … }].

Beats are timeline moments. They are resolved like cues (the narration’s word times, estimated without them), translated as word markers (D28), and checked like every anchor (E_TIMELINE_ANCHOR_MISSING). The player places them as a function of time, like timed blocks: seeking back hides what had not come yet. Beats are the research’s strongest result made cheap: temporal contiguity and signalling.

Predict, then reveal

trend with mode: "predict" hides the points after predict.from. The learner draws the rest of the line, then presses the button. The real line draws over the guess, with feedback that names both values.

  • Scoring. It is not scored by default (scored: false): it is a moment of engagement (prediction and generation effects: Kim, Reinecke and Hullman 2017; Bertsch et al. 2007), not a test. With scored: true it counts like a question, correct within predict.tolerance.
  • What is recorded. The guess is kept in the learner’s state, so a resumed screen shows it revealed, and it is sent as an interaction.
  • Slides. They reserve the room the feedback takes, as for an answered question.

Diagrams

  • Source and renderer. diagram takes Mermaid text in mermaid, which agents write fluently. Pele draws it in the core at build time (MIT, by kepano; pinned to an exact version and checked monthly). There is no Mermaid fallback: Mermaid needs a browser to lay out and weighs 1.6 MB.
  • Allowed types: flowchart, sequence, state, mindmap, timeline, journey, ishikawa, venn. Others are E_DIAGRAM_TYPE, and syntax errors are E_DIAGRAM_SYNTAX with Pele’s line and column.
  • Two variants. It is drawn wide as written and narrow with autoDirection, and the container picks one.
  • Words.
    • The Mermaid text is written in the course’s language.
    • A translation writes labels, by node and edge id, and the build swaps them on the parsed model.
    • Colours come from the tokens through --pele-*; classDef and style colours are refused (W_DIAGRAM_COLOR), so dark themes stay readable.
  • The player. It reveals nodes by depth and draws edges. Pointing at a node lights the path that leads to it.

Agent-made charts

A chart the catalogue cannot draw is a free object.

  • Writing it. Its code may import * as d3 from 'd3' (D3 7.9, bundled into the object) and import { … } from '@elabora/charts', the same kit the native blocks use: one clock (host.onFrame), entrances, the soothing hover, the magnetic pointer, the tip, number formats, label dodging and the frame with its table.
  • What the author changes. It declares what authors may change in its manifest’s props, as any object does. The skill elabora-charts teaches the same rules as this decision.
  • Between the two.
    • When an author asks for what a block cannot do (a second series, a log scale), the agent may fork the block into an object.
    • An object reused in three modules is a candidate for the catalogue.

Revisit if: authors keep asking for several series in bars or trend (then a series prop rather than an object); Pele stalls or changes its ids (then pin it, or contribute upstream); the build-time layout of a chart proves wrong in a language with long words (then the behaviour lays it out again in the browser).