name: wcygan-graphic-demos description: Use when creating, editing, reviewing, or debugging wcygan.net article graphic demos, including Canvas 2D engines, SVG/DOM diagrams, Leaflet maps, ASCII flipbooks, MDX embeds, src/demos model state, demo CSS, accessibility text, reduced-motion behavior, and desktop/mobile visual verification.
wcygan.net Graphic Demos
Goal: Build and maintain article-native graphic demos that explain one concrete software or data-systems idea through inspectable state, clear motion, and responsive presentation.
Success means:
- The demo teaches one invariant or concept that the surrounding prose names.
- The implementation follows the local shape for its complexity: React article shell, deterministic model, renderer, lifecycle, CSS, and tests when state is meaningful.
- The rendered figure works in the MDX post, stays readable on mobile, respects reduced motion, and exposes useful accessibility text.
Stop when the demo source, post embed, styling, and verification evidence all agree with the concept being taught.
Reference Map
references/ui-motion-polish.md: Read before adding, tuning, or reviewing demo motion, micro-interactions, animation timing, easing, gesture behavior, reduced-motion handling, or animation performance.references/ui-design.md: Read when a demo needs a broader visual polish pass, interaction review, component feel audit, or concrete Before/After feedback on design details.references/canvas-rendering-lifecycle.md: Read before implementing or reviewing Canvas 2D renderers,requestAnimationFrameengines, DPR sizing, offscreen/layered canvases, and frame cleanup.references/web-animation-techniques.md: Read before choosing CSS transitions, CSS animations, or the Web Animations API for demo UI motion.references/playwright-visual-verification.md: Read before writing or running Playwright screenshot checks for rendered article demos.
Start Here
Trace the post first. Open the MDX file that imports the component, read the paragraph before and after the embed, and state the concept in one sentence.
Name the invariant before editing code. Good examples in this repo include:
- Entity routing: writes for an account route to the region that owns that account.
- Replication lag: a healthy-looking replica can return an older version during failover.
- Optimistic locking: the row version read earlier must still match at update time.
- Consistent hashing: adding a node moves only the keys whose next clockwise token changes.
Choose the representation that makes the invariant easiest to inspect:
- Use Canvas 2D for animated packet flows, timelines, logs, rings, replay, and dense state diagrams.
- Use SVG for small vector diagrams with a fixed number of labels and paths.
- Use DOM/CSS for compact controls, bars, tables, chips, and stateful article widgets.
- Use Leaflet for real map tiles.
- Use ASCII flipbooks for generated frame data from
src/data/*.json. - Use static Mermaid SVGs for diagrams authored in
src/diagrams/<slug>/*.mmdand compiled intopublic/<slug>/*.svg.
Demo Option Types
Classify a demo along two axes before implementation: how state advances, and what the reader can manipulate. Prefer the simplest option that exposes the post's invariant without extra controls.
- Continuous phase loop: a
progressvalue from 0 to 1 drives named phases, moving packets, labels, and status. Use for routing, replication, retries, workflow execution, crash recovery, replay, and other flows where motion itself explains causality. - Discrete autoplay or step-wise: an integer
stepIndexadvances one state at a time, often with clickable stage markers. Use when the reader should compare named moments instead of track sub-frame motion. - Scenario selection: buttons or tabs switch between a small set of alternatives such as option A versus option B, query shapes, rebalance strategies, failure modes, or partition keys. Use when the teaching goal is comparison.
- Parameterized model: sliders, steppers, or small inputs change model parameters and recompute the figure immediately. Use for rings, load distribution, fanout, thresholds, and other demos where the invariant emerges from changing values.
- Live action or async probe: a button triggers real work and the UI moves through idle, pending, success, and failure states. Use when the article needs inspectable runtime evidence rather than a simulation.
- Spatial reference: a map, topology, or fixed diagram anchors a concept in geography or structure. Use when location, ownership, or topology matters more than elapsed time.
- Static reference or gallery: a stable visual inventory gives context without progression. Use when interaction would distract from recognition or scanning.
- Ambient loop: lightweight decorative or identity motion with no explanatory model. Keep this rare and make reduced motion settle to a static frame.
Keep the house contract consistent across types: name the invariant, name the option type, define the progression source, expose only useful controls, provide status text when state changes, and choose a reduced-motion state that still teaches the same idea.
Local Architecture
Prefer the model-backed shape when a demo has time, phases, packets, ownership, or meaningful derived state:
src/components/ExampleDemo.tsx
src/demos/example/model.ts
src/demos/example/engine.ts
src/demos/example/render-canvas.ts
src/demos/example/viewport.ts
src/demos/example/model.test.ts
Use these responsibilities:
- React component: article markup, header copy, controls, refs, lifecycle,
aria-label, timeline/status DOM, anddata-phaseattributes. - Model: domain state, typed snapshots, phase definitions, labels, semantic status, clamps/easing, and testable derived values.
- Engine:
requestAnimationFrame,ResizeObserver,IntersectionObserverwhen useful, page visibility, reduced-motion defaults, cleanup, and snapshot callbacks. - Renderer: pure drawing from snapshot plus viewport, with named geometry and semantic colors.
- CSS: figure frame, layout, controls, legends, responsive breakpoints, and reduced-motion behavior.
Keep small one-off demos in one component when the state is simple and the split
would add ceremony. GeoDnsRoutingDemo, ConsistentHashingRingCanvasDemo,
ShardingPartitioningDemos, and the ASCII components are valid local examples
of component-local models.
Motion And Lifecycle
Build the first frame to teach something before the animation advances.
Before changing motion, translate the request into a motion contract: purpose,
pattern, timing, easing or physics, spatial rule, feedback behavior, performance
constraint, and reduced-motion fallback. Use references/ui-motion-polish.md
for the concrete vocabulary and thresholds.
Map time to named phases. Use typed phase identifiers, phaseLabel, and
timeline state helpers when the reader needs to follow a sequence.
Run motion only after mount. Access window, document, canvas contexts,
Leaflet, matchMedia, and observers inside effects or engines.
Respect reduced motion by showing a useful settled state, final state, or single representative step. Keep the same invariant visible without playback.
Pause work when the page is hidden. For long-running Canvas demos, stop the loop
when document.hidden is true and resume or render when visible again.
Clean up every animation frame, observer, media-query listener, event listener,
interval, and map instance in the returned effect or engine destroy() method.
Accessibility And Article Fit
Place each demo in a <figure> with a concise header or nearby prose that names
the concept. Add a figcaption, legend, timeline, or status text when color or
motion carries meaning.
Write aria-label, <title>, or <desc> text that describes the actual state
transition. Name the actors, states, and outcome that the reader would see.
Expose controls with native inputs and labels. Use aria-live for derived
metrics that update from user interaction.
Keep the demo inside the post rhythm. Use existing src/styles/app.css demo
families, semantic colors, and the mobile-first acceptance bar from AGENTS.md.
Styling Patterns
Use semantic colors consistently:
- Blue for primary actions, selected paths, active regions, and source systems.
- Gold for moving packets, probes, highlighted paths, and active focus.
- Green for healthy, available, committed, current, or successful state.
- Red for failure, stale state, conflict, rejected writes, deletes, and changed ownership when the prose calls it out.
- Muted gray for supporting UI, inactive lines, grid planes, and labels.
Build geometry from named points, paths, ports, constants, and shared layout objects. Keep connector paths and moving packets derived from the same geometry.
Give fixed-format surfaces stable dimensions with aspect-ratio, explicit CSS
height, or viewport-aware canvas sizing so labels, hover states, and animation
keep the layout stable.
Verification
Run the narrowest useful checks for the change:
- Model or phase edits:
deno task test src/demos/<name>/model.test.ts. - Shared renderer edits: run the matching renderer/model tests when present.
- Type or component edits:
deno task typecheck. - Broad demo or post edits:
deno task pre-commit.
Inspect the rendered post when visuals change. Check desktop and a phone-width viewport. Confirm the canvas or SVG is nonblank, labels fit, controls work, and horizontal overflow stays at zero.
Check reduced motion for demos with playback. Confirm the representative state still teaches the invariant.
Before finishing, report which source files changed, which route or post owns the demo, and which checks or browser views proved the result.