{
  "kind": "code",
  "model": "gemini-4-argon",
  "generatedAt": "2026-10-21T05:31:39.409Z",
  "prompt": "Turn the attached Attention Is All You Need paper by Vaswani et al. (2017), arXiv 1706.03762, into a four-chapter illustrated interactive storybook about attention and the Transformer. Use original concise paraphrases, no more than 160 words of factual explanation in total. Cite paper page and section numbers beside the claims. Label fictional characters and analogies, preserve limitations, avoid performance superlatives and benchmark numbers. Black and white inline SVG illustrations, chapter buttons, reduced motion and no external resources. Return JSON {title,content:\"complete self-contained HTML document\"}. Include only inline scripts, CSS and inline SVG or canvas, no external libraries, URLs, network access or imports. Make the example polished, responsive, keyboard and touch usable. Support prefers-reduced-motion and pause animation when document.hidden. Include meaningful accessible text. Never claim tests were run. Keep implementation concise under 18000 characters.",
  "sourceDocument": {
    "title": "Attention Is All You Need",
    "url": "https://arxiv.org/abs/1706.03762",
    "pdf": "https://arxiv.org/pdf/1706.03762",
    "authors": "Vaswani et al.",
    "year": 2017
  },
  "sourceImage": null,
  "scope": "Direct real Vertex generation with production schema validation and JavaScript syntax checks. Not an account, billing or browser interaction test.",
  "usage": {
    "promptTokenCount": 19268,
    "candidatesTokenCount": 9448,
    "totalTokenCount": 28716,
    "trafficType": "ON_DEMAND",
    "promptTokensDetails": [
      {
        "modality": "IMAGE",
        "tokenCount": 7800
      },
      {
        "modality": "TEXT",
        "tokenCount": 11468
      }
    ],
    "candidatesTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 9448
      }
    ]
  },
  "output": {
    "title": "The Weaver's Loom: An Interactive Storybook of the Transformer",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>The Weaver's Loom: Attention & The Transformer</title>\n<style>\n  :root {\n    --bg: #ffffff;\n    --fg: #111111;\n    --muted: #555555;\n    --border: #000000;\n    --accent-bg: #f4f4f4;\n  }\n  * { box-sizing: border-box; }\n  body {\n    margin: 0;\n    padding: 0;\n    background: var(--bg);\n    color: var(--fg);\n    font-family: 'Georgia', 'Times New Roman', serif;\n    line-height: 1.6;\n    display: flex;\n    flex-direction: column;\n    min-height: 100vh;\n  }\n  header {\n    border-bottom: 2px solid var(--border);\n    padding: 1rem 1.5rem;\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: space-between;\n    align-items: center;\n    gap: 1rem;\n  }\n  h1 {\n    margin: 0;\n    font-size: 1.35rem;\n    letter-spacing: 0.02em;\n  }\n  .subtitle {\n    font-size: 0.85rem;\n    color: var(--muted);\n    font-family: monospace;\n  }\n  .controls {\n    display: flex;\n    gap: 0.5rem;\n    align-items: center;\n  }\n  button {\n    background: var(--bg);\n    color: var(--fg);\n    border: 2px solid var(--border);\n    padding: 0.4rem 0.8rem;\n    font-family: monospace;\n    font-size: 0.85rem;\n    font-weight: bold;\n    cursor: pointer;\n    transition: background 0.15s, color 0.15s;\n  }\n  button:hover, button:focus-visible {\n    background: var(--fg);\n    color: var(--bg);\n    outline: none;\n  }\n  button[aria-current=\"step\"], button.active {\n    background: var(--fg);\n    color: var(--bg);\n  }\n  button:disabled {\n    border-color: #aaa;\n    color: #aaa;\n    cursor: not-allowed;\n    background: var(--bg);\n  }\n  nav {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 0.5rem;\n    padding: 0.75rem 1.5rem;\n    border-bottom: 1px solid var(--border);\n    background: var(--accent-bg);\n  }\n  main {\n    flex: 1;\n    max-width: 960px;\n    width: 100%;\n    margin: 0 auto;\n    padding: 1.5rem;\n    display: grid;\n    grid-template-columns: 1fr;\n    gap: 1.5rem;\n  }\n  @media (min-width: 768px) {\n    main {\n      grid-template-columns: 1.1fr 0.9fr;\n      align-items: start;\n    }\n  }\n  .illustration-box {\n    border: 2px solid var(--border);\n    padding: 1rem;\n    background: var(--bg);\n    display: flex;\n    flex-direction: column;\n    gap: 0.75rem;\n  }\n  svg {\n    width: 100%;\n    height: auto;\n    max-height: 340px;\n    display: block;\n    border: 1px solid #ddd;\n    background: #fff;\n  }\n  .interactive-bar {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 0.5rem;\n    align-items: center;\n    justify-content: space-between;\n    font-family: monospace;\n    font-size: 0.85rem;\n    padding-top: 0.5rem;\n    border-top: 1px dashed var(--border);\n  }\n  .story-box {\n    display: flex;\n    flex-direction: column;\n    gap: 1rem;\n  }\n  .chapter-title {\n    margin: 0;\n    font-size: 1.5rem;\n    border-bottom: 2px solid var(--border);\n    padding-bottom: 0.3rem;\n  }\n  .badge {\n    display: inline-block;\n    font-family: monospace;\n    font-size: 0.75rem;\n    text-transform: uppercase;\n    border: 1px solid var(--border);\n    padding: 0.1rem 0.4rem;\n    margin-right: 0.4rem;\n    background: var(--accent-bg);\n    font-weight: bold;\n  }\n  .analogy-card {\n    border-left: 3px solid var(--border);\n    padding: 0.5rem 0 0.5rem 1rem;\n    background: var(--accent-bg);\n    margin: 0;\n    font-style: italic;\n  }\n  .fact-card {\n    border: 2px solid var(--border);\n    padding: 1rem;\n    margin: 0;\n    background: var(--bg);\n  }\n  .cite {\n    font-family: monospace;\n    font-size: 0.8rem;\n    background: var(--accent-bg);\n    border: 1px solid var(--border);\n    padding: 0.05rem 0.3rem;\n    font-style: normal;\n    white-space: nowrap;\n  }\n  .pager {\n    display: flex;\n    justify-content: space-between;\n    margin-top: 0.5rem;\n    padding-top: 1rem;\n    border-top: 1px solid var(--border);\n  }\n  footer {\n    border-top: 2px solid var(--border);\n    padding: 0.75rem 1.5rem;\n    font-family: monospace;\n    font-size: 0.8rem;\n    display: flex;\n    justify-content: space-between;\n    flex-wrap: wrap;\n    gap: 0.5rem;\n    background: var(--accent-bg);\n  }\n  /* Animations */\n  @keyframes pulseDash {\n    to { stroke-dashoffset: -24; }\n  }\n  @keyframes floatNode {\n    0%, 100% { transform: translateY(0px); }\n    50% { transform: translateY(-4px); }\n  }\n  .anim-dash {\n    stroke-dasharray: 6 6;\n    animation: pulseDash 1.2s linear infinite;\n  }\n  .anim-float {\n    animation: floatNode 2.5s ease-in-out infinite;\n  }\n  body.paused .anim-dash,\n  body.paused .anim-float {\n    animation-play-state: paused !important;\n    stroke-dasharray: none;\n  }\n  @media (prefers-reduced-motion: reduce) {\n    .anim-dash, .anim-float {\n      animation: none !important;\n    }\n  }\n</style>\n</head>\n<body>\n\n<header>\n  <div>\n    <h1>The Weaver's Loom: A Storybook of the Transformer</h1>\n    <div class=\"subtitle\">Based on Vaswani et al. (2017), \"Attention Is All You Need\" (arXiv:1706.03762)</div>\n  </div>\n  <div class=\"controls\">\n    <button type=\"button\" id=\"motionBtn\" aria-pressed=\"false\">Pause Motion</button>\n  </div>\n</header>\n\n<nav aria-label=\"Chapter Navigation\">\n  <button type=\"button\" class=\"chap-btn active\" data-chap=\"0\" aria-current=\"step\">Ch 1: The Sequential Chain</button>\n  <button type=\"button\" class=\"chap-btn\" data-chap=\"1\">Ch 2: The Loom of Attention</button>\n  <button type=\"button\" class=\"chap-btn\" data-chap=\"2\">Ch 3: Twin Towers & Waves</button>\n  <button type=\"button\" class=\"chap-btn\" data-chap=\"3\">Ch 4: Horizons & Limits</button>\n</nav>\n\n<main id=\"mainContent\" tabindex=\"-1\">\n  <section class=\"illustration-box\" aria-label=\"Interactive Illustration\">\n    <div id=\"svgContainer\" role=\"region\" aria-live=\"polite\"></div>\n    <div class=\"interactive-bar\" id=\"interactiveControls\"></div>\n  </section>\n\n  <section class=\"story-box\" aria-live=\"polite\">\n    <h2 class=\"chapter-title\" id=\"chapTitle\"></h2>\n    <div class=\"analogy-card\">\n      <span class=\"badge\">Fictional Character & Analogy</span>\n      <span id=\"analogyText\"></span>\n    </div>\n    <div class=\"fact-card\">\n      <span class=\"badge\">Factual Explanation</span>\n      <p id=\"factText\" style=\"margin:0.5rem 0 0 0;\"></p>\n    </div>\n    <div class=\"pager\">\n      <button type=\"button\" id=\"prevBtn\">&larr; Previous</button>\n      <button type=\"button\" id=\"nextBtn\">Next &rarr;</button>\n    </div>\n  </section>\n</main>\n\n<footer>\n  <span>Use Left/Right arrow keys or buttons to turn pages.</span>\n  <span id=\"wordCountDisplay\">Factual explanation word count: --</span>\n</footer>\n\n<script>\n(function() {\n  const chapters = [\n    {\n      title: \"Chapter 1: The Bucket Brigade & The Direct Thread\",\n      analogy: \"Fictional scribe Chronos passes buckets of ink one by one down a long line, waiting for each step before starting the next. Fictional weaver Aria instead stretches threads across her loom, linking any two words directly at the same time.\",\n      factHtml: `Recurrent models process symbols step-by-step, computing hidden state <i>h<sub>t</sub></i> from <i>h<sub>t-1</sub></i>, which prevents parallel training across sequence positions <span class=\"cite\">[p.2, §1]</span>. Convolutional models require stacked layers where operations between distant positions grow linearly or logarithmically <span class=\"cite\">[p.2, §2]</span>. The Transformer removes recurrence and convolutions, using self-attention to connect any two positions in a constant number of operations <span class=\"cite\">[p.1, Abs; p.2, §2]</span>.`,\n      factPlain: \"Recurrent models process symbols step-by-step, computing hidden state ht from ht-1, which prevents parallel training across sequence positions. Convolutional models require stacked layers where operations between distant positions grow linearly or logarithmically. The Transformer removes recurrence and convolutions, using self-attention to connect any two positions in a constant number of operations.\",\n      controlLabel: \"Mode:\",\n      controlBtn: \"Toggle: Sequential vs Self-Attention\"\n    },\n    {\n      title: \"Chapter 2: The Council of Eight Lenses\",\n      analogy: \"To match threads, Aria holds up a Query lantern to Key mirrors, blending Value spools. When bright lanterns washed out the shadows, she dimmed them with a scale filter, then split her lantern into eight smaller lenses so they wouldn't blur together.\",\n      factHtml: `Attention maps query, key, and value vectors to weighted sums <span class=\"cite\">[p.3, §3.2]</span>. Large key dimensions (<i>d<sub>k</sub></i>) cause large dot products that push softmax into tiny-gradient regions, so dot products are scaled by 1/&radic;<i>d<sub>k</sub></i> <span class=\"cite\">[p.4, §3.2.1]</span>. Averaging in a single attention head reduces effective resolution; Multi-Head Attention projects queries, keys, and values into <i>h</i>=8 parallel subspaces to attend to diverse positions <span class=\"cite\">[p.2, §2; p.4–5, §3.2.2]</span>.`,\n      factPlain: \"Attention maps query, key, and value vectors to weighted sums. Large key dimensions (dk) cause large dot products that push softmax into tiny-gradient regions, so dot products are scaled by 1/√dk. Averaging in a single attention head reduces effective resolution; Multi-Head Attention projects queries, keys, and values into h=8 parallel subspaces to attend to diverse positions.\",\n      controlLabel: \"Inspect Head:\",\n      controlBtn: \"Switch Lens: Averaged vs Multi-Head\"\n    },\n    {\n      title: \"Chapter 3: Twin Towers, Ripples & The Blindfold\",\n      analogy: \"Aria builds two six-story towers. Since her parallel loom has no sense of time, she stamps each thread with wave-ripples at the base. In the second tower, she wears a one-way blindfold so she cannot peek at future threads not yet woven.\",\n      factHtml: `The architecture stacks <i>N</i>=6 identical encoder and decoder layers containing self-attention, position-wise feed-forward networks, residual connections, and layer normalization <span class=\"cite\">[p.3, §3.1]</span>. Without recurrence, sinusoidal or learned positional encodings are added to input embeddings to represent token order <span class=\"cite\">[p.6, §3.5]</span>. Decoder self-attention masks future positions (setting softmax inputs to &minus;&infin;) to preserve auto-regressive generation <span class=\"cite\">[p.3, §3.1; p.5, §3.2.3]</span>.`,\n      factPlain: \"The architecture stacks N=6 identical encoder and decoder layers containing self-attention, position-wise feed-forward networks, residual connections, and layer normalization. Without recurrence, sinusoidal or learned positional encodings are added to input embeddings to represent token order. Decoder self-attention masks future positions (setting softmax inputs to -∞) to preserve auto-regressive generation.\",\n      controlLabel: \"Decoder Step:\",\n      controlBtn: \"Advance Auto-Regressive Mask\"\n    },\n    {\n      title: \"Chapter 4: Tangled Tapestries & Uncharted Looms\",\n      analogy: \"When a tapestry grows extraordinarily long, Aria's loom demands a massive grid of crossing threads. Moreover, shrinking her key mirrors blurs her aim, and weaving final output knots still happens one thread at a time.\",\n      factHtml: `Self-attention complexity is <i>O(n<sup>2</sup>&middot;d)</i> per layer; it is faster than recurrent layers when sequence length <i>n</i> is smaller than dimension <i>d</i>, but very long sequences may require restricting attention to local neighborhoods of size <i>r</i>, increasing path length to <i>O(n/r)</i> <span class=\"cite\">[p.6–7, §4, Table 1]</span>. Too many heads or small <i>d<sub>k</sub></i> hurts quality <span class=\"cite\">[p.9, §6.2]</span>, and making generation less sequential remains future work <span class=\"cite\">[p.10, §7]</span>.`,\n      factPlain: \"Self-attention complexity is O(n²·d) per layer; it is faster than recurrent layers when sequence length n is smaller than dimension d, but very long sequences may require restricting attention to local neighborhoods of size r, increasing path length to O(n/r). Too many heads or small dk hurts quality, and making generation less sequential remains future work.\",\n      controlLabel: \"Sequence Mode:\",\n      controlBtn: \"Toggle: Full O(n²) vs Restricted O(r·n)\"\n    }\n  ];\n\n  let currentChap = 0;\n  let subState = 0;\n  let userPaused = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n  const chapBtns = document.querySelectorAll('.chap-btn');\n  const prevBtn = document.getElementById('prevBtn');\n  const nextBtn = document.getElementById('nextBtn');\n  const motionBtn = document.getElementById('motionBtn');\n  const svgContainer = document.getElementById('svgContainer');\n  const interactiveControls = document.getElementById('interactiveControls');\n  const chapTitle = document.getElementById('chapTitle');\n  const analogyText = document.getElementById('analogyText');\n  const factText = document.getElementById('factText');\n  const wordCountDisplay = document.getElementById('wordCountDisplay');\n\n  function updateMotionState() {\n    const isHidden = document.hidden;\n    if (userPaused || isHidden) {\n      document.body.classList.add('paused');\n    } else {\n      document.body.classList.remove('paused');\n    }\n    motionBtn.setAttribute('aria-pressed', String(userPaused));\n    motionBtn.textContent = userPaused ? 'Resume Motion' : 'Pause Motion';\n  }\n\n  motionBtn.addEventListener('click', () => {\n    userPaused = !userPaused;\n    updateMotionState();\n  });\n\n  document.addEventListener('visibilitychange', updateMotionState);\n\n  function getSVG(chap, state) {\n    if (chap === 0) {\n      const isAttn = state % 2 === 1;\n      return `<svg viewBox=\"0 0 400 240\" role=\"img\" aria-labelledby=\"svgTitle0 svgDesc0\">\n        <title id=\"svgTitle0\">Sequential Recurrence versus Parallel Self-Attention</title>\n        <desc id=\"svgDesc0\">Top shows Chronos passing buckets sequentially from t=1 to t=4. Bottom shows Aria's loom connecting all positions directly in O(1) operations.</desc>\n        <rect x=\"10\" y=\"10\" width=\"380\" height=\"95\" fill=\"none\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"20\" y=\"28\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">Chronos: Recurrent Step-by-Step O(n) [p.2, §1]</text>\n        ${[0,1,2,3].map(i => `\n          <circle cx=\"${65 + i*90}\" cy=\"65\" r=\"18\" fill=\"${!isAttn ? '#000' : '#fff'}\" stroke=\"#000\" stroke-width=\"2\"/>\n          <text x=\"${65 + i*90}\" y=\"69\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\" fill=\"${!isAttn ? '#fff' : '#000'}\">h${i+1}</text>\n          ${i < 3 ? `<line x1=\"${85 + i*90}\" y1=\"65\" x2=\"${135 + i*90}\" y2=\"65\" stroke=\"#000\" stroke-width=\"2\" class=\"${!isAttn ? 'anim-dash' : ''}\"/><polygon points=\"${135+i*90},61 ${144+i*90},65 ${135+i*90},69\" fill=\"#000\"/>` : ''}\n        `).join('')}\n        <rect x=\"10\" y=\"120\" width=\"380\" height=\"110\" fill=\"none\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"20\" y=\"138\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">Aria's Loom: Self-Attention O(1) Path [p.2, §2]</text>\n        ${[0,1,2,3].map(i => `\n          <rect x=\"${47 + i*90}\" y=\"195\" width=\"36\" height=\"22\" fill=\"${isAttn ? '#000' : '#fff'}\" stroke=\"#000\" stroke-width=\"2\"/>\n          <text x=\"${65 + i*90}\" y=\"210\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\" fill=\"${isAttn ? '#fff' : '#000'}\">x${i+1}</text>\n        `).join('')}\n        <path d=\"M65,195 Q155,140 245,195\" fill=\"none\" stroke=\"#000\" stroke-width=\"${isAttn ? '2.5' : '1'}\" class=\"${isAttn ? 'anim-dash' : ''}\"/>\n        <path d=\"M65,195 Q200,130 335,195\" fill=\"none\" stroke=\"#000\" stroke-width=\"${isAttn ? '2.5' : '1'}\" class=\"${isAttn ? 'anim-dash' : ''}\"/>\n        <path d=\"M155,195 Q245,145 335,195\" fill=\"none\" stroke=\"#000\" stroke-width=\"${isAttn ? '2' : '1'}\"/>\n      </svg>`;\n    }\n    if (chap === 1) {\n      const multi = state % 2 === 1;\n      return `<svg viewBox=\"0 0 400 240\" role=\"img\" aria-labelledby=\"svgTitle1 svgDesc1\">\n        <title id=\"svgTitle1\">Scaled Dot-Product and Multi-Head Attention</title>\n        <desc id=\"svgDesc1\">Shows Query, Key, Value vectors passing through 1/sqrt(dk) scale filter and splitting into h=8 parallel attention heads.</desc>\n        <text x=\"15\" y=\"24\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">${multi ? 'Multi-Head (h=8 Subspaces) [p.4, §3.2.2]' : 'Single Head (Averaged Resolution) [p.2, §2]'}</text>\n        <g class=\"anim-float\">\n          <rect x=\"20\" y=\"50\" width=\"50\" height=\"28\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"2\"/>\n          <text x=\"45\" y=\"68\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\">Query</text>\n          <rect x=\"20\" y=\"105\" width=\"50\" height=\"28\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"2\"/>\n          <text x=\"45\" y=\"123\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\">Key</text>\n          <rect x=\"20\" y=\"160\" width=\"50\" height=\"28\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"2\"/>\n          <text x=\"45\" y=\"178\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\">Value</text>\n        </g>\n        <circle cx=\"145\" cy=\"92\" r=\"24\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"2\"/>\n        <text x=\"145\" y=\"89\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">1/&radic;dk</text>\n        <text x=\"145\" y=\"102\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"9\">Scale</text>\n        <line x1=\"70\" y1=\"64\" x2=\"123\" y2=\"82\" stroke=\"#000\" stroke-width=\"2\" class=\"anim-dash\"/>\n        <line x1=\"70\" y1=\"119\" x2=\"123\" y2=\"100\" stroke=\"#000\" stroke-width=\"2\" class=\"anim-dash\"/>\n        ${multi ? [\n          0,1,2,3,4,5,6,7\n        ].map(h => `\n          <rect x=\"225\" y=\"${36 + h*22}\" width=\"65\" height=\"16\" fill=\"${h%2===0?'#000':'#fff'}\" stroke=\"#000\" stroke-width=\"1.5\"/>\n          <text x=\"257\" y=\"${48 + h*22}\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"9\" fill=\"${h%2===0?'#fff':'#000'}\">Head ${h+1}</text>\n          <line x1=\"169\" y1=\"92\" x2=\"225\" y2=\"${44 + h*22}\" stroke=\"#000\" stroke-width=\"1\"/>\n          <line x1=\"290\" y1=\"${44 + h*22}\" x2=\"330\" y2=\"120\" stroke=\"#000\" stroke-width=\"1\"/>\n        `).join('') : `\n          <rect x=\"215\" y=\"85\" width=\"85\" height=\"60\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"2\" stroke-dasharray=\"4 2\"/>\n          <text x=\"257\" y=\"112\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">Averaged</text>\n          <text x=\"257\" y=\"126\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">Single Head</text>\n          <line x1=\"169\" y1=\"92\" x2=\"215\" y2=\"115\" stroke=\"#000\" stroke-width=\"2\" class=\"anim-dash\"/>\n          <line x1=\"300\" y1=\"115\" x2=\"330\" y2=\"120\" stroke=\"#000\" stroke-width=\"2\"/>\n        `}\n        <line x1=\"70\" y1=\"174\" x2=\"215\" y2=\"174\" stroke=\"#000\" stroke-width=\"1.5\" stroke-dasharray=\"3 3\"/>\n        <rect x=\"330\" y=\"95\" width=\"55\" height=\"50\" fill=\"#000\" stroke=\"#000\" stroke-width=\"2\"/>\n        <text x=\"357\" y=\"118\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\" fill=\"#fff\">Concat</text>\n        <text x=\"357\" y=\"132\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\" fill=\"#fff\">WO</text>\n      </svg>`;\n    }\n    if (chap === 2) {\n      const step = (state % 3) + 1;\n      return `<svg viewBox=\"0 0 400 240\" role=\"img\" aria-labelledby=\"svgTitle2 svgDesc2\">\n        <title id=\"svgTitle2\">Encoder-Decoder Stacks, Positional Sine Waves, and Decoder Masking</title>\n        <desc id=\"svgDesc2\">Left shows N=6 Encoder stack with sine wave positional encodings. Right shows N=6 Decoder stack with -infinity mask blocking future tokens beyond step ${step}.</desc>\n        <!-- Encoder -->\n        <rect x=\"25\" y=\"30\" width=\"130\" height=\"135\" fill=\"none\" stroke=\"#000\" stroke-width=\"2\"/>\n        <text x=\"90\" y=\"22\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">Encoder (N=6)</text>\n        <rect x=\"38\" y=\"42\" width=\"104\" height=\"32\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"90\" y=\"62\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">Feed-Forward</text>\n        <rect x=\"38\" y=\"90\" width=\"104\" height=\"32\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"90\" y=\"110\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">Self-Attention</text>\n        <!-- Sine wave pos encoding -->\n        <path d=\"M 35 195 Q 52 175, 70 195 T 105 195 T 140 195\" fill=\"none\" stroke=\"#000\" stroke-width=\"2\" class=\"anim-float\"/>\n        <text x=\"90\" y=\"220\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">Positional Sine [§3.5]</text>\n        <line x1=\"90\" y1=\"180\" x2=\"90\" y2=\"165\" stroke=\"#000\" stroke-width=\"2\"/>\n        <!-- Cross connection -->\n        <path d=\"M 155 55 C 195 55, 195 100, 235 100\" fill=\"none\" stroke=\"#000\" stroke-width=\"2\" class=\"anim-dash\"/>\n        <!-- Decoder -->\n        <rect x=\"235\" y=\"30\" width=\"145\" height=\"135\" fill=\"none\" stroke=\"#000\" stroke-width=\"2\"/>\n        <text x=\"307\" y=\"22\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">Decoder (N=6)</text>\n        <rect x=\"248\" y=\"40\" width=\"118\" height=\"25\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"307\" y=\"56\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"9\">Feed-Forward</text>\n        <rect x=\"248\" y=\"75\" width=\"118\" height=\"25\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"307\" y=\"91\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"9\">Enc-Dec Attention</text>\n        <rect x=\"248\" y=\"110\" width=\"118\" height=\"42\" fill=\"#000\" stroke=\"#000\" stroke-width=\"1.5\"/>\n        <text x=\"307\" y=\"126\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"9\" fill=\"#fff\">Masked Self-Attn</text>\n        <text x=\"307\" y=\"142\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"9\" fill=\"#fff\">Allowed: pos &le; ${step} (-&infin;)</text>\n        <!-- Output tokens -->\n        ${[1,2,3].map(t => `\n          <rect x=\"${242 + (t-1)*44}\" y=\"182\" width=\"36\" height=\"24\" fill=\"${t <= step ? '#fff' : '#000'}\" stroke=\"#000\" stroke-width=\"1.5\"/>\n          <text x=\"${260 + (t-1)*44}\" y=\"198\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\" fill=\"${t <= step ? '#000' : '#fff'}\">${t <= step ? 'y'+t : '-∞'}</text>\n        `).join('')}\n        <text x=\"307\" y=\"222\" text-anchor=\"middle\" font-family=\"monospace\" font-size=\"10\">Masking Future [§3.2.3]</text>\n      </svg>`;\n    }\n    // Chapter 3 (index 3): Complexity & Limitations\n    const restricted = state % 2 === 1;\n    const cells = [];\n    for (let r = 0; r < 6; r++) {\n      for (let c = 0; c < 6; c++) {\n        const active = !restricted || Math.abs(r - c) <= 1;\n        cells.push(`<rect x=\"${45 + c*24}\" y=\"${55 + r*24}\" width=\"22\" height=\"22\" fill=\"${active ? '#000' : '#fff'}\" stroke=\"#000\" stroke-width=\"1\"/>`);\n      }\n    }\n    return `<svg viewBox=\"0 0 400 240\" role=\"img\" aria-labelledby=\"svgTitle3 svgDesc3\">\n      <title id=\"svgTitle3\">Attention Complexity Grid and Model Limitations</title>\n      <desc id=\"svgDesc3\">Left shows 6x6 attention grid comparing full O(n squared) connections with local neighborhood r restricted connections. Right shows limitations when dk is too small.</desc>\n      <text x=\"45\" y=\"30\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">${restricted ? 'Restricted: O(r·n·d), Path O(n/r)' : 'Full Grid: O(n²·d), Path O(1)'}</text>\n      <text x=\"45\" y=\"45\" font-family=\"monospace\" font-size=\"10\">[p.6–7, §4, Table 1]</text>\n      ${cells.join('')}\n      <line x1=\"215\" y1=\"20\" x2=\"215\" y2=\"220\" stroke=\"#000\" stroke-width=\"1.5\" stroke-dasharray=\"4 4\"/>\n      <text x=\"230\" y=\"35\" font-family=\"monospace\" font-size=\"11\" font-weight=\"bold\">Preserved Limits</text>\n      <rect x=\"230\" y=\"50\" width=\"150\" height=\"50\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\"/>\n      <text x=\"240\" y=\"70\" font-family=\"monospace\" font-size=\"10\">Small dk / Too Many</text>\n      <text x=\"240\" y=\"86\" font-family=\"monospace\" font-size=\"10\">Heads Hurts Quality</text>\n      <text x=\"340\" y=\"96\" font-family=\"monospace\" font-size=\"8\">[p.9, §6.2]</text>\n      <rect x=\"230\" y=\"115\" width=\"150\" height=\"50\" fill=\"#fff\" stroke=\"#000\" stroke-width=\"1.5\"/>\n      <text x=\"240\" y=\"135\" font-family=\"monospace\" font-size=\"10\">Fast when n &lt; d;</text>\n      <text x=\"240\" y=\"151\" font-family=\"monospace\" font-size=\"10\">Costly for huge n</text>\n      <text x=\"340\" y=\"161\" font-family=\"monospace\" font-size=\"8\">[p.6–7, §4]</text>\n      <rect x=\"230\" y=\"180\" width=\"150\" height=\"42\" fill=\"#000\" stroke=\"#000\" stroke-width=\"1.5\"/>\n      <text x=\"240\" y=\"198\" font-family=\"monospace\" font-size=\"10\" fill=\"#fff\">Sequential Gen</text>\n      <text x=\"240\" y=\"213\" font-family=\"monospace\" font-size=\"9\" fill=\"#fff\">Future Work [p.10, §7]</text>\n    </svg>`;\n  }\n\n  function render() {\n    const c = chapters[currentChap];\n    chapTitle.textContent = c.title;\n    analogyText.textContent = c.analogy;\n    factText.innerHTML = c.factHtml;\n    svgContainer.innerHTML = getSVG(currentChap, subState);\n\n    interactiveControls.innerHTML = `\n      <span>${c.controlLabel}</span>\n      <button type=\"button\" id=\"subActionBtn\">${c.controlBtn}</button>\n    `;\n    document.getElementById('subActionBtn').addEventListener('click', () => {\n      subState++;\n      svgContainer.innerHTML = getSVG(currentChap, subState);\n    });\n\n    chapBtns.forEach((btn, idx) => {\n      if (idx === currentChap) {\n        btn.classList.add('active');\n        btn.setAttribute('aria-current', 'step');\n      } else {\n        btn.classList.remove('active');\n        btn.removeAttribute('aria-current');\n      }\n    });\n\n    prevBtn.disabled = currentChap === 0;\n    nextBtn.disabled = currentChap === chapters.length - 1;\n    updateMotionState();\n  }\n\n  function goToChapter(idx) {\n    if (idx < 0 || idx >= chapters.length) return;\n    currentChap = idx;\n    subState = 0;\n    render();\n  }\n\n  chapBtns.forEach(btn => {\n    btn.addEventListener('click', () => goToChapter( Number(btn.dataset.chap) ));\n  });\n  prevBtn.addEventListener('click', () => goToChapter(currentChap - 1));\n  nextBtn.addEventListener('click', () => goToChapter(currentChap + 1));\n\n  document.addEventListener('keydown', (e) => {\n    if (e.key === 'ArrowRight') goToChapter(currentChap + 1);\n    if (e.key === 'ArrowLeft') goToChapter(currentChap - 1);\n  });\n\n  // Calculate total factual word count across all 4 chapters\n  const totalWords = chapters.reduce((acc, ch) => {\n    return acc + ch.factPlain.trim().split(/\\s+/).length;\n  }, 0);\n  wordCountDisplay.textContent = `Total factual explanation words across all 4 chapters: ${totalWords}`;\n\n  render();\n})();\n</script>\n</body>\n</html>"
  },
  "editorialNotes": [
    "Removed an unenforced word-count target from the display counter. Model-generated content and citations retained; review against the source paper."
  ]
}