scripts/gen_demo_path.py(10KB)· 產出 docs/demo-path.svgGraphify README 的第一張圖(docs/demo-path.svg,本站 首頁 也用了)不是手繪的——是這個腳本產生的動畫 SVG。畫面:左邊一個終端機正在輸入 graphify path "FastAPI" "ModelField",右邊同一張圖自己畫出來,一次點亮一跳,其餘節點保持暗淡。
docstring 列了它遵守的約束(這是「怎麼做程式化視覺化」的絕佳教材):
<img> 引用的 SVG 內——能通過 GitHub 的 sanitizer、無 JS、無外部字型。#4db18f 家族)強調色,無亮粉霓虹。<animate> 是 dur=10s repeatCount=indefinite,循環點前回到起始狀態,無縫迴圈。三個 helper 組出 SMIL 的 keyTimes/values:
kt(*pairs) — 把 (keyTime, value) 對轉成 values 與 keyTimes 字串,且把 0.9500 這種數字收乾淨。op0() — 元素的初始 opacity(STATIC=1 時是 1,bake 靜態 frame 做視覺 QA;否則 0,等動畫亮起)。reveal(t, hold, start) — 產生「在 t 秒亮起 → 保持 → 循環前淡出」的 <animate attributeName="opacity">。這是「路徑逐跳點亮」的核心——每個 hop 有自己的亮起時間,錯開就形成脈衝效果。主體是一串 out.append(…) 的組裝:
graphify path "FastAPI" "ModelField" 逐字元輸出,每個字元 reveal(t)(t = 0.35 + i*0.058,錯開模擬打字)。<animate attributeName="x"> 讓游標沿字元位置走、最後原地閃爍。執行:python3 scripts/gen_demo_path.py → 寫出 docs/demo-path.svg;STATIC=1 時 bake 靜態 frame。
reveal() 怎麼做出「逐跳點亮」、STATIC=1 是幹嘛的。這是一個「把產品 demo 也當成程式化資產」的好例子——圖更新時重跑一次就好,不用手工重畫。實際產出:assets/demo-path.svg(本站首頁使用,來源標註於 關於)。
前面是「看懂 reveal() 動畫」;這次是把整組行銷/文件圖檔變成 build artifact:你的團隊 README、首頁、說明文件各處都用到圖,圖的資料每次重跑 graphify 後都會變,你不想手工重畫。
python3 scripts/gen_demo_path.py + 你自製的其它視覺化產生器(社群餅圖、god-node 排行 SVG),統一輸出到 assets/。STATIC=1 bake 靜態 frame 進 PR——reviewer 不需開瀏覽器看動畫,直接看靜態圖檢查「路徑對不對、節點位置合不合理」。git diff assets/ 就能看到「哪次資料變化改動了視覺」。<img> 下正常顯示,避免「gif/JS 動畫在很多環境被擋」的相容問題。gen_demo_path.py 真正的價值在「在約束下設計」:
<img> 且過 GitHub sanitizer——所以不能用 JS、不能用外部字型、不能有外部資源。這逼出「<animate> 內嵌」的方案,也讓檔案可離線、可內嵌、零依賴。<animate> 都是 dur=10s repeatCount=indefinite——循環點前回到起始狀態,無縫迴圈。時間軸是「全域對齊」的,不是各自獨立計時,否則跳動會逐漸錯位。kt() 把 (keyTime, value) 對轉成 keyTimes/values;reveal() 產生「t 秒亮起 → 保持 → 循環前淡出」的 opacity 動畫——路徑逐跳點亮的「脈衝」感,就是每個 hop 的 reveal 時間錯開造成的。docs/demo-path.svg 與 graph.json 是同一份資料的直譯」。其實它是人為挑選的一條 path 的「示意演出」——腳本裡寫死要展示 graphify path "FastAPI" "ModelField" 這條路徑,節點位置、動畫時序都是編排的。它「看起來像」即時渲染,但資料若換了,這條路徑可能不存在、SVG 畫出來的就是假的。真正「即時從圖算路徑」的是 graph.html;SVG 是「劇本」。看 SVG 講解時要記得它是 demo artifact,不是 data snapshot。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| SVG 在 GitHub 上不顯示動畫 | 用了 JS 或外部資源(sanitizer 會擋) | 確保全在 SMIL/CSS 內嵌;<animate> 不依賴外部腳本 |
| 動畫循環處「跳一下」 | 循環點前沒回到起始狀態,或各 animate 時間軸沒對齊 | 檢查 reveal 的 start 參數;確認所有 dur 都是同一主週期 |
| demo 路徑在圖裡已不存在 | 資料更新後,寫死的 FastAPI→ModelField 這條路徑消失了 | 把 demo 路徑參數化(讀 graph.json 驗證存在再畫);或選一條穩定的主路徑 |
| 動畫在部分瀏覽器不跑 | SMIL 支援度差異(舊 Edge/IE 沒有) | 接受降級(顯示靜態 frame);或用 CSS keyframes 替代純 SMIL |
| 視覺配色刺眼 | 違反品牌色票(亮粉霓虹) | 遵守「暗底 + 單一 emerald 強調色」約束;回歸到 #4db18f 家族 |
kt() 的 (keyTime, value) 對該怎麼重新分配。