Build diagrams that move or respond to input. Works with Claude, Cursor, Codex, OpenClaw, Hermes, and all agents that read SKILL.md.
| Tier | Output | Where to use |
|---|---|---|
| 1. Lesson diagram | Declarative SMIL animation, or an SVG-redrawing slider component, both mounted via a figure fence | In lessons |
| 2. Mechanism diagram | An HTML panel showing real system components, where the reader operates one control and reads a computed conclusion | Standalone pages, READMEs, articles, pages on sites outside the course |
| 3. Dither field | A WebGL ordered-dither band using paper, accent, and ink colors, with four fixed-seed motions | Headers and section dividers |
The course runtime has strict limits, so tier 1 has the most rules. Tiers 2 and 3 have their own reference files.
When to use
- The course explains a process that changes over time, such as tokens passing through stages, a queue filling, or a loop repeating.
- One input changes a formula's output, such as learning rate, temperature, chunk size, or batch size.
- The author asks for an animated, slider, or interactive diagram.
- The page needs the reader to change one condition and observe the behavior of a cache, queue, context window, or router: use tier 2.
- The page needs a slow animated header in the course palette: use tier 3.
When to use other skills
- Fixed structure, no timeline or input: use the
blueprint-figurestatic diagram. - A full explainer page with its own state model and machine geometry: use
isometric-explainer。 - Only palette, fonts, or writing rules are needed: use
course-style. This skill copies the necessary parts intoreferences/tokens.md。
Method
-
State the diagram's single change in one sentence. If it needs two sentences, split it into two diagrams.
-
Choose a tier. Use tier 1 inside lessons. Tier 2 reads
references/mechanism-figures.md, starting fromtemplates/mechanism.html. Tier 3 readsreferences/dither-fields.md, copyingtemplates/dither.js. The following steps apply to tier 1: use animation when time is the variable, and a slider when a number is the variable. -
Use kebab-case names, for example
request-path、context-budget. Check the registry first; registering a module with the same name replaces the earlier diagram. -
Put the code in
figures-<topic>.js, wrap it in an IIFE, readwindow.LF, and return immediately if it does not exist. -
The diagram function signature is
function (host, cfg), add one.lfcard to the host, and it may return a cleanup function. -
The card contains
.lf-head(uppercase.lf-labeland a short hint),.lf-body、.lf-capand a caption. -
The SVG uses
viewBox="0 0 520 H"; H is usually 200 to 250, and single bars can be shorter. -
Add a title and desc, create IDs only once, and place them outside the render function.
-
Animate the entrance first, then move into a slow loop, following each item in
references/smil-rules.md。 -
Define the slider first
state._render, then call LF.slider or LF.select, and finally call oncestate._render()。 -
At the end of the module use
LF.register({ 'your-name': fn })to register. -
Course Markdown adds a fence; the first line is the name, and JSON may follow:
```figure context-budget {"windowK": 32} ``` -
Complete the checklist and review in light mode, dark mode, at 375px width, and with reduced motion enabled.
How pages mount figures
- The Markdown parser converts the fence to
<div class="lesson-figure" data-figure="name {json}">。 - The builder scans the course for figure names, finds the module containing that quoted name, and writes the manifest. If no provider is found, the build stops.
- The page loads only the modules needed for that lesson, in a fixed order. New files are placed after the listed files and loaded alphabetically.
- The mount function takes the first word as the name and parses the rest as JSON; on failure, cfg is an empty object.
- If the figure function throws, the runtime clears the host and logs a warning; the rest of the lesson continues rendering.
- After mounting, fill in any missing title, desc, role=img, and control labels. Add a pause button when SMIL is present, and a replay button when there is a one-shot animation.
- Stop animations when out of the viewport, when the tab is hidden, or when the reader clicks pause. Show a static frame when reduced motion is enabled or when printing.
See all runtime functions and two complete examples in references/toolkit.md。
Rules
Animated figures:
- Use only animate, animateTransform, and animateMotion; do not use setInterval or requestAnimationFrame in figures.
- Each figure has at most 55 SVG elements.
- Entrances go from opacity 0, scale 0.95 to opacity 1, scale 1, never starting from scale 0.
- Entrances use calcMode=spline,
keySplines="0.23 1 0.32 1", with a duration of 0.5 to 0.6 seconds. - Stagger entrances by 0.05 to 0.4 seconds; exits are shorter than entrances.
- Loops run 2.5 to 6 seconds with repeatCount=indefinite. Loops must not set fill=freeze; otherwise the runtime changes them to play once.
- keyTimes has the same number of entries as values, goes from 0 to 1, and is monotonically non-decreasing.
- keySplines has one fewer entry than keyTimes and may only be used with calcMode=spline.
- When animateMotion uses keyPoints, calcMode=linear, keyPoints has the same number of entries as keyTimes, and there is no values.
- Do not use var() for animated fill or stroke values. Overlay a target-color element and change its opacity.
- Loops only change opacity, transform, stroke-dashoffset, or path motion. Animations of x, y, x1, y1, x2, y2, width, height, r, cx, cy, rx, ry are changed by the runtime to run once.
- The frame specified by the host's data-static-time must be fully readable; the default is 1.5 seconds. Set it explicitly when the complete state appears only later.
- To scale an element around its center: draw the group's content around (0,0), move the group with translate, and scale with additive=sum.
Slider components:
- Write only ES5: use var, function expressions, and string concatenation; do not use arrow functions, let, const, or template strings.
- Define state._render before the first LF.slider or LF.select, because controls wrap it when created.
- In state._render, remove all SVG child elements and rebuild them; do not edit nodes in place.
- Create IDs only once, outside rendering. Attributes missing from new nodes are removed by the runtime, including IDs.
- Bars grow by length or by path stroke-dasharray, not by scale, because coordinated nodes scale around their center.
- Labels are short, lowercase in English, with units in parentheses, for example
chunk size (tokens). The Chinese page provides the corresponding translation.
Shared by both figure types:
- Colors come from CSS variables, using light values as defaults, for example
var(--blueprint,#3553ff). Use literal hex values only when no variable is available. - The main body may contain at most one accent color, blueprint; a secondary state may use warn; other parts use the ink and rule tokens.
- SVG text is at least 12 units, with font var(--font-mono). If it must be smaller, give the SVG at least 500px width and allow horizontal scrolling within the figure.
- Measure the actual font size on a phone. On a 375px screen, a 520-unit figure may be only 279px wide, so a 12-unit label is actually about 6.4px.
- The caption clearly explains each color. English sentences are at most 25 words; Chinese uses short sentences.
- lf-label is uppercase in English, two to four words, with a corresponding Chinese translation.
Mechanism figure, layer 2:
- Show real names and values such as file names, key names, and token counts; do not use item 1 or unnamed gray bars.
- Provide one main control: step, slider, toggle, play, or stop component.
- Finally output in text a conclusion computed from the figure's values; do not hard-code the result.
- Play once at 35% visibility, provide a replay button, and do not loop.
- Animate only transform and opacity, with easing
cubic-bezier(0.23, 1, 0.32, 1). Press 120 to 160ms, reveal 200 to 300ms, collapse 380 to 500ms. - Stagger each list item by 30 to 70ms, staggering only the first eight items.
- Labels are complete in every frame: no omission, no overlap, and no covering the dot matrix. Text is at least 11px; the conclusion is at least 12.5px.
- At 320px the panel is single-column, and control touch targets are 40px.
- Use a mechanism not used by other pages on the site, and register it in the mechanism table.
Dither field, layer 3:
- Read bg, blueprint, and ink, and redraw when data-theme changes.
- At most 30 frames per second, drawing only when visible.
- Draw a static frame when reduced motion is enabled. Show static diagonal hatching when WebGL is unavailable.
- The band is aria-hidden=true. Except for small label patches, place no text on the dot matrix.
Pre-completion checks
- The fence name exactly matches the registered name, and no other module has the same name.
- The module has no arrows, let, const, or template strings.
- Course figures have no setInterval or requestAnimationFrame.
- The smil-rules.md validator returns an empty array for mounted hosts.
- Each animated figure has at most 55 SVG elements.
- Loop durations are all between 2.5 and 6 seconds.
- Loops do not change the geometric properties from rule 11.
- Figures are complete under reduced motion, with no missing elements.
- All lines and labels are visible in dark mode.
- Labels are readable at 375px width, and the page outside the chart does not scroll horizontally.
- Slider at minimum and maximum shows no NaN, negative widths, or console errors.
- The SVG has one title and desc, and IDs remain unchanged after sliding.
- The caption explains each color.
- Layer 2 passes all checks in mechanism-figures.md.
- Layer 3 passes all checks in dither-fields.md.
Files
references/smil-rules.md: twelve SMIL rules, reasons, and browser validator.references/toolkit.md: LF function, mount order, complete slider and SMIL modules, off-site preview page.references/tokens.md: light/dark color scheme, fonts, animation duration.references/mechanism-figures.md: real names, counterexamples, mechanisms, structures, conclusions, animation budgets, and checks for Layer 2.references/dither-fields.md: shaders, four types of motion, markers, rules, dithering bars, and checks for Layer 3.templates/mechanism.html: an LRU cache mechanism diagram that can be opened directly in a browser, including capacity controls.templates/dither.js: the complete dithering script; after loading, add<div class="dither" data-seed="...">。
Also see in the repository site/lesson-figures.js runtime and site/figures-*.js for more charts.