Figma → Landing Page
從 Figma 設計稿生成可部署的靜態活動落地頁:index.html + css/main.css + js/{tool,pm_main,main}.js + images/*.webp。
呼叫:/figma-landing-page <Figma 連結> [活動名稱] [輸出目錄]
固定契約(任何情況下不得偏離):
- 模板佔位符恰好 3 個:
__PAGE_TITLE__、__FUNCTION_NAME__(均在 main.js,title 另出現在 index.html)、__PC_BASE__(在 tool.js;375 = 僅 H5 幀;1920 = H5+PC 雙幀)。 - CTA 元素必須額外掛
.join-btn(固定 JS 的選擇器契約),與 BEM 類並存。 - 斷點 576px 三處統一:JS rem 分支、CSS
@media (min-width: 576px)、platform 判定。 - px 歸一化:H5
px × 375 ÷ H5幀寬 ÷ 100 = rem;PCpx × 1920 ÷ PC幀寬 ÷ 100 = rem。 - 模板 js 三件(
tool.jsrem 適配 /pm_main.jspostMessage 橋 /main.js活動業務層,載入順序即此)固定段一個字都不改;頁面互動只插在main.js的// === Page-specific interactions ===之下(IIFE 內部,可直接用$p/pm/track/Date.prototype.format)。 - 詳細規則(切圖邊界、類名、互動推斷表)見
references/patterns.md,交付標準見references/checklist.md——生成前先讀這兩個檔案。
Step 1 — 解析輸入與環境檢查
- 從連結提取 file key 與 node-id。node-id 連字符轉冒號(
123-456→123:456)後再調任何 Figma API;調 API 得到 404/空結果時第一時間檢查這一步。 - 三項環境檢查(不通過先修復再繼續):
- Figma MCP 已連接(未連接則引導使用者認證,認證類互動不計入確認門的「唯一一次打斷」)。先調
whoami(豁免限額)確認席位:View/Collab 或 Starter 席位僅 6 次 MCP 呼叫/月——預算緊張時跳過 MCP,直接走 Step 2/4 的 REST 路線(PAT 存~/.figma_token,缺失時請使用者在 Figma Settings → Security 生成,讓使用者在自己終端寫入檔案避免入聊天記錄)。 which cwebp——缺失則告知使用者brew install webp;使用者拒絕安裝則整頁回退 png 產物,並在交付報告註明。node -e "require('playwright-core')"——缺失則在 scratchpad 目錄npm i playwright-core;瀏覽器複用本機 Chrome(channel: 'chrome'),不下載瀏覽器二進位檔。
- Figma MCP 已連接(未連接則引導使用者認證,認證類互動不計入確認門的「唯一一次打斷」)。先調
- 輸出目錄預設
./output/<活動名稱-slug>/(skill 全部產物統一放output/下;活動名稱未提供時從 Figma 頁面/幀名推斷,於確認門核對)。目錄已存在且非空時不要現在打斷——覆蓋確認屬於確認門內容。
Step 2 — 盤點設計稿
- 用稀疏元資料工具(get_metadata 類)讀節點樹;不要對根幀一次性拉全量 design context。
- MCP 不可用/預算盡時:REST
GET /v1/files/<key>/nodes?ids=<node>(不帶 depth = 全子樹 JSON,含文字全文、字型、fills 漸變原值、精確 bbox——資訊比 get_metadata 更全)。存本地反覆解析,一次呼叫管全程;CSS 色值/漸變/文案直接取自該 JSON,無需 get_code。 - 幀識別:寬 ≤ 480 → H5 幀;≥ 1200 → PC 幀;無法判定的幀列入確認門。僅 H5 幀 →
__PC_BASE__ = 375;H5+PC 雙幀 →__PC_BASE__ = 1920。 - 產出資產清單:section 列表(hero、banner、steps、tnc…);每個節點標註 切圖 / 真文字 / 互動元件(判定規則見
references/patterns.md)。 - 標出所有 CTA(Join Now / 註冊 / Sign Up 類按鈕)——它們要掛
.join-btn。
Step 3 — 確認門(正常流程中生成前唯一一次打斷)
一條訊息列全以下內容,一次拿到使用者確認;此後直到交付不再打斷:
- 活動名稱、
__PAGE_TITLE__值、__FUNCTION_NAME__值(如WinsdayBillionDropLandingPage) - 輸出目錄(目錄非空時在此確認是否覆蓋)
- 切圖清單(節點 →
images/<name>.webp) - CTA 節點清單
- 互動清單:每項附推斷依據和所需參數(倒數計時→截止時間/到期行為;輪播→自動播放/間隔;彈窗→觸發時機;表見
references/patterns.md)。設計稿推不出的參數讓使用者在這裡填寫;無法歸類的節點標註「靜態」。 - 幀識別存疑項
Step 4 — 導出切圖(四級兜底鏈路,按可用性降級)
- MCP
download_assets(席位預算充足時):每批 ≤ 20 節點、scale 2x、format png;臨時 URL 用 curl 下載。 - REST 渲染
GET /v1/images/<key>?ids=…&format=png&scale=2:ids 逗號批量但每批 ≤ 4 個大節點(超了報 "Render timeout");429 = 席位渲染預算盡(View 席位約 12 張後觸發、視窗小時級),換下一級,別死等。 - REST 原圖端點
GET /v1/files/<key>/images:返回全檔案 imageRef → 原圖 URL 映射,走檔案預算、幾乎不受渲染限流。適合一切圖片填充節點(照片/貼紙/圖示——節點 JSON 的fills[].imageRef對上號即得原始解析度,常遠超 2x,按 fill 的 scaleMode 裁切/trim alpha 後縮放)。不適用向量合成節點(面板/緞帶)。 - 使用者手動導出(零配額):請使用者在 Figma 選中節點 Export。首選 SVG 格式——向量部分無限清晰、點陣圖以原始解析度 base64 內嵌(可正則抽取
<image>解碼,是抽透明元素的最佳來源)。SVG→2x 點陣圖光柵化管線:把 SVG 拷到臨時目錄(kebab 安全檔案名,原名常含&/空格)、寫同目錄 HTML 包裝<img src="./x.svg">(file:// 直開 SVG 或跨目錄 file 引用都會被 Chrome 拒載)、playwrightdeviceScaleFactor:2+omitBackground:true截圖得透明 PNG。
- 通用:轉 webp
cwebp -q 80;命名語義化 kebab-case,不帶 hash;純漸變/純色節點直接讀 JSON 寫 CSS,不出圖。 - 注意:Figma 導出的 SVG viewBox 可能含投影/出血(比節點框大),容器按節點框定位時讓圖等比溢出,勿壓扁。
- 單圖導出失敗:重試 2 次 → 降級下一鏈路;全鏈路失敗才跳過並記入交付報告。
Step 5 — 生成程式碼
- 從
assets/template/起步:base.css內容作為css/main.css的開頭骨架(產物只有單個 main.css,不單獨輸出 base.css)。 index.html:替換<title>;字型 link 換成設計稿字型(Google Fonts 匹配不到時選最接近並記入報告);#app內按 section 生成語義化結構,BEM 類名(.hero__bg、.banner__headline),CTA 元素額外掛join-btn。css/main.css:數值取自 Figma 精確尺寸/色值/漸變(get_code 的 plain HTML+CSS 輸出可輔助取值),全部先做 px 歸一化再寫 rem;背景background-image,內容圖<img>。雙幀頁:H5 規則在前,PC 覆蓋全部放@media (min-width: 576px)。js/:拷貝模板三件(tool.js / pm_main.js / main.js),替換 3 個佔位符(tool.js 的__PC_BASE__、main.js 的另外兩個);確認過的互動程式碼插在 main.js 的 marker 之下。- 設計裡出血到幀邊緣被裁的元素(bbox 超出幀寬),容器要
overflow: hidden復現幀裁切,否則頁面橫向溢出。 - 自檢:
node --check js/*.js三件全部通過。
Step 6 — 截圖比對迭代(按 section 分塊,上限 3 輪)
- 在輸出目錄起本地服務:
python3 -m http.server <埠>。 - 把以下截圖腳本寫到 scratchpad 並用它按 section 分塊截圖(clip 座標從 DOM 拿:
page.evaluate裡對每個 section 元素取getBoundingClientRect):
// shot.mjs <url> <out.png> <width> <dsf> [clipY clipH]
import { chromium } from 'playwright-core';
const [url, out, width, dsf, clipY, clipH] = process.argv.slice(2);
const browser = await chromium.launch({ channel: 'chrome' });
const page = await browser.newPage({
viewport: { width: +width, height: 800 },
deviceScaleFactor: +dsf,
});
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot(clipY === undefined
? { path: out, fullPage: true }
: { path: out, clip: { x: 0, y: +clipY, width: +width, height: +clipH } });
await browser.close();
- H5 比對:本地 width 375、dsf 2;Figma 側用
download_assets按 section 節點導出 2x png 比對圖(比對圖放 scratchpad,不進images/)。 - 逐 section 並排比對、逐差異修正;最多 3 輪,仍有差異則記入交付報告。
- 比對收斂後,另以 width 414(dsf 2)整頁快速回歸一次,確認無錯位溢出(checklist 要求 375/414 兩檔)。
- 整幀截圖只用於交付報告觀感,絕不作為差異判定依據(長頁整幀會被降取樣到看不清字型大小/色差)。
- 雙幀頁:另以 width 1920、dsf 1 對 PC 佈局重複以上分塊比對(對 PC 幀 1x 導出圖);並以 width 1280 整頁快速回歸(checklist 雙幀檔要求 1280/1920)。
- 順手檢查:瀏覽器 console 無報錯(
page.on('console')或開發者工具)。
Step 7 — 交付
交付報告包含:
- 輸出目錄樹
references/checklist.md逐項勾選結果- 剩餘已知差異(3 輪內未消除的)
- 分塊比對截圖路徑
- 用過的兜底(png 代 webp、近似字型、跳過的切圖)
錯誤處理速查
| 場景 | 處理 |
|---|---|
| Figma MCP 未連接/認證失效 | 引導認證後從中斷步驟繼續(不計入確認門打斷) |
| node-id 調 API 404/空 | 檢查連字符→冒號轉換 |
| 切圖導出失敗/限流 429 | 重試 2 次 → 降級下一級鏈路(見 Step 4)→ 仍失敗跳過 + 記報告 |
| cwebp 缺失且使用者拒裝 | 產物回退 images/*.png + 記報告 |
| 幀結構無法識別 | 列入確認門問使用者(要具體 node-id) |
| 輸出目錄非空 | 確認門內一併確認覆蓋 |