1仕組みと動作原理
「Figma → コンポジション」の処理を機能ごとに5つのフェーズ(静的アセット / ブランドトークン / コンポーネント / モーション / シェーダー)に分割。前3フェーズはREST + CLIを使用し、後2フェーズはRESTに対応するものがないためコネクタまたはネイティブエクスポートに依存します。
Bring the user's Figma work into a composition. **Split by capability** (design spec §2):
RESTをデフォルトの通信経路(バッチ処理・ヘッドレス実行対応)とし、コネクタはモーション/シェーダー用のオプションとして位置づけます。レンダリングの決定性を保証するため、どちらの経路でもインポート時にアセットをローカルへ凍結します。
REST is used wherever it can be (usable at volume, headless). A compatible Figma connector is optional for motion and shader data; without one, ask for a native export. Every path freezes assets locally so renders stay deterministic.
最初のステップではコマンドを実行せず認証情報の事前確認を行います。シェル環境またはプロジェクトの.env内に読み取り専用のFIGMA_TOKENが存在することを確認し、未設定の場合は一度だけセットアップを案内して停止します。「とりあえず実行してエラーを拾う」ことは禁止します。
**Preflight — before the first CLI call, check a token exists**: shell env (`[ -n "$FIGMA_TOKEN" ]`) **or** the project `.env` (the CLI auto-loads it — a `.env` entry counts as configured).
アセットインポートは「冪等性・凍結・トレーサビリティ」を徹底します。fileKey:nodeId:format:scale:versionに基づいて冪等性を保ち、生成物は.media/images/に配置し、ソース情報をmanifestに記録してmedia-useの共有インデックスを再構築します。
Idempotent per `fileKey:nodeId:format:scale:version`.
フレーム全体のアセット取得時は複数ノードを単一の/v1/imagesリクエストに統合して分あたりのレート制限を回避します。逆に絵コンテの一括エクスポートはチャンク分割します(12個を超えるIDではレンダータイムアウトが発生するため、約4個ずつに分割)。
All render in a single `/v1/images` call, which is figma's own answer to the per-minute rate limit
コンポーネントフェーズではノードツリーを幾何学的に正確な編集可能HTMLへ再構築し、「値ではなくIDに基づく」トークンバインディングを実行します。インポート済みトークンにはvar(--slug, literal)をバインドし、未知のトークンはリテラル値を維持しつつフラグ付けします。
Bound to an **unknown** token → literal + `data-figma-unresolved` flag.
モーションフェーズは「機械的デコード + 客観的ゲートチェック」を採用。コネクタから取得したモーションコンテキストは純粋なヘルパーでデコードし(手動でのキーフレーム転記を禁止、ループ折り返し末尾フレームを除去)、verify-motion.mjsでエクスポート動画のモーションエネルギーを比較し、15dB未満は不合格とします。
it compares motion-energy deltas (static import fidelity cancels out) and fails below 15dB min motion-PSNR
絵コンテセクションは推測ではなく機械的構文に従ってデコードします。サイズでシーン単位をフィルタリングし、x座標で順序付け、隣接フレームの差分から要素チェーンを導出し、各チェーンにつき1つのアセットのみをエクスポートします。各フレームが同一UIである場合は「UIの再構築 + フレーム差分を1インタラクションとして扱う」アプローチへ昇格させます。
**The cardinal rule: storyboard frames are KEYFRAMES, not slides.**
2コア機能
3外部依存関係
| Kind | Dependency / Endpoint |
|---|---|
| cli | hyperframes CLI 的 figma 子命令(asset / tokens / component)与 check 门禁 |
| api | Figma REST 批量渲染导出(host 未在 SKILL.md 出现,只写了路径) |
| api | Figma REST published-styles 回退(非 Enterprise 变量降级路径,需 library_content:read) |
| network | 用户粘贴的 figma.com 链接(解析 fileKey / nodeId 后走 REST);取 token 的引导页在 figma.com/settings |
| network | 可选的兼容 Figma 连接器(运动上下文与着色器数据;与本 skill 的 token 分开授权;未指名具体服务) |
| package | @hyperframes/core/figma 纯 helper(motionContextToDocs 解码、motionToGsap、emitTimelineScript) |
| cli | ffprobe / ffmpeg(仅 verify-motion.mjs 以数组参数子进程调用,抽帧与 PSNR) |
| network | GSAP + CustomEase CDN(注入合成 HTML 的 script 标签;产物期由浏览器拉取,按范式不判级) |
4推奨統制措置と判定根拠
- scripts/: ローカルスクリプトまたはコマンドの実行: node skills/figma/scripts/verify-motion.mjs --reference <export.mp4> --rend
- 网络端点: 外部ネットワークアクセスの宣言: Figma REST 読み取り専用API呼び出し(/v1/images バッチエクスポート、/v1/files/:key/styles フォールバック、node tree、variable
- 本地工作目录: ファイルの読み書きと成果物出力: .media/images/(凍結されたFigmaレンダリングアセット)、.media/manifest.jsonl(ソース来歴台帳)、.media/index.md(
5二重目の独立検証
- [ok] FIGMA_TOKEN 是否真被读取并用于外发(橙档判定的关键证据) — SKILL.md 第 26 行给出预检(`[ -n "$FIGMA_TOKEN" ]` 或项目 .env),第 28–30 行给出取 token 的一次性设置与「never ask them to paste the token into the conversation」;第 36 行给出 401/403/429 的处置语义。读取与实际 REST 调用发生在官方 hyperframes CLI 侧,本 skill 的目录只声明并约束该行为——与 hyperframes-cli 同口径,故橙档依据记在 SKILL.md 的声明面,并注明执行主体。
- [unlocatable] Figma REST 的具体 host 能否在源码内定位 — SKILL.md 只写出路径(`/v1/images`、`/v1/files/:key/styles`),未出现 api.figma.com 或任何 host;连接器也未指名具体服务。故 external_deps.endpoint 按「仅路径」标注,不补写推测域名。
- [ok] verify-motion.mjs 的外部接触面(是否有隐藏网络/凭证/越界写入) — 全文 154 行只 import node:child_process / node:fs / node:os / node:path;调用为 execFileSync("ffprobe", …)、execFileSync("ffmpeg", …)、spawnSync("ffmpeg", …) 三处,全部数组参数无 shell;无 fetch、无 process.env、无凭证;写入仅限 mkdtempSync(join(tmpdir(), "verify-motion-")) 下的临时图,结束 rmSync 清理。阈值与标定写在文件头注释里(忠实 min 20.3dB / 发散 min 5.0dB,默认阈值 15dB)。
- [ok] 「连接器不执行 shader、会压平」这一关键警告是否自洽(会不会是夸大) — Phase 5 段与 Phase 4 步骤 4 的例外说明互相印证:两处都指向「请用户原生导出」,且 Phase 4 明确 shader 轨道烘焙会静默丢 shader。属同一声明的两处一致陈述,非矛盾。
- [ok] 「分镜帧是关键帧而非幻灯片」是否只是口号 — 同一段给出可机械执行的规则:场景单元按尺寸(如 >1400×900)过滤、顺序按 absoluteBoundingBox.x、相邻帧按 name 再按几何相似匹配成元素链、每链一资产、批量导出分块(~4/次,26 场景 ≈52 次单资产调用是反面教材),并给出升级判据(同一 UI 逐帧 → 重建 app、把帧差当作交互)。
6結論
22ae9717e5a19361…