> ## Documentation Index
> Fetch the complete documentation index at: https://hyperframes-fix-nested-composition-media-inpoint.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Flowchart

> Animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction

export const InstallCommand = ({command, item}) => {
  const [copied, setCopied] = React.useState(false);
  const [tuned, setTuned] = React.useState("");
  React.useEffect(() => {
    if (!item) return;
    const read = () => {
      try {
        const raw = new URLSearchParams(window.location.search).get(`vars-${item}`);
        if (!raw) return setTuned("");
        const parsed = JSON.parse(raw);
        if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return setTuned("");
        if (Object.keys(parsed).length === 0) return setTuned("");
        setTuned(` --vars '${JSON.stringify(parsed)}'`);
      } catch {
        setTuned("");
      }
    };
    read();
    window.addEventListener("hf-vars-changed", read);
    window.addEventListener("popstate", read);
    return () => {
      window.removeEventListener("hf-vars-changed", read);
      window.removeEventListener("popstate", read);
    };
  }, [item]);
  const fullCommand = `${command}${tuned}`;
  const copy = async () => {
    try {
      if (navigator.clipboard && window.isSecureContext) {
        await navigator.clipboard.writeText(fullCommand);
      } else {
        const previous = document.activeElement;
        const scratch = document.createElement("textarea");
        scratch.value = fullCommand;
        scratch.setAttribute("readonly", "");
        scratch.style.position = "fixed";
        scratch.style.opacity = "0";
        document.body.appendChild(scratch);
        scratch.select();
        document.execCommand("copy");
        document.body.removeChild(scratch);
        previous?.focus?.();
      }
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {}
  };
  return <div className="hf-install-command not-prose my-4 flex items-stretch overflow-hidden rounded-xl border border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900">
      <code className="flex-1 overflow-x-auto whitespace-nowrap border-r border-zinc-200 px-4 py-3 font-mono text-sm text-zinc-800 dark:border-zinc-800 dark:text-zinc-100">
        {fullCommand}
      </code>
      <button type="button" onClick={copy} data-copied={copied ? "true" : "false"} aria-label={`Copy ${command} to the clipboard`} className="hf-install-copy">
        <svg className="hf-install-copy-clipboard" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          <path d="M14.25 5.25H7.25C6.14543 5.25 5.25 6.14543 5.25 7.25V14.25C5.25 15.3546 6.14543 16.25 7.25 16.25H14.25C15.3546 16.25 16.25 15.3546 16.25 14.25V7.25C16.25 6.14543 15.3546 5.25 14.25 5.25Z" />
          <path d="M2.80103 11.998L1.77203 5.07397C1.61003 3.98097 2.36403 2.96397 3.45603 2.80197L10.38 1.77297C11.313 1.63397 12.19 2.16297 12.528 3.00097" />
        </svg>
        <svg className="hf-install-copy-check" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          <path d="M2.75 9.5L6.5 13.25L15.25 4.5" />
        </svg>
      </button>
      <span className="hf-install-copy-status" role="status" aria-live="polite">
        {copied ? "Copied" : ""}
      </span>
    </div>;
};

<iframe className="w-full aspect-video rounded-xl border-0 bg-zinc-100 dark:bg-zinc-800" title="flowchart preview" loading="lazy" srcDoc={`<!doctype html><html><head><meta charset="utf-8"><style>html,body{margin:0;height:100%;overflow:hidden;background:transparent}hyperframes-player{display:block;width:100%;height:100%}</style><script src="https://cdn.jsdelivr.net/npm/@hyperframes/player@0.7/dist/hyperframes-player.global.js"><\/script></head><body><script>fetch("/public/catalog/blocks/flowchart.json").then(function(r){return r.json()}).then(function(d){var p=document.createElement("hyperframes-player");p.setAttribute("srcdoc",d.html);p.setAttribute("controls","");p.setAttribute("autoplay","");p.setAttribute("loop","");p.setAttribute("muted","");p.setAttribute("poster","https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flowchart.png");document.body.appendChild(p)});<\/script></body></html>`} />

## Install

<InstallCommand command="npx hyperframes add flowchart" item="flowchart" />

That writes one file: `compositions/flowchart.html`.

## Source

<Accordion title={`flowchart.html`}>
  ```html theme={null}
  <!doctype html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=1920, height=1080" />
      <title>Flowchart</title>
      <link rel="preconnect" href="https://fonts.googleapis.com" />
      <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
      <link
        href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=block"
        rel="stylesheet"
      />
      <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
      <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
        html,
        body {
          margin: 0;
          width: 1920px;
          height: 1080px;
          overflow: hidden;
          background-color: #ffffff;
        }
      </style>
    </head>
    <body>
      <div
        id="flowchart"
        data-composition-id="flowchart"
        data-width="1920"
        data-height="1080"
        data-start="0"
        data-duration="12"
      >
        <div class="canvas">
          <svg class="connectors" width="1920" height="1080" viewBox="0 0 1920 1080">
            <!-- Level 1 to 2 -->
            <path
              id="path-1-L"
              class="connector"
              d="M 960 130 L 960 200 L 600 200 L 600 270"
              fill="none"
              stroke="#333"
              stroke-width="4"
            />
            <path
              id="path-1-R"
              class="connector"
              d="M 960 130 L 960 200 L 1320 200 L 1320 270"
              fill="none"
              stroke="#333"
              stroke-width="4"
            />

            <!-- Level 2 to 3 (Left side) -->
            <path
              id="path-2-LL"
              class="connector"
              d="M 600 330 L 600 400 L 400 400 L 400 470"
              fill="none"
              stroke="#333"
              stroke-width="4"
            />
            <path
              id="path-2-LR"
              class="connector"
              d="M 600 330 L 600 400 L 800 400 L 800 470"
              fill="none"
              stroke="#333"
              stroke-width="4"
            />

            <!-- Level 2 to 3 (Right side) -->
            <path
              id="path-2-RL"
              class="connector"
              d="M 1320 330 L 1320 400 L 1120 400 L 1120 470"
              fill="none"
              stroke="#333"
              stroke-width="4"
            />
            <path
              id="path-2-RR"
              class="connector"
              d="M 1320 330 L 1320 400 L 1520 400 L 1520 470"
              fill="none"
              stroke="#333"
              stroke-width="4"
            />
          </svg>

          <div id="label-yes" class="connector-label">Yes</div>
          <div id="label-not-sure" class="connector-label">Not sure</div>

          <!-- Level 1 -->
          <div id="node-root" class="node yellow" style="left: 960px; top: 100px">
            Should I learn to code?
          </div>

          <!-- Level 2 -->
          <div id="node-yes" class="node green" style="left: 600px; top: 300px">Yes</div>
          <div id="node-not-sure" class="node peach" style="left: 1320px; top: 300px">Not sure</div>

          <!-- Level 3 -->
          <div id="node-python" class="node lavender" style="left: 400px; top: 500px">
            <div style="position: relative; display: inline-block">
              <span id="python-text">Start with Pythom</span>
              <svg class="squiggle-container" width="64" height="6" viewBox="0 0 64 6">
                <path
                  id="squiggle"
                  d="M 0 3 Q 2 0 4 3 T 8 3 T 12 3 T 16 3 T 20 3 T 24 3 T 28 3 T 32 3 T 36 3 T 40 3 T 44 3 T 48 3 T 52 3 T 56 3 T 60 3 T 64 3"
                  fill="none"
                  stroke="#E53935"
                  stroke-width="2"
                />
              </svg>
            </div>
          </div>
          <div id="node-nocode" class="node blue" style="left: 800px; top: 500px">
            Try no-code first
          </div>
          <div id="node-website" class="node pink" style="left: 1120px; top: 500px">
            Build a personal website
          </div>
          <div id="node-course" class="node yellow" style="left: 1520px; top: 500px">
            Take a free intro course
          </div>

          <!-- Cursor -->
          <div id="cursor" class="cursor-container">
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
              <path
                d="M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z"
                fill="white"
                stroke="black"
              />
            </svg>
            <div class="cursor-tag">You</div>
          </div>

          <!-- Emoji -->
          <div id="emoji-thumb" class="emoji">👍</div>

          <!-- Overlay -->
          <div id="fade-overlay"></div>
        </div>

        <style>
          [data-composition-id="flowchart"] {
            width: 1920px;
            height: 1080px;
            background-color: #ffffff;
            background-image: radial-gradient(#e5e5e5 1px, transparent 1px);
            background-size: 20px 20px;
            position: absolute;
            overflow: hidden;
            font-family: "Inter", sans-serif;
          }

          [data-composition-id="flowchart"] .canvas {
            width: 100%;
            height: 100%;
            position: absolute;
            transform: scale(1.2);
            transform-origin: 960px 300px;
          }

          [data-composition-id="flowchart"] .node {
            position: absolute;
            transform: translate(-50%, -50%) scale(0);
            padding: 16px 24px;
            border-radius: 12px;
            font-size: 18px;
            font-weight: 500;
            color: #333;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            white-space: nowrap;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 10;
          }

          [data-composition-id="flowchart"] .node.yellow {
            background-color: #e8d44d;
          }
          [data-composition-id="flowchart"] .node.green {
            background-color: #c2e8a0;
          }
          [data-composition-id="flowchart"] .node.peach {
            background-color: #f5c5a3;
          }
          [data-composition-id="flowchart"] .node.lavender {
            background-color: #d4c5f9;
          }
          [data-composition-id="flowchart"] .node.blue {
            background-color: #a8d8f0;
          }
          [data-composition-id="flowchart"] .node.pink {
            background-color: #f8b4c8;
          }

          [data-composition-id="flowchart"] .connectors {
            position: absolute;
            top: 0;
            left: 0;
            z-index: 5;
            pointer-events: none;
          }

          [data-composition-id="flowchart"] .connector {
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
          }

          [data-composition-id="flowchart"] .connector-label {
            position: absolute;
            font-size: 14px;
            font-weight: 600;
            color: #333;
            background: white;
            padding: 2px 6px;
            border-radius: 4px;
            opacity: 0;
            z-index: 6;
            transform: translate(-50%, -50%);
          }

          [data-composition-id="flowchart"] #label-yes {
            left: 780px;
            top: 230px;
          }
          [data-composition-id="flowchart"] #label-not-sure {
            left: 1140px;
            top: 230px;
          }

          [data-composition-id="flowchart"] .cursor-container {
            position: absolute;
            left: 1920px;
            top: 1080px;
            z-index: 100;
            pointer-events: none;
            display: flex;
            align-items: flex-start;
          }

          [data-composition-id="flowchart"] .cursor-tag {
            background-color: #9747ff;
            color: white;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 12px;
            font-weight: 600;
            margin-left: 4px;
            margin-top: 12px;
          }

          [data-composition-id="flowchart"] .squiggle-container {
            position: absolute;
            right: 0;
            bottom: -4px;
            opacity: 0;
          }

          [data-composition-id="flowchart"] .emoji {
            position: absolute;
            font-size: 32px;
            left: 510px;
            top: 500px;
            transform: translate(-50%, -50%) scale(0);
            z-index: 20;
          }

          [data-composition-id="flowchart"] #fade-overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: white;
            opacity: 0;
            z-index: 1000;
            pointer-events: none;
          }

          [data-composition-id="flowchart"] .selection-border {
            position: absolute;
            top: -4px;
            left: -4px;
            right: -4px;
            bottom: -4px;
            border: 2px solid #0b84f3;
            border-radius: 16px;
            pointer-events: none;
            opacity: 0;
          }

          [data-composition-id="flowchart"] .text-highlight {
            background-color: #d0e4ff;
          }
        </style>

        <script>
          (function () {
            const tl = gsap.timeline({ paused: true });
            const S = '[data-composition-id="flowchart"]';
            const nodePython = document.querySelector(S + " #node-python");
            const pythonText = document.querySelector(S + " #python-text");

            // 1. Root node scales in
            tl.to(S + " #node-root", { scale: 1, duration: 0.4, ease: "power2.out" });

            // 2. Hold
            tl.addLabel("hold1", "+=0.6");

            // 3. Connectors draw
            tl.to(
              S + " .connector#path-1-L, " + S + " .connector#path-1-R",
              { strokeDashoffset: 0, duration: 0.5, ease: "none" },
              "hold1",
            );

            tl.to(
              S + " #label-yes, " + S + " #label-not-sure",
              { opacity: 1, duration: 0.2 },
              "hold1+=0.25",
            );

            // 4. Level 2 nodes
            tl.to(S + " #node-yes", { scale: 1, duration: 0.4, ease: "back.out(1.7)" }, "hold1+=0.4");
            tl.to(
              S + " #node-not-sure",
              { scale: 1, duration: 0.4, ease: "back.out(1.7)" },
              "hold1+=0.6",
            );

            // 5. Hold
            tl.addLabel("hold2", "+=0.5");

            // 6. Level 2→3 connectors
            tl.to(
              S +
                " .connector#path-2-LL, " +
                S +
                " .connector#path-2-LR, " +
                S +
                " .connector#path-2-RL, " +
                S +
                " .connector#path-2-RR",
              { strokeDashoffset: 0, duration: 0.4, ease: "none" },
              "hold2",
            );

            // 7. Leaf nodes
            const leafNodes = [
              S + " #node-python",
              S + " #node-nocode",
              S + " #node-website",
              S + " #node-course",
            ];
            leafNodes.forEach((id, i) => {
              tl.to(
                id,
                { scale: 1, duration: 0.4, ease: "back.out(1.7)" },
                `hold2+=${0.3 + i * 0.15}`,
              );
            });

            tl.to(S + " .squiggle-container", { opacity: 1, duration: 0.1 }, "hold2+=0.3");

            // 8. Hold
            tl.addLabel("hold3", "+=0.8");

            // 9. Cursor drifts in
            tl.to(S + " #cursor", { x: -1470, y: -540, duration: 1, ease: "power1.inOut" }, "hold3");

            // 10. Cursor clicks — selection border
            tl.add(() => {
              if (!nodePython) return;
              if (!nodePython.querySelector(".selection-border")) {
                const border = document.createElement("div");
                border.className = "selection-border";
                nodePython.appendChild(border);
              }
              gsap.set(S + " .selection-border", { opacity: 1 });
            }, "hold3+=1");

            tl.to(
              S + " #cursor",
              { scale: 0.8, duration: 0.05, yoyo: true, repeat: 1, overwrite: "auto" },
              "hold3+=1",
            );

            // 11. Hold
            tl.addLabel("hold4", "+=0.3");

            // 12. Double-click to highlight "Pythom"
            tl.to(
              S + " #cursor",
              { scale: 0.8, duration: 0.05, yoyo: true, repeat: 3, overwrite: "auto" },
              "hold4",
            );
            tl.add(() => {
              if (!pythonText) return;
              pythonText.innerHTML = 'Start with <span class="text-highlight">Pythom</span>';
            }, "hold4+=0.1");

            // 13. Hold
            tl.addLabel("hold5", "+=0.2");

            // 14. Type correction: "Pythom" → "Python"
            const typingStart = tl.labels["hold5"];
            const words = ["P", "Py", "Pyt", "Pyth", "Pytho", "Python"];
            words.forEach((word, i) => {
              tl.add(
                () => {
                  if (pythonText)
                    pythonText.innerHTML = `Start with <span class="text-highlight">${word}</span>`;
                },
                typingStart + i * 0.05,
              );
            });

            const typingEnd = typingStart + words.length * 0.05;
            tl.add(() => {
              if (pythonText) pythonText.innerHTML = "Start with Python";
              gsap.set(S + " .squiggle-container", { opacity: 0 });
            }, typingEnd);

            // 15. Hold
            tl.addLabel("hold6", typingEnd + 0.5);

            // 16. Cursor clicks away to deselect
            tl.to(S + " #cursor", { x: -1420, y: -500, duration: 0.3, overwrite: "auto" }, "hold6");
            tl.to(
              S + " #cursor",
              { scale: 0.8, duration: 0.05, yoyo: true, repeat: 1, overwrite: "auto" },
              "hold6+=0.3",
            );
            tl.to(S + " .selection-border", { opacity: 0, duration: 0.1 }, "hold6+=0.3");

            // 17. Emoji pop
            tl.to(
              S + " #emoji-thumb",
              { scale: 1, duration: 0.15, ease: "back.out(2)" },
              "hold6+=0.4",
            );

            // 18. Hold
            tl.addLabel("hold7", "+=2");

            // 19. Fade out
            tl.to(S + " #fade-overlay", { opacity: 1, duration: 0.5 }, "hold7");

            window.__timelines = window.__timelines || {};
            window.__timelines["flowchart"] = tl;
          })();
        </script>
      </div>
    </body>
  </html>
  ```
</Accordion>

## Usage

After installing, add the block to your host composition:

```html theme={null}
<div data-composition-id="flowchart" data-composition-src="compositions/flowchart.html" data-start="0" data-duration="12" data-track-index="1" data-width="1920" data-height="1080"></div>
```

Tagged `diagram` `flowchart` `interactive`.

## Related topics

* [Browse the complete Catalog](/catalog)
* [Add assets and Catalog items in Studio](/studio/assets-and-blocks)
* [Build a richer composition](/go-further)
