graphic-gif
從 CSS 動畫或 AI 影像轉影片 API 產生循環動畫 GIF。輸出:animation.gif。
不同於其他輸出靜態 PNG 或 PDF 的 graphic- 技能,此技能輸出的是動畫 .gif。它使用透過 Playwright 和 Web Animations API 逐幀擷取的 CSS @keyframes 動畫(選項 A,預設),或透過 Kling 的 AI 影像轉影片管道(選項 B)。
關鍵規則(每次生成前務必閱讀)
- 預設為 css-animated。 除非明確要求,否則絕不使用
ai-generated。 - 畫布為 800×800 像素正方形。 所有
clamp()值以 800px 計算(1vw = 8px)。 - 單一目足 HTML。 所有 CSS 內嵌在
<style>中。字型 CDN<link>是唯一的外部依賴。 - 絕不在聊天中輸出 HTML。 儲存到檔案,僅顯示摘要。
- 影格擷取使用 Web Animations API 搜尋。 禁止使用
setTimeout循環或animation-delay技巧。 - 精確影格數:
Math.floor(duration_seconds * fps)個影格。在t=duration_ms時的影格不得擷取——它會與t=0重複,導致循環點出現明顯的停頓。 - 無佔位方塊。 僅使用 CSS 生成的視覺元素。不包含「此處放置圖片」之類的元素。
- 較簡單的調色盤 = 較小的檔案。 使用:
clean-slate、terminal、electric-burst、brutalist。 - 不要使用 animation-delay 來實現錯開效果。 將錯開效果直接寫入
@keyframes的百分比——影格搜尋會處理時序。 - 在撰寫 CSS 之前先確定設計方向。 基調、標誌性元素、動感風格、令人難忘的細節——所有這些在編寫第一行程式碼之前就應決定。
步驟 1:接收輸入
必要參數: prompt(內容描述和動畫簡報)
可選參數(含預設值):
| 參數 | 預設值 | 選項 |
|---|---|---|
| animation_type | css-animated | css-animated / ai-generated |
| duration | 3.0 | 秒 |
| fps | 12 | 每秒影格數 |
| loop | true | true / false |
| style | clean-slate | clean-slate / terminal / electric-burst / brutalist |
| dimensions | 800x800 | 寬x高(像素) |
| optimization | balanced | quality / balanced / filesize |
如果缺少 prompt 或缺少動作描述,請確切詢問:
「GIF 應該顯示什麼?請描述內容和動作(例如:'統計數字逐一增加:73% 的買家在購買前閱讀 3 篇以上的內容。打字機效果,一次一個字元。風格:terminal。3 秒,12fps。')
關鍵設定(皆為可選,顯示預設值):
- animation_type:css-animated(預設)或 ai-generated
- duration:3.0 秒
- fps:12
- loop:true
- style:clean-slate(選項:clean-slate / terminal / electric-burst / brutalist)
- dimensions:800x800
- optimization:balanced(選項:quality / balanced / filesize)」
如果所有必要資訊都已提供 → 直接跳至步驟 2。
步驟 2:內部架構(不對使用者顯示)
針對 css-animated:
- 從以下動畫類型中選擇一種:
fade-in、slide-in、typewriter、counter、pulse、loop-scroll - 閱讀
references/animation-library.md— 找到所選類型的完整 HTML/CSS 規範 - 閱讀
references/style-presets.md— 載入所選樣式的 CSS token 區塊 - 計算影格數:
Math.floor(duration_seconds * fps)— 記下這個數字 - 確定設計方向:
| 決策項目 | 從何推導 |
|---|---|
| 基調 | 目標受眾的情緒感受(機械化 / 溫暖 / 電光 / 專業) |
| 標誌性元素 | 一致使用的一種視覺裝置(游標閃爍、幽靈數字、掃描線疊加、強調邊框) |
| 動感風格 | 此類型的緩動曲線哲學(彈簧 / 線性 / 步進 / 緩入緩出) |
| 令人難忘的細節 | 觀看者對這個 GIF 會記住的「唯一一件事」 |
針對 ai-generated:
- 產生基本靜止影格 HTML(畫布的海報風格佈局)
- 使用螢幕截圖匯出為 PNG
- 呼叫 Kling API:
POST https://api.klingai.com/v1/videos/image2video,附帶image_url和描述動作的prompt - 輪詢任務完成狀態
- 下載影片 → 使用 ffmpeg 轉換為 GIF:
# 雙次調色盤以獲得最佳色彩品質 ffmpeg -i input.mp4 -vf "fps=12,scale=800:800:flags=lanczos,palettegen=stats_mode=diff" palette.png ffmpeg -i input.mp4 -i palette.png -vf "fps=12,scale=800:800:flags=lanczos,paletteuse=dither=bayer:bayer_scale=5" output.gif
步驟 3:HTML 生成(css-animated 路徑)
在生成之前,請閱讀 references/animation-library.md 和 references/style-presets.md。
畫布基礎——每個 GIF 都需要:
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: 800px;
height: 800px;
overflow: hidden;
background: var(--bg);
font-family: var(--font-body);
}
.canvas {
width: 800px;
height: 800px;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
動畫規則:
- 所有動畫元素設定
animation-fill-mode: forwards(或both) - 各類型的時序函數:
typewriter→steps(N, end),其中 N = 精確字元數counter→linearfade-in→cubic-bezier(0.22, 1, 0.36, 1)(緩出)slide-in→cubic-bezier(0.34, 1.56, 0.64, 1)(彈簧過衝)pulse→ease-in-out搭配animation-iteration-count: infiniteloop-scroll→linear搭配animation-iteration-count: infinite
- 對於一次性動畫(fade-in、slide-in、typewriter、counter):
animation-iteration-count: 1——循環發生在 GIF 層級 - 不要使用
animation-delay——錯開效果已寫入@keyframes百分比
打字機 N 的計算方式: 計算每個字元,包括空格、標點符號、數字:
- 「73% of buyers」= 14 個字元 →
steps(14, end) - 「Hello, World!」= 13 個字元 →
steps(13, end)
計數器 CSS @property(計數器類型必須使用):
@property --num {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
.counter {
animation: countUp var(--duration) linear forwards;
counter-reset: num var(--num);
}
.counter::after { content: counter(num); }
@keyframes countUp {
from { --num: 0; }
to { --num: var(--target); }
}
循環滾動:內容必須複製:
<!-- 4 個原始項目 + 4 個重複項目 -->
<div class="ticker-track" style="--item-count: 4;">
[item1][item2][item3][item4][item1][item2][item3][item4]
</div>
translateX(0 → -50%) 搭配 linear infinite。
設計品質規則(來自步驟 2 的確定事項):
- 指定的標誌性元素必須存在於 CSS/HTML 中(不僅是描述)
- 字體排版:顯示文字與輔助文字之間的字重對比至少 2:1(例如 700 比 400)
- 背景:深色樣式不要使用純白色
#fff——請使用該預設的確切--bg值 - 對於 terminal 風格:使用
::after添加掃描線疊加,搭配repeating-linear-gradient,opacity: 0.03 - 對於 brutalist:在關鍵元素上使用粗邊框
4px solid #000或4px solid var(--accent) - 令人難忘的細節:如果需要額外元素——立即添加
步驟 4:自我 QA(在步驟 5 之前修復所有失敗)
畫布:
-
body和.canvas精確為 800×800px(或指定的尺寸) -
body和.canvas都設有overflow: hidden - 沒有元素超出畫布邊界
動畫:
- 任何地方都沒有
animation-delay——錯開效果已寫入@keyframes百分比 - 所有動畫從
t=0開始(Web Animations API 將從那裡搜尋) - 所有動畫元素設定
animation-fill-mode: forwards或both - 一次性動畫:
animation-iteration-count: 1 - 無限動畫(pulse、loop-scroll):
animation-iteration-count: infinite
類型特定檢查:
- 打字機:
steps(N, end)中的 N = 文字字串的精確字元數 - 計數器:已宣告
@property --num,包含syntax: '<integer>'和initial-value: 0 - 計數器:已設定
counter-reset: num var(--num)和::after { content: counter(num) } - 循環滾動:內容在 HTML 中精確複製一次
設計:
- 無佔位方塊
- 已根據
references/style-presets.md套用樣式預設 token——沒有自由使用的十六進位顏色 - 步驟 2 中命名的標誌性元素確實存在於 HTML/CSS 中
- 步驟 2 中令人難忘的細節已實際實作
- 所選風格的字型已引入字型 CDN
<link>
步驟 5:匯出
根據 prompt 決定 slug(kebab-case,≤30 個字元)。建立輸出目錄:
mkdir -p [slug]
儲存 HTML:
[slug]/animation.html
在瀏覽器中開啟以進行快速視覺檢查:
open [slug]/animation.html
執行匯出腳本(將 [skill-root] 取代為此技能的實際路徑):
bash [skill-root]/scripts/export-gif.sh \
[slug]/animation.html \
[slug]/animation.gif \
--duration [duration] \
--fps [fps] \
[--no-loop if loop=false] \
--optimization [optimization] \
--width [W] \
--height [H]
此腳本會:
- 在暫存目錄中安裝
gifenc、sharp(或jimp)和playwright - 如果尚未快取,則下載 Chromium
- 執行
capture-and-encode.mjs——暫停動畫、搜尋每個影格、螢幕截圖、組合 GIF - 如果可用,執行
gifsicle最佳化處理 - 報告檔案大小並開啟結果
如果在 [skill-root]/scripts/export-gif.sh 找不到匯出腳本,請檢查技能是否已安裝其完整的 scripts/ 資料夾。
步驟 6:輸出摘要
在成功匯出後顯示:
## GIF:[1 行描述]
日期:[YYYY-MM-DD] | 風格:[style] | 動畫類型:[type] | [duration]秒 @ [fps]fps
尺寸:[WxH] | 影格數:[N] | 循環:[true/false]
檔案
原始檔: [slug]/animation.html
輸出檔: [slug]/animation.gif
大小: [X] KB
檢查清單
- [ ] 預覽在起點/終點處能乾淨循環(無停頓)
- [ ] 在預期顯示尺寸下文字清晰可讀
- [ ] 檔案大小適當:電子郵件 <500KB / 社群媒體 <3MB
AI 生成路徑(選項 B)
僅在明確指定 animation_type: ai-generated 時使用。
需求:
- 環境變數中存在 Kling API 金鑰:
KLING_API_KEY(每天 66 個免費額度,免費層無需信用卡) - 本機安裝
ffmpeg用於影片→GIF 轉換
工作流程:
- 產生符合 prompt 的基本靜止影格 HTML(指定尺寸的海報/圖形風格)
- 將靜止影格匯出為 PNG:
# 透過 Playwright 快速截圖 node -e " const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: W, height: H } }); await page.goto('file://[slug]/animation.html'); await page.screenshot({ path: '[slug]/base-frame.png' }); await browser.close(); })(); " - 上傳到 Kling 影像轉影片端點
- 使用 ffmpeg 雙次調色盤將結果轉換為 GIF
- 套用 gifsicle 最佳化
當 Kling 不可用時: 回退到 css-animated,並通知使用者:「AI 生成需要 Kling API 金鑰 (KLING_API_KEY)。正在回退到 css-animated。請設定金鑰以啟用 AI 生成。」
提示建議(當使用者尋求指導時顯示)
「請描述動作,而不僅僅是內容。『統計數字逐一增加』勝過『顯示統計數據』。」
「為減小檔案大小,請保持簡單。1–3 個動畫元素和一個純色背景即可。」
「以循環為思考出發點。動畫應能從結尾無縫流動回開頭。」
「明確指定動畫類型。
typewriter和counter對社群媒體最有效。」✅ 良好範例:「建立一個動畫 GIF,css-animated,打字機效果。文字:'73% of B2B buyers read 3+ pieces of content before contacting sales.' 每個字元逐一打出。風格:terminal。3 秒,12fps,loop=true。」
❌ 不良範例:「製作一個行銷技巧的動畫 gif」