昨天的 UIUX 留的待辦是解壓一個 .lottie、數彈簧屬性的關鍵影格。我今天仍然沒有在 Figma 建檔匯出,所以那一項照樣留著;但重讀 LottieFiles 的支援表原文、再把 dotLottie 2.0 規格讀完,發現昨天有三處要更正,而且有一個結論要翻面:我昨天說「彈簧烤進檔案後,執行時沒有任何旋鈕」,對 Lottie JSON 成立,對 dotLottie 不成立,規格白紙黑字給了至少兩條執行時改動的路。另外我用 Python 把彈簧取樣的檔案成本實算了一遍,結果比昨天暗示的小很多。以下每一項都標明出處,或標為推論;只談介面與流程,不碰財經。

📖 學

一、昨天要更正的三處

第一,那張支援表講的是 LottieFiles 外掛,不是 Figma 自己的匯出。 頁面副標題寫「Export timeline animations made with Figma Motion from the LottieFiles plugin」,我昨天把它和 Figma 說明中心那一頁混成同一個匯出器的規格。兩份文件在同一個項目上還互相打架:Figma 說明中心寫投影、雜訊與玻璃效果「won’t update during the animation」,匯出取的是第一格的樣子;LottieFiles 的表卻把投影列為支援,註明「Shadow offset, blur, color, and opacity are exported」。兩頁都是 2026 年 9 月的文件,我無法判斷它們描述的是同一個匯出器的不同說法,還是 Figma 原生匯出與外掛各走各的路。這一點只有實測能分:同一個含投影動畫的檔案,兩條路各匯一次。

第二,被「錄下來」的不只彈簧。 同一頁在支援等級說明下面有一句我昨天漏讀的話:「Some supported features are exported by recording the visible result over time」,並指出像是部分版面與形狀變化沒有直接的 Lottie 對應。表中具體標示這種做法的有兩項:自動版面(auto layout)動態是「Exported from the visible layout result over time」,多邊形邊數是「Exported from the visible geometry over time」;另有一列「複雜版面變化」為部分支援,備註是網格或副軸變動可能要簡化。所以昨天的結論「彈簧是取樣烤死的」要擴大成「彈簧、自動版面、多邊形邊數都是取樣烤死的」,以 Figma Motion 的典型用法,自動版面動畫比彈簧常見得多。

第三,「動畫文字內容」這個詞有定義了。 原文的列是「Animated text content」,備註「Text content keyframes are not currently preserved」,指的是文字字串本身有關鍵影格,也就是字串隨時間被換掉。昨天我說文件沒有定義、可能涵蓋 9 月 30 日新增的逐字、逐詞、逐行動畫;現在可以說,這個詞的字面意思較窄。但逐字動畫仍然沒有任何一列直接回答:表中沒有「每個字元各自動畫」這一項,所以它是否保留依舊是未驗證,只是「表中已列為不支援」這個擔心可以降級。另外新看到一列「Static text appearance」為部分支援,備註「Text may be converted depending on the export path」,沒說轉成什麼,我推測是把文字轉成向量路徑,但文件沒有明說,這是推論。順帶一個小修正:昨天把布林運算籠統寫成不支援,其實 Boolean subtract 是支援的,不支援的是聯集、交集與排除的動畫。還有一個設計上的陷阱:隱藏圖層「excluded from export」,如果減少動態版是靠隱藏某些圖層做出來的,匯出時它們會直接消失,而不是變成不可見。

二、dotLottie 有執行時的旋鈕,Lottie JSON 沒有

昨天的結論來自「Lottie 屬性值就是關鍵影格,沒有執行時可調的東西」。對純 Lottie JSON 這成立,LottieFiles 的 Motion tokens 頁也這麼說:「Exporting as Lottie JSON removes them along with state machines and themes」,並且「A plain Lottie runtime cannot read tokens」。Figma 說明中心對兩種格式的描述是:Lottie 是沒有內建壓縮、每個檔案只能含一個動畫的 JSON;dotLottie 是把動畫與圖片、字型資產打包的壓縮檔。

但 dotLottie 2.0 規格(dotlottie.io/spec/2.0)把檔案定義成 ZIP:manifest.json 加上 a/(一到多個動畫)、t/(主題)、s/(狀態機)、i/(圖片)、f/(字型)。從這個結構讀得出三條規格層面的路,我標明各自的前提:

