01 / SEQUENCE CSS KEYFRAME CHOREOGRAPHY
A leads. B answers. C lands. The diagram never changes its meaning.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Choreography changes when attention arrives.
02 / TRACE SVG STROKE DRAWING / TIMED BY CSS
Keep the nodes still. Let the connection become the sentence.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Stroke drawing changes how a connection is discovered.
03 / TRAVEL DECLARATIVE SVG / ANIMATEMOTION
A single signal follows the same route. The browser handles the geometry.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Path motion changes where attention is carried.
04 / REVEAL CSS MASK / SOFT-EDGE WIPE
A moving aperture exposes the highlight. Nothing underneath changes position.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
A mask changes what is visible through a window.
NEXT CUT / A custom Marp clip-path aperture opens the next slide.
05 / TILT CSS 3D TRANSFORMS
Tilt the plane. Lift B toward the viewer. Return to a readable, flat frame.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Perspective changes what feels closer.
06 / FLIP THROUGH FRAMES SPRITE SHEET / CSS STEPS
The same specimen, baked into a strip of images. No shape is interpolated live.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Frame animation changes which still is on screen.
07 / PLAY THE RENDER LOCAL VIDEO / MOTION GRAPHICS
The motion was rendered before the talk. The browser only decodes the clip.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Video changes who does the rendering, and when.
08 / PLAY AUTHORED VECTORS LOTTIE / LOCAL JAVASCRIPT RENDERER
The same motif is authored as vector layers. A player renders the in-between frames.
STILL FRAME / A connects to B, then C. Motion adds emphasis, not information.
Authored vectors change how motion is handed off.
NEXT CUT / Marp's built-in slide transition. Then compare a shared-element morph.
09 / MORPH STATE A / OVERVIEW
This slide is still. Press the right arrow to give B the stage.
A morph changes layout without losing identity.
09 / MORPH STATE B / FOCUS
The object persists. Its role in the composition changes.
Two readable slides. One continuous object.
THE DESIGN RULE CHOOSE THE RELATIONSHIP FIRST
Then choose live geometry,
authored vectors, or pixels.
Play once. Pause. Replay.
Honor reduced motion.
If the animation vanishes,
the idea must remain.
Different mechanisms. The same controls and complete stills. Marp connects the slides.
This is a lab about animation techniques, not a simulation of another engineering system. A, B, and C are an intentionally neutral specimen: start, shape, land. The same positions, dimensions, connecting path, and labels recur in the next eight experiments. Only the motion mechanism changes. The morph pair then changes layout while keeping the identities. Every slide is understandable as a still. Animations start manually, run once, and can be paused or replayed in the audience window. CSS and native SVG interpolate the first examples. Frames and video are pre-rendered, and Lottie requires a locally packaged JavaScript vector renderer. Shared JavaScript manages playback, slide activation, and accessibility; Marp itself also uses JavaScript. None of these examples claim "no JavaScript anywhere." The opening boundary visibly demonstrates Marp's built-in cover transition.
The three HTML node cards share the ml-lift CSS keyframes, delayed by 0, 1, and 2 seconds. Each gesture lasts 2 seconds, so the whole sequence ends at 4 seconds. Only transform and box-shadow change; labels and the connecting path stay visible. The JavaScript toggles playback classes and holds native CSSAnimation clocks. CSS, not JavaScript, interpolates the frames. Pause holds the CSS clock immediately, even when Marp hides its SVG before the next paint. Replay restarts it. Source: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations
The SVG path has pathLength="1". CSS sets stroke-dasharray: 1 and animates stroke-dashoffset from 1 to 0 over four seconds. This is SVG geometry with a CSS animation, not SMIL and not a JavaScript path-length calculation. A muted full route remains underneath, including in the starting frame. The static and print states show the entire colored route. Pausing freezes the drawn length. Source: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pathLength Source: https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-dashoffset
The signal is a native SVG animateMotion element (SMIL). begin="indefinite" stops it from running on every hidden slide when the document opens. beginElement starts it; pauseAnimations and unpauseAnimations control the SVG clock. JavaScript never computes positions. The signal follows the visible route between the outer cards, passing behind B, and repeatCount="1" makes it finite. The sibling animation uses an explicit href target; this also avoids HTML normalization treating a nested SVG circle as an empty element during export. CSS animation-play-state does not pause SMIL: it needs its own SVG clock methods. Print, no-JS, reduced-motion, and presenter views hide the moving signal and show a separate authored static marker. Changing browser motion preferences resets it. Source: https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animateMotion Source: https://developer.mozilla.org/en-US/docs/Web/API/SVGSVGElement/pauseAnimations
The overlay SVG contains only colored connector segments and card outlines. Its CSS alpha mask is a wide black-to-transparent linear gradient. Animating mask-position from 100% to 0% exposes the overlay left-to-right; a soft gradient edge distinguishes this mask from a hard clip-path wipe. The underlying diagram, especially the labels, stays complete and stationary. At rest, in print, and without JavaScript the mask is removed, showing all ink. Masks can add painting/compositing work; do not assume every effect is GPU-only. The next slide boundary is a separate custom Marp transition, ml-aperture. Its clip-path keyframes create a hard-edged opening across the complete slide. Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mask-position
This is CSS 3D, not WebGL. An HTML parent supplies perspective; the diagram plane uses transform-style: preserve-3d. CSS rotates the plane around X/Y and translates B along Z. All frames come from CSS keyframes, with a finite four-second duration. Overflow, filters, opacity, and other grouping properties on a preserve-3d parent can flatten descendants. The plane avoids them. The surrounding slide still has Marp's SVG/foreignObject wrapper; verify the actual export, not just a plain div. The final, print, reduced-motion, no-JS and presenter states are flat and readable. Source: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style Source: https://developer.mozilla.org/en-US/docs/Web/CSS/perspective
This is a real PNG sprite sheet: twelve 680 by 300 cells laid out horizontally. CSS background-position advances from 0 to -7480px with steps(11, end), preserving the first and last cells. There is no smoothing or JavaScript frame selection. The deliberately low frame count makes the stepped character visible. The next slide uses the same authored gesture in a pre-rendered 30 fps clip. Original artwork and source: assets/motion-lab/specimen.svg. Regenerate the sprite, video, and authored Lottie data with npm run motion:assets. No stock media is used. Source: https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function/steps
The repository contains a real, original VP9 WebM clip, recorded offline at 30 fps from the specimen SVG with Chromium's Canvas/MediaRecorder APIs. Its frame gesture matches the sprite example, but it contains many more encoded frames. No animation loop renders this slide live: HTMLMediaElement decodes the local file. Playback uses the common buttons and media play/pause/currentTime/ended APIs. There is no audio; the accessible description and static poster describe the full content, so there is no missing spoken information or caption track. VP9 WebM is verified in Chromium. Codec support and decoding can vary; the poster remains available and a decode/load failure is explicitly reported. Source: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video
This is a genuine Lottie composition rendered by the locally packaged MIT-licensed lottie-web 5.13.0 SVG light player, not a screenshot, video, or CSS imitation. The original composition contains vector card/letter outlines, authored rotation and scale keyframes, and a trimmed route stroke. Its author-time data is generated in scripts/generate-motion-assets.mjs; it was not exported from After Effects. Lottie represents the designer-authored vector family in this lab; Rive is another option, not an additional runtime required here. Supported export features vary. The player runs JavaScript internally. This slide deliberately makes no CSS-only or no-JavaScript claim. It loads locally only when this audience slide is active. Use the local HTTP preview or Pages, not file://, to load the composition JSON. Only this repository's trusted original JSON is rendered, not user-supplied data. Source and license: https://github.com/airbnb/lottie-web/tree/v5.13.0
The next boundary uses Marp's fade transition with a 1400ms duration. A, B, and C each have a unique view-transition-name on both slides. The View Transition API interpolates their captured geometry while unnamed elements, including the route, cross-fade. A morph is NOT SVG path interpolation; this route is deliberately not named. No custom JavaScript is used for this transition. Each name must be unique within a visible slide or the whole transition can fail. Verified in Chromium; Marp documents Safari SVG/foreignObject-related limitations. Unsupported browsers still navigate. Reduced motion removes the shared names and lets Marp use its simple fade. Each PDF page is an independently complete layout. Source: https://github.com/marp-team/marp-cli/blob/v4.5.1/docs/bespoke-transitions/README.md#morphing-animations
Compare B's rendered position and size with the previous slide. The visible motion must come from the named view-transition group, not just the whole-slide fade. The transition also works backward with the left arrow. Nothing animates between navigations, and there is no timer or simulation state to keep synchronized. A and C retain their own stable names as well, so three shared elements morph. In browsers without the API, both layouts still display and the arrow keys work. Do not claim universal cross-browser morph fidelity.
Compare a technique because it changes the audience's understanding, not because it adds movement. The examples are intentionally finite and manually started. The shared runtime manages CSS classes, SVG/media/player clocks, completion events, and visibility. Only the Lottie example adds an animation library. Everything is packaged locally; all artwork, frame sequences, and video are original. The motif lives in this Markdown and assets/motion-lab/specimen.svg; opt-in ml classes live in themes/motion-lab.css and controls in assets/motion-lab.js. The custom-default theme composes the scoped stylesheet without changing the CI/CD deck. Use the audience window for controls; presenter previews stay static.