asopi tech
asopi techIndie Developer
Embedding Animated Diagrams in Astro Markdown with Starch

[August 2026 edition]

Embedding Animated Diagrams in Astro Markdown with Starch

Published: Aug 19, 2026
Reading time: ~6 min

We introduced animation as a way to explain abstract concepts and complex processing flows more clearly in blog articles.

On this site, we added an <animated-diagram> component that displays diagrams defined with the Starch DSL in Markdown. This article presents the actual result and how we wrapped Starch for the site.

What is Starch?

Starch is a DSL for defining shapes, paths, and changes over time as text, then rendering an animated diagram in the browser from that definition.

Shapes and paths go in objects, and time-based changes go in animate. In the following example, a packet moves from the start of a path to its end over two seconds.

DSL

name "Starch basics"
background #071015
viewport 480x260

style routeStyle
  stroke #557c50 width=3

objects
  route: path (60,120) (420,120) @routeStyle
  packet: ellipse 24x24 fill #a6d65f pathFollow=route pathProgress=0
  start: text "start" size=14 fill #eaf4f6 at 60,165
  end: text "end" size=14 fill #eaf4f6 at 420,165

animate 2 loop easing=linear autoKey=false
  0 packet.transform.pathProgress: 0
  2 packet.transform.pathProgress: 1

Starch rendering result

objects defines the path and packet, while animate changes pathProgress from 0 to 1. Starch loads this definition and draws the animation into an SVG.

The problem was not whether an AI could implement the UI

Playback buttons and a seek bar were not the main reason for this change. A coding agent can implement a clearly specified UI. The recurring cost was translating every change in the meaning of a diagram into another set of low-level Canvas and GSAP edits.

Before the Starch migration, the two MCP animations, their shared playback code, and the video exporter occupied four files and 641 lines. Those files encoded all of the following as implementation details:

  • the 1072×720 composition and coordinates of every Agent, Router, Instance, database, and label
  • different polyline routes for the Stateful and Stateless sides
  • segment-by-segment packet interpolation and a composite packet that had to remain horizontal
  • A→B→C delivery in 0.8-second stages, a 2.4-second movement, and a 0.12-second hold
  • active borders, colors, glow, and progress labels switched at arrival points
  • separate states for authentication failure, token issuance, per-instance authorization, and database access
  • a renderAt(seconds) entry point that reproduced the same frame at an arbitrary time

In the first diagram, routes were coordinate arrays. packetAt() calculated each segment length and interpolated packet positions, while GSAP state thresholds such as .72 and .83 controlled when an Instance became active. The second diagram derived authorization timing from payloadSpeed = 160 and assembled rejection, authentication, authorization, and database access into separate timeline stages.

An AI can write this code. But every change to the visual explanation still required instructions for which route to follow, when each state changed, and what should be emphasized at that instant, followed by visual review of the generated result.

Starch changed the unit of instruction and review, not the coding capability. Structure and paths live in objects; state at each time lives in animate; the same time produces the same SVG. A change can therefore be reviewed as objects, routes, states, and time instead of as a Canvas API and timeline diff.

We have not demonstrated that moving to a DSL always makes the source short. The first dedicated component was 319 lines, while the revised vanilla Starch definition is still 160 lines. The second DSL is 377 lines. A diagram-specific ShapeSet or helper does not disappear from the cost merely because it moves to another file. What this migration has demonstrated is a declarative source for meaning and time, with deterministic reproduction from the same input and timestamp.

Loading a DSL instead of a video

Here is a diagram embedded in an article. Try dragging the seek handle.

The browser loads the DSL and draws the animation into an SVG. Rather than playing back a finished file the way a video does, it builds the diagram from the DSL definition and animates it.

So when you seek, Starch rebuilds the diagram for that position from the DSL. Unlike stepping through video frames, an intermediate state is drawn as it is.

Display it from Markdown

In this implementation, the article provides a custom element with the public DSL URL and a description of the diagram.

<animated-diagram
  src="https://example.com/diagram.starch"
  aria-label="A comparison of Stateful MCP and Stateless MCP"
  autoplay
></animated-diagram>

src provides the public DSL URL, and aria-label describes the diagram. The article only needs to provide the diagram definition and description.

How we wrapped Starch

We leave diagram rendering to Starch and add article-facing display and controls in this site’s component. When the custom element connects in the browser, it fetches the DSL and passes it to StarchDiagram.

The core of the implementation is:

const source = this.getAttribute('src');
if (!source) {
  this.showError(`${this.copy.failed} src is required.`);
  return;
}

const response = await fetch(source, { signal: this.abortController.signal });
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);

const dsl = await response.text();
this.diagram = new StarchDiagram(stage, {
  autoplay: false,
  onEvent: () => this.syncControls(),
});

const result = this.diagram.setDSL(dsl);
if (!result.ok) throw new Error(result.error);

this.dataset.ready = 'true';
this.dataset.warningCount = String(result.warnings.length);
this.dataset.duration = String(this.diagram.duration);
this.range.max = String(this.diagram.duration);

The wrapper fetches the DSL, connects StarchDiagram to the stage, and parses it with setDSL. It displays an error when parsing fails and passes the duration to the seek bar when parsing succeeds. Starch renders the SVG; our component handles the article-facing controls.

Features added as a component

This component groups the features that improve accessibility for animated diagrams and provide playback controls such as play, pause, and seeking:

  • play, pause, restart, seek, chapter navigation, and full-screen display
  • role="img", aria-label, labelled controls, and playback-status announcements
  • a still frame when prefers-reduced-motion is enabled
  • an error message when loading fails and fallback text when JavaScript is unavailable
  • responsive sizing and larger controls for pointer-based interaction

The Starch definition and description vary by diagram. Playback and accessibility behavior live in the shared component, so we do not reimplement the same behavior for each article.

Why VHS and Starch use different embed syntax

With VHS, the Astro build generates MP4, GIF, or PNG files from a VHS tape, then displays those generated files as HTML in the article. The browser plays or displays the generated files.

Starch loads a DSL in the reader’s browser instead of displaying a completed video. <animated-diagram> fetches the DSL, passes it to StarchDiagram, and draws the animation into an SVG in real time. The component also manages the live state, such as seeking and reduced motion.

For this reason, we use a Markdown video code block to specify generated VHS media, while we use a browser-side custom element for Starch. We show the Starch DSL in a code block so it is easy to read, and use <animated-diagram> for the actual animation.

Summary

On this site, we added a component that embeds Starch animation diagrams in Markdown so that abstract concepts and complex processing flows are easier to explain in articles.

  • Starch defines shapes, paths, and changes over time
  • the component loads the DSL and lets Starch render the SVG
  • the shared component provides controls, accessibility, and error display
  • MCP structure and state changes can be explained with an animation

References