做法規格依據前提與狀態
主題覆寫動畫屬性主題規則的 value:「Static override value that replaces the original property value」;也可改給 keyframes,關鍵影格可帶 hold 與貝茲把手屬性必須先有 slot ID。Motion tokens 頁說可從程式碼控制「text, colors, transforms, gradients」,但 Figma 匯出的彈簧屬性會不會被標上 slot ID,文件沒說(未驗證)
狀態機挑動畫與播放參數播放狀態有 loop、loopCount、speed、segment、autoplay;輸入有布林型;JS 端有 stateMachineSetBooleanInput(name, value)Figma 的互動匯出只涵蓋原型觸發(點擊、懸停、按下、延遲等)。「用一個減少動態布林值切換兩個動畫」沒有文件說 Figma 會產生,需要手動編輯封裝(推論可行,未測)
只改播放參數同上的 loopCount 與 speed不改曲線形狀,只能壓低重複次數與速度,剛好夠用來處理 5 秒規則

兩點要誠實標出。第一,我在整份 2.0 規格頁搜尋「reduce」「motion」「prefers」,零命中:格式提供的是機制,不是減少動態的政策,要不要根據使用者偏好切換、怎麼切換,全都得自己接線,這和 10 月 3 日讀到 dotlottie-web 原始碼裡沒有 reduced-motion 是同一個結論。第二,主題覆寫「取代原始值」是我讀規格文字的結論,沒有跑過;一個有關鍵影格的屬性被 value 覆寫後會不會真的變成靜態,要用播放器確認。

所以昨天那句話的新版本是:Lottie JSON 匯出的彈簧確實無法在執行時調整,只能另匯出檔案;dotLottie 匯出則在規格上存在不必重新匯出的路,但每一條都需要匯出端配合(slot ID)或手動編輯封裝(狀態機),Figma 目前文件沒有保證。

三、取樣成本:實算後比我昨天暗示的小

昨天我說取樣讓「檔案變大」但沒有量。今天我用 Python 做了一個合成實驗:同樣是昨天那個彈簧(質量 1、剛度 100、阻尼 10,阻尼比 0.5,約 0.8076 秒落入終點正負 2%,峰值過衝 16.3%),讓一個圖層的位置從 0 移到 200,寫成 Lottie 位置屬性的 JSON,比較「取樣成逐影格關鍵影格」和「單一貝茲曲線兩個關鍵影格」。

影格率做法關鍵影格數精簡 JSON 位元組Deflate 最高壓縮後
30 fps彈簧取樣261,690277
30 fps貝茲2121103
60 fps彈簧取樣503,243452

30 fps 時原始 JSON 大約是 14 倍,壓縮後只有 2.7 倍,絕對值是每個屬性多出約 170 位元組。dotLottie 是 Deflate 壓縮的 ZIP,所以實際落在後者。這個數字只在屬性數量達到數百個時才會變成問題;我的關鍵影格格式是自己寫的最簡形式,Figma 的取樣密度與欄位我都查不到,所以這是量級估計,不是 Figma 的實測。結論要降級:取樣的真正代價不是檔案大小,而是前面第二節講的不可調整,以及預覽與正式播放器可能不一致。

四、交付表再調整

前兩天的交付表加到 5 欄。今天依更正再改,把「用哪個匯出器」放到最前面,因為兩份文件已經對同一功能給出不同說法:

欄位填什麼為什麼
匯出路徑與格式Figma 原生或 LottieFiles 外掛;Lottie JSON 或 dotLottie兩者支援表不一致;JSON 會丟掉主題、狀態機與 token
被取樣的屬性彈簧、自動版面、多邊形邊數這些在執行時都不能調
文字動畫類型位移與淡入、旋轉縮放、字串換內容、逐字字串關鍵影格確定不保留,逐字未驗證,旋轉縮放有 pivot 限制
隱藏圖層有或無隱藏圖層不會匯出
減少動態機制獨立檔、主題、狀態機輸入、僅改 loopCount依格式與是否有 slot ID 決定
總時長與循環總格數 ÷ 影格率套 WCAG 2.2.2 的 5 秒規則
驗證方式在正式播放器實看預覽與播放器可能不同

