Use this when a static diagram can't show movement — when the lesson is about what happens, in what order. Here: a web request travels through a load balancer to one of three app servers, with Play / Pause / Step controls.
This is a copyable exemplar, not a finished lesson. Lift the <section id="player"> block (and its slice of CSS + the <script>) into a real lesson built from assets/lesson-template.html — drop it where the template's id="try-it" demo goes.
When a lot of people hit a busy website at once, no single computer answers everyone. A load balancer sits at the front door and hands each visitor's request to whichever back-end computer is least busy. The visitor never notices — they just get an answer.
A picture of boxes and arrows can show that this happens, but not the order it happens in. This demo lets you press Play and actually watch one request travel: in to the front door, out to a chosen server, the work gets done, and an answer comes back. Press Step to walk it one beat at a time.
Think of it like… a host at a busy restaurant. People arrive at the door (the load balancer), and the host glances around and seats each party at whichever table (app server) has a free waiter — so no single waiter gets buried while others stand idle.
The load balancer is a reverse proxy (e.g. Nginx, HAProxy, or a managed L7 ALB) terminating the client connection and opening its own connection to a chosen upstream. Selection here is least-connections; round-robin and weighted variants are common. A periodic health check removes an unhealthy upstream from the pool, so the chosen server is always one that recently passed a probe.
The "answer comes back" beat is the response flowing back along the same proxied connection. In practice the app server may also touch a shared database or cache before responding — omitted here to keep the running example to one request, one round trip.
Press Play to run it end to end, Pause to freeze, or Step to advance one beat. The chosen server lights up; Reset reshuffles which server gets picked.
Ready. The load balancer will pick a server when you press Play or Step.
The motion is a tiny finite state machine in vanilla JS — four phases: arrive, route, process, respond. Each Step advances one phase and tweens the token's cx/cy with requestAnimationFrame and an ease-in-out curve. Play just auto-fires the next step on a timer; Pause clears the timer. There is no <video>, no GIF, no library — so it scrubs, steps, and resets deterministically.
A static SVG (the architecture pattern in svg-patterns.md) answers "what's connected." Animation answers "in what order, and which path this time." Reach for this demo type only when sequence or timing is the lesson; otherwise a labelled still costs less and reads faster.
The whole sequence is narrated in the aria-live="polite" caption, so a screen-reader user hears each beat without seeing motion. Controls are real <button>s, and prefers-reduced-motion drops the tweens to instant jumps.
The engine is small: a list of phases, a function that moves one token from A to B, and three buttons calling step(), play(), reset(). Here is the heart of it (the full version is the <script> at the bottom of this file).
// four ordered phases — the whole "process over time" const PHASES = ['arrive', 'route', 'process', 'respond']; let phase = -1, chosen = pickServer(); // which app server this run function step() { if (phase >= PHASES.length - 1) return done(); phase++; render(phase, chosen); // tween token + light up nodes } function play() { // auto-fire the next step on a timer timer = setInterval(() => phase < PHASES.length - 1 ? step() : pause(), 1100); }