Animating with SMIL

SVG's animation elements come from SMIL (Synchronized Multimedia Integration Language). <animate> moves one attributeName from/to values or through a values list over dur; repeatCount="indefinite" loops and fill="freeze" keeps the end. <set> jumps, <animateTransform type="rotate"> animates a transform, and <animateMotion> follows a path (<mpath href>), turning with rotate="auto". begin takes times and events (2s, click, intro.end+0.5s); keyTimes and keySplines shape the pacing.

A book flying along a path while it changes color, at four timesHTMLLive
<svg id="anim" width="140" height="102" font-family="Arial" font-size="12">
  <path id="trail" d="M15 85Q70-25 125 85" fill="none" stroke="#bbb" stroke-dasharray="4"/>
  <rect x="-12" y="-8" width="24" height="16" rx="2" fill="#1f5f8b">
    <animateMotion dur="2s" repeatCount="indefinite" rotate="auto">
      <mpath href="#trail"/></animateMotion>
    <animate attributeName="fill" values="#1f5f8b;#e09a10;#1f5f8b" dur="2s"
      repeatCount="indefinite"/></rect>
  <text x="70" y="100" text-anchor="middle">t = 0 s</text>
</svg>
<script>
  for (const t of [0.5, 1, 1.25]) {
    const copy = anim.cloneNode(true); copy.id = '';
    copy.querySelector('text').textContent = `t = ${t} s`;
    document.body.append(copy);
    copy.pauseAnimations(); copy.setCurrentTime(t);
  }
  anim.pauseAnimations(); anim.setCurrentTime(0);
</script>
Browser output of Listing 1.30
Browser output of 30

Each outer <svg> has its own SMIL clock, which pauseAnimations() stops and setCurrentTime() seeks. Motion is paced by default, so at 0.5 s the book has covered a quarter of the arc's length. beginElement() and endElement() start and stop one animation from script.