🧠 記

  • 那張支援表是 LottieFiles 外掛的表,不是 Figma 原生匯出的表。 兩者在投影上互相矛盾(外掛說支援、Figma 說明中心說只取第一格)。邊界:我無法判斷是不同匯出器還是文件落差。
  • 被取樣烤進影格的不只彈簧,還有自動版面與多邊形邊數。 另外字串關鍵影格不保留、隱藏圖層不匯出、布林減去支援但聯集交集排除不支援。
  • Lottie JSON 沒有執行時旋鈕;dotLottie 規格有(主題覆寫、狀態機輸入、loopCount),但需要匯出端或手動配合。 規格全文零個 reduced-motion 字樣,政策要自己接線。
  • 單一彈簧屬性取樣的成本量級:30 fps 約 26 個關鍵影格、壓縮後多約 170 位元組。 合成實驗,非 Figma 實測。

✍️ 實踐

這份 30 分鐘清單接續昨天未做的實測,並新增更正後的驗證:

  1. 雙匯出器比對。 做一個含投影與自動版面動畫的 Figma Motion 檔,各用 Figma 原生匯出與 LottieFiles 外掛匯出一份,記下投影是否隨時間變化,用來裁決兩份文件誰對。
  2. 解壓檢查。 把 .lottie 改副檔名為 .zip 解開,看 manifest.json 有沒有 themes、stateMachines,再數彈簧屬性的關鍵影格數與有沒有 h: 1,用實測數字取代今天的 26 個。
  3. 找 slot ID。 在動畫 JSON 裡搜尋 sid,確認哪些屬性被標了 slot ID、被彈簧驅動的位置或縮放有沒有;沒有的話,主題覆寫那條路就走不通。
  4. 逐字動畫實驗。 三個字逐字淡入,匯出並用 dotlottie-web 播放,結果寫進交付表。
  5. 減少動態最小方案。 如果檔案沒有 slot ID,先採最低成本做法:另匯一份把彈簧改 Ease out 或 Hold 的檔,並把循環改成播放 1 次;用 matchMedia('(prefers-reduced-motion: reduce)') 決定載入哪一份。

🔗 延伸學習

💬 問 AI

我在評估 Figma Motion 匯出 Lottie / dotLottie 的減少動態做法。請嚴格分成三區回答:「文章說的」「你查證到的」「你的推論」,三區不能混;不確定就直說,不要編造連結、版本號或數字。
 
文章說的(請當成待查證的主張):
1. LottieFiles 的 Figma Motion export 頁(2026-09-11 更新)描述的是 LottieFiles 外掛的匯出,並說部分功能是「錄下可見結果」匯出,自動版面與多邊形邊數屬此類;「Animated text content」指文字內容關鍵影格,不保留;隱藏圖層不匯出。
2. Figma 說明中心說投影、雜訊、玻璃效果只取第一格;LottieFiles 表卻說投影支援。兩者可能描述不同匯出器。
3. Motion tokens 頁說 token、主題、狀態機只存在於 dotLottie,Lottie JSON 會丟掉。
4. dotLottie 2.0 規格:主題規則的 value 會取代原始屬性值、可改給 keyframes;狀態機播放狀態有 loop、loopCount、speed、segment,輸入有布林型;規格全文沒有 reduced-motion 相關字樣。
5. 合成實驗:阻尼比 0.5 的彈簧在 30 fps 取樣約 26 個關鍵影格,精簡 JSON 約 1,690 位元組,壓縮後約 277 位元組;同動作的單一貝茲約 121 與 103 位元組。
 
請做:
A. 逐點用官方文件或規格驗證 1–5,標示「查證成立/部分成立/查不到」並附連結。
B. 「有關鍵影格的屬性被主題規則 value 覆寫後,會不會變成靜態」,dotlottie-web 或規格有沒有明確說法?沒有就明說沒有。
C. Figma Motion 匯出的 dotLottie,會不會替被動畫的屬性加上 slot ID?只引用文件或實測結果。
D. 在「推論」區回答:沒有 slot ID 時,減少動態版該用獨立檔、手動編輯狀態機,還是只調 loopCount?各自的維護成本與無障礙風險。
E. 給我一份 8 項以內的匯出前檢查表,涵蓋匯出器選擇、格式、被取樣的屬性、5 秒規則、減少動態機制與正式播放器實測。