動態圖形
本技能建立會動或會回應輸入的圖形。分為三個層級。請與 Claude、Cursor、Codex、OpenClaw、Hermes 或任何讀取 SKILL.md 的代理程式搭配使用。
| 層級 | 製作內容 | 放置位置 |
|---|---|---|
| 1. 課程圖形 | 宣告式 SMIL 動畫,或可重繪 SVG 的滑桿小工具。兩者皆從 ``figure fence 掛載。 | 課程內容 |
| 2. 機構圖 | 一個 HTML 面板,顯示系統的命名零件。讀者驅動一個控件並讀取計算結果。 | 獨立頁面、README、文章、課程網站課程之外的區域 |
| 3. 抖色場 | 一個 WebGL 條帶,使用紙色、強調色與墨水色繪製有序抖色點,並有四種種子動畫。 | 頁面頁首與章節分隔 |
第 1 層有最多規則,因為課程執行環境有嚴格限制。第 2 層和第 3 層有自己的參考檔案。
使用時機
- 課程說明一個隨時間變化的過程:移動通過階段的 token、逐漸填滿的佇列、重複執行的迴圈。
- 課程說明一個公式,其中一個輸入會改變輸出:學習率、溫度、區塊大小、批次大小。
- 作者撰寫「將此圖形動畫化」、「加入滑桿」或「讓圖表互動」。
- 網頁需要一個示範,讓讀者改變一個參數,觀察系統的反應:快取、佇列、上下文視窗、路由器。使用第 2 層。
- 網頁需要一個使用課程顏色的慢速動畫頁首。使用第 3 層。
不應使用時機
- 概念是固定結構,沒有時間軸或輸入。請製作靜態 SVG 圖形。同層級技能
blueprint-figure涵蓋靜態圖形。 - 頁面是完整解說頁,有自己的狀態模型與機器幾何。同層級技能
isometric-explainer涵蓋此類。 - 你只需要調色盤、字型或散文規則。同層級技能
course-style包含這些。本技能會將其所需部分複製到references/tokens.md。
方法
-
寫一句話,命名圖形所展示的單一變化。如果需要兩句話,請製作兩個圖形。
-
選擇層級。在課程內,使用第 1 層。對於第 2 層,請閱讀
references/mechanism-figures.md並從templates/mechanism.html開始。對於第 3 層,請閱讀references/dither-fields.md並複製templates/dither.js。以下步驟針對第 1 層。在第 1 層中,當變數是時間時使用動畫圖形;當變數是數字時使用滑桿小工具。 -
選擇一個 kebab-case 的名稱,例如
request-path或context-budget。首先在註冊表中搜尋該名稱。後續模組若註冊相同名稱,會取代先前的圖形。 -
將程式碼放入名為
figures-<topic>.js的模組檔案中。將其包裝在 IIFE 中,讀取window.LF,若缺少則提前返回。 -
撰寫圖形函數
function (host, cfg)。它會將一個.lf卡片附加到host,並可傳回 dispose 函數。 -
建立卡片:
.lf-head包含大寫的.lf-label與簡短提示、.lf-body、以及包含說明的.lf-cap。 -
使用
viewBox="0 0 520 H"作為 SVG。大多數課程圖形的 H 值介於 200 到 250。單一長條需要較小值。 -
添加
<title>和<desc>,並為其建立唯一 ID(在任何 render 函數外部,僅建立一次)。 -
對於動畫圖形,先添加入場動畫,再添加一個緩慢迴圈。請逐行遵循
references/smil-rules.md。 -
對於滑桿小工具,在呼叫
LF.slider或LF.select之前,先定義state._render。然後在結尾呼叫一次state._render()。 -
在模組結尾呼叫
LF.register({ 'your-name': fn })。 -
在課程 Markdown 中,添加 fence。將名稱放在第一行,可選的 JSON 設定放在其後:
```figure context-budget {"windowK": 32} ``` -
執行「完成前檢查」中的檢查。在淺色主題、深色主題、375px 寬度以及開啟減少動畫模式的情況下檢視圖形。
頁面如何掛載圖形
- Markdown 解析器將 fence 轉換為
<div class="lesson-figure" data-figure="name {json}">。 - 網站建置程序掃描課程 Markdown 中的 fence 名稱。它會找到包含該名稱的模組檔案,並寫入一個 manifest。沒有提供者的 fence 名稱會導致建置失敗。
- 頁面僅載入課程所需的模組,按固定順序。新模組檔案按字母順序放在已列出的模組之後。
- 掛載函數將第一個單詞讀取為名稱,並將其餘部分解析為 JSON。格式錯誤的 JSON 會得到空的
cfg。 - 如果圖形函數拋出錯誤,執行環境會清空 host 並記錄警告。課程的其餘部分仍會正常渲染。
- 掛載後,執行環境會添加標題、描述、
role="img",以及缺失的控制標籤。當圖形包含 SMIL 動畫時,會添加暫停按鈕;當任何動畫播放一次時,會添加重播按鈕。 - 當圖形離開視口、分頁隱藏或讀者按下暫停時,執行環境會暫停動畫。在減少動畫或列印模式下,會顯示靜態畫面。
references/toolkit.md 描述了每個執行環境函數,並包含兩個完整的範例模組。
規則
動畫圖形:
- 僅使用
<animate>、<animateTransform>和<animateMotion>。請勿在圖形中使用setInterval或requestAnimationFrame。 - 每個圖形保持在 55 個 SVG 元素以內。
- 入場動畫從透明度 0 和縮放 0.95 開始,到透明度 1 和縮放 1 結束。切勿從縮放 0 開始。
- 入場動畫使用
calcMode="spline"和keySplines="0.23 1 0.32 1"。入場持續時間為 0.5 到 0.6 秒。 - 入場開始時間交錯 0.05 到 0.4 秒。離場動畫應比入場動畫短。
- 迴圈持續 2.5 到 6 秒,使用
repeatCount="indefinite"。請勿在迴圈上設定fill="freeze",否則執行環境會將其播放一次。 - 每個
keyTimes列表的項目數應與values相同。它以 0 開始,以 1 結束,且永不減少。 - 每個
keySplines列表的項目數應比keyTimes少一個。僅在calcMode="spline"時使用。 - 使用
keyPoints的animateMotion應使用calcMode="linear"。其 keyPoints 數量應與 keyTimes 數量相同。它沒有values。 - 請勿在動畫化的
fill或stroke值中使用var()。請改為動畫化一個具有目標顏色的第二個元素的透明度。 - 迴圈僅動畫化透明度、變形、
stroke-dashoffset或沿路徑的運動。執行環境會將任何對 x、y、x1、y1、x2、y2、width、height、r、cx、cy、rx 或 ry 的動畫播放一次。 - host 的
data-static-time(預設 1.5 秒)時的畫面應完整且可讀。當後續時間點顯示完整狀態時,在 host 上設定該屬性。 - 圍繞元素中心進行縮放。在 (0, 0) 周圍繪製群組內容,並使用
translate移動群組。使用additive="sum"添加縮放。
滑桿小工具:
- 僅撰寫 ES5 語法:
var、函數表達式、字串串接。無箭頭函數、let、const或模板字串。 - 在第一次呼叫
LF.slider或LF.select之前,先定義state._render。滑桿會在建立時包裝該 render 函數。 - 在
state._render中,移除所有 SVG 子元素並重新添加。請勿原地編輯節點。 - 在
state._render外部建立 ID(僅一次)。執行環境會移除新節點沒有的屬性,包括 ID。 - 透過長度或路徑上的
stroke-dasharray來增長長條。請勿使用縮放來增長長條,因為已協調的節點會以其中心進行縮放。 - 保持每個滑桿標籤簡短、小寫,並在括號中加上單位,例如
chunk size (tokens)。
兩種圖形皆適用:
- 從 CSS 變數中取得所有顏色,並以淺色主題值作為預設值,例如
var(--blueprint,#3553ff)。僅在無合適變數時使用文字十六進位值。 - 最多使用一個強調色 (
--blueprint) 作為主要主題,並使用--warn表示第二個狀態。其餘部分使用墨水色與邊框色 token。 - 設定 SVG 文字為 12 單位或以上,使用
var(--font-mono)。如果標籤必須更小,請賦予 SVG 最小寬度 500 px,並讓它橫向捲動。 - 在手機上測量標籤大小。在 375 px 的螢幕上,卡片內一個 520 單位的 SVG 繪製寬度約為 279 px。一個 12 單位的標籤繪製出來約為 6.4 px。
- 使用純技術英文撰寫說明。說明每種顏色的含義。句子保持在 25 個單詞以內。
.lf-label中的標籤使用大寫,長度為兩到四個單詞。
機構圖(第 2 層):
- 顯示真實名稱與真實數字:檔案名稱、鍵值、Token 計數。絕不使用
item 1或沒有名稱的灰色長條。 - 給讀者一個控件:步驟、滑桿、切換、播放或停止某個零件。
- 以文字結論行結束,根據主體中的數字計算得出。切勿撰寫固定結果。
- 當圖形可見度達 35% 時執行一次,添加重播按鈕,且永不迴圈。
- 僅動畫化
transform和opacity,使用cubic-bezier(0.23, 1, 0.32, 1)。按下持續 120 到 160 毫秒,揭示持續 200 到 300 毫秒,摺疊持續 380 到 500 毫秒。 - 列表項目交錯 30 到 70 毫秒,僅針對前 8 個項目。
- 保持每個標籤在每個影格中完整可見:無省略號、無重疊、點上無文字。文字 11 px 或以上,結論文字 12.5 px 或以上。
- 在 320 px 寬度時,將面板堆疊為單一欄,並為每個控件提供 40 px 的觸控目標。
- 使用網站上其他頁面未使用過的機構,並將其添加到網站的機構表中。
抖色場(第 3 層):
- 從
--bg、--blueprint和--ink讀取顏色,並在data-theme變更時重新繪製。 - 最多以每秒 30 幀的速度繪製,且僅在條帶可見時繪製。
- 在減少動畫模式下,繪製一個靜態畫面。若無 WebGL,則顯示靜態剖面線。
- 將條帶標記為
aria-hidden="true",並且除了標籤晶片外,不要在點上放置任何文字。
完成前檢查
- fence 名稱與註冊名稱完全相符,且無其他模組註冊該名稱。
- 模組中無
=>、let、const或反引號字串。 - 模組中無
setInterval與requestAnimationFrame。 -
references/smil-rules.md中的驗證器對掛載後的 host 傳回空列表。 - 每個動畫圖形擁有 55 個或少於 55 個 SVG 元素。
- 每個迴圈的持續時間在 2.5 到 6 秒之間。
- 無迴圈動畫化規則 11 中所列的幾何屬性。
- 開啟減少動畫模式時,圖形顯示完整畫面,且無元素遺失。
- 在深色主題中,每條線條與標籤均可見。
- 在 375 px 寬度下,每個標籤均可讀,且頁面在圖形外部無橫向捲動。
- 對於小工具,將每個滑桿移動到最小值和最大值時,不會產生
NaN、負數寬度或控制台錯誤。 - SVG 有一個標題和一個描述,且其 ID 在滑桿移動後保持不變。
- 說明中提及圖形所使用的每種顏色。
- 第 2 層:
references/mechanism-figures.md結尾的檢查清單中的每個項目均通過。 - 第 3 層:
references/dither-fields.md結尾的檢查清單中的每個項目均通過。
檔案
references/smil-rules.md:十二條 SMIL 規則的完整內容、每條規則防止的問題,以及可在瀏覽器控制台中執行的驗證器。references/toolkit.md:LF函數與掛載順序。它還包含一個完整的滑桿小工具、一個完整的 SMIL 圖形,以及一個供課程網站外使用的預覽頁面。references/tokens.md:淺色與深色主題的顏色 token、字型以及動畫時間值。references/mechanism-figures.md:第 2 層。真實名稱、已拒絕的圖形、機構形狀、解剖、結論、動畫預算與檢查。references/dither-fields.md:第 3 層。著色器繪製方式、四種動畫、標記、規則、抖色條帶與檢查。templates/mechanism.html:一個完整的第 2 層圖形範例,一個具有大小控制的 LRU 快取,可在任何瀏覽器中開啟。templates/dither.js:一個完整的第 3 層腳本。載入它並添加<div class="dither" data-seed="...">。
在 AI Engineering from Scratch 儲存庫中,另請參閱 site/lesson-figures.js 以了解執行環境,以及 site/figures-*.js 以查看更多圖形。