diff --git a/README.md b/README.md
index 9f1e11f0..1952acbc 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,10 @@ A knowledge graph is not a vector index: it is **deterministic**, **every edge i
## See it in action
+
+
+
+
Once the graph is built you query it instead of reading files. Real output, graphify run on the FastAPI codebase shown above:
```text
diff --git a/docs/demo-path.svg b/docs/demo-path.svg
new file mode 100644
index 00000000..4bf10a6e
--- /dev/null
+++ b/docs/demo-path.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scripts/gen_demo_path.py b/scripts/gen_demo_path.py
new file mode 100644
index 00000000..acb0dae7
--- /dev/null
+++ b/scripts/gen_demo_path.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python3
+"""Generate docs/demo-path.svg: the animated 'path lights up' README hero-companion.
+
+Concept 1 ("The Path Lights Up"): a terminal types `graphify path ...` on the
+left; on the right the same answer draws itself as a graph, a pulse igniting
+each hop while the rest of the constellation stays dim.
+
+Constraints honored:
+- Pure SMIL/CSS inside an -referenced SVG (survives GitHub's sanitizer,
+ no JS, no external fonts).
+- Brand palette only: muted emerald green (#4db18f family) as the single
+ accent on a dark green-black card. No shiny/neon colors.
+- One 10s master period; every is dur=10s repeatCount=indefinite and
+ fades back to its start state before the loop point, so the loop is seamless.
+
+Run: python3 scripts/gen_demo_path.py -> writes docs/demo-path.svg
+"""
+import math
+import os
+import random
+
+STATIC = bool(os.environ.get("STATIC")) # bake the lit held-frame for visual QA
+
+T = 10.0 # master loop seconds
+HOLD_END = 0.96 # everything fades out over the last 0.4s
+FADE = 0.12 # generic fade-in duration (fraction handled per item)
+
+# ---- brand palette (sampled from docs/logo.png) ----------------------------
+BG = "#0c1712" # dark green-black card
+BG2 = "#0f1e18" # subtle gradient partner
+BORDER = "#20342b"
+DIVIDER = "#1c2c25"
+DIM_NODE = "#2c3a34" # unlit nodes
+DIM_EDGE = "#22302a" # unlit edges
+GREEN = "#4db18f" # brand green (lit)
+GREEN_HI = "#62c4a2" # brand green light (accents/caption)
+GREEN_DK = "#41a884" # brand green deep
+TXT = "#c6d6ce" # primary terminal text
+TXT_DIM = "#6f8a7f" # secondary terminal text
+PROMPT = "#4db18f"
+DOTS = ["#ff5f56", "#ffbd2e", "#27c93f"] # macOS traffic lights: close / minimize / zoom
+
+W, H = 900, 360
+CHARW = 6.62 # mono advance at 11px
+FS = 11
+LX = 20 # left text margin
+PANEL = 336 # terminal panel width
+
+def kt(*pairs):
+ """pairs of (keyTime, value) -> (values_str, keyTimes_str)."""
+ ks = ";".join(f"{k:.4f}".rstrip("0").rstrip(".") if k not in (0, 1) else str(int(k)) for k, _ in pairs)
+ vs = ";".join(str(v) for _, v in pairs)
+ return vs, ks
+
+def op0():
+ """initial opacity for a revealable element (1 when baking a static frame)."""
+ return "1" if STATIC else "0"
+
+def reveal(t, hold_val="1", start_val="0"):
+ """opacity reveal at time t (s), hold, fade out before loop."""
+ if STATIC:
+ return ""
+ a = t / T
+ b = min((t + FADE) / T, HOLD_END - 0.001)
+ vs, ks = kt((0, start_val), (a, start_val), (b, hold_val), (HOLD_END, hold_val), (1, start_val))
+ return f''
+
+out = []
+def e(s): out.append(s)
+
+# ---------------------------------------------------------------- svg header
+e(f'')
+
+with open("docs/demo-path.svg", "w", encoding="utf-8") as f:
+ f.write("".join(out))
+print("wrote docs/demo-path.svg", sum(len(s) for s in out), "bytes")