Communitygithub.com

Parcha-ai/build

在 HyperFrames HTML 中建立影音合成、動畫、標題卡、疊層、字幕、語音旁白、音訊反應式視覺效果與場景轉場。在需要建立任何基於 HTML 的影音內容時使用。

build 是什麼?

此技能定義了一套以 HTML 為中心的影音製作工作流程,將 HTML 視為影音的最終真理來源。使用者可以透過撰寫帶有 `data-*` 屬性來控制時間、GSAP 時間軸來處理動畫,以及 CSS 來定義樣式的 HTML 檔案,來建立完整的影音合成。其主要優勢在於其強制性的「先佈局,後動畫」方法論:它要求開發者先將每個場景的「英雄幀」建構為靜態 HTML/CSS,然後再使用 GSAP 在該位置進行動畫進出。這種方法消除了由於猜測元素的最終位置而導致的意外重疊問題,確保了可預測且可渲染的結果。此技能支援多個平台(如 Claude Code、Cursor),並詳細說明了強制性的規則,包括嚴格的時間限制(無 `repeat: -1`)、同步時間軸建構(無 `async/await` 用於時間軸建立)、特定的場景轉場協定(始終使用轉場,僅在最後一個場景使用出場動畫),以及自動化品質檢查(如 WCAG 對比度稽核和動畫地圖)。它還透過 `hyperframes-cli` 介面簡化了 `init`、`lint`、`preview`、`render`、`transcribe` 和 `tts` 等 CLI 命令。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Parcha-ai/build/tree/HEAD/.agents/skills/hyperframes

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

預覽

來自技能 README

說明文件

HyperFrames

HTML 是影片的真實來源。一個合成是一個帶有 data-* 屬性用來控制時間的 HTML 檔案,一個 GSAP 時間軸用來控制動畫,以及 CSS 用來控制外觀。框架負責處理剪輯的可見性、媒體播放和時間軸同步。

方法

在撰寫 HTML 之前,先從高層次思考:

  1. 什麼 — 觀眾應該體驗到什麼?識別敘事弧線、關鍵時刻和情感節拍。
  2. 結構 — 有多少個合成,哪些是子合成,哪些是內聯的,哪些軌道承載什麼內容(影片、音訊、疊層、字幕)。
  3. 時間 — 哪些剪輯驅動持續時間,轉場落在哪裡,節奏如何。
  4. 佈局 — 先建立結束狀態。請參閱下方的「先佈局,後動畫」。
  5. 動畫 — 然後使用下面的規則加入動畫。

對於小型編輯(修正顏色、調整時間、加入一個元素),直接跳到規則部分。

如果未提供 visual-style.md 或動畫方向,請遵循 house-style.md 以獲得運動預設值、尺寸和調色板。

先佈局,後動畫

將每個元素放置在其最明顯的時刻所在的位置——也就是它完全進入、正確定位且尚未退出的影格。先將其撰寫為靜態的 HTML+CSS。暫時不使用 GSAP。

為什麼這很重要: 如果你將元素定位在其動畫起始狀態(螢幕外、縮放為 0、透明度為 0),然後將其補間到你認為它們應該落地的位置,你只是在猜測最終的佈局。重疊問題在影片渲染之前是看不見的。透過先建立結束狀態,你可以在加入任何動畫之前看到並修復佈局問題。

流程

  1. 為每個場景識別英雄影格 — 元素同時可見數量最多的時刻。這就是你要建構的佈局。
  2. 為該影格撰寫靜態 CSS。.scene-content 容器必須使用 width: 100%; height: 100%; padding: Npx; 並搭配 display: flex; flex-direction: column; gap: Npx; box-sizing: border-box 來填滿整個場景。使用 padding 將內容向內推 — 絕對不要在內容容器上使用 position: absolute; top: Npx。當內容高於剩餘空間時,使用絕對定位的內容容器會溢出。保留 position: absolute 僅用於裝飾性元素。
  3. 使用 gsap.from() 加入入場動畫 — 從螢幕外/不可見的狀態動畫到 CSS 位置。CSS 位置是最終的真實狀態;補間動畫描述了到達那裡的過程。
  4. 使用 gsap.to() 加入出場動畫 — 從 CSS 位置動畫到螢幕外/不可見的狀態。

範例

/* scene-content 填滿場景,padding 定位內容 */
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title {
  font-size: 120px;
}
.subtitle {
  font-size: 42px;
}
/* 容器可填滿任何場景大小 (1920x1080, 1080x1920 等)。
   Padding 定位內容。Flex + gap 處理間距。 */

錯誤 — 硬編碼尺寸和絕對定位:

.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex; /* ... */
}
// 步驟 3: 動畫進入這些位置
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);

// 步驟 4: 動畫退出這些位置
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);

元素跨時間共享空間時

如果元素 A 在元素 B 進入同一區域之前退出,兩者都應該有各自英雄影格的正確 CSS 位置。時間軸的順序保證了它們在視覺上永遠不會共存——但如果你跳過了佈局步驟,你就不會發現它們因為時間錯誤而意外重疊的情況。

何謂刻意重疊

分層效果(文字後的光暈、陰影元素、背景圖案)和 Z 軸堆疊設計(卡片堆疊、深度圖層)是刻意的。佈局步驟的目的是捕捉非刻意的重疊——兩個標題疊在一起、一個統計數字蓋住標籤、內容溢出影格邊界。

資料屬性

所有剪輯

屬性必要值
id是唯一識別碼
data-start是秒數或剪輯 ID 參考 ("el-1", "intro + 2")
data-duration用於 img/div/子合成時必要秒數。影片/音訊預設為媒體持續時間。
data-track-index是整數。相同軌道的剪輯不能重疊。
data-media-start否來源的修剪偏移量(秒)
data-volume否0-1(預設為 1)

data-track-index 不影響視覺層疊——請使用 CSS z-index。

合成剪輯

屬性必要值
data-composition-id是唯一的合成 ID
data-start是開始時間(根合成:使用 "0")
data-duration是優先於 GSAP 時間軸持續時間
data-width / data-height是像素尺寸(1920x1080 或 1080x1920)
data-composition-src否外部 HTML 檔案的路徑

合成結構

透過 data-composition-src 載入的子合成使用 <template> 包裝。獨立合成(主 index.html)不使用 <template>——它們直接將 data-composition-id 的 div 放在 <body> 中。在獨立檔案上使用 <template> 會隱藏瀏覽器中的所有內容並破壞渲染。

子合成結構:

<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    <!-- 內容 -->
    <style>
      [data-composition-id="my-comp"] {
        /* 作用域樣式 */
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
    <script>
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });
      // 補間動畫...
      window.__timelines["my-comp"] = tl;
    </script>
  </div>
</template>

在根目錄中載入:<div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>

影片與音訊

影片必須為 muted playsinline。音訊始終是獨立的 <audio> 元素:

<video
  id="el-v"
  data-start="0"
  data-duration="30"
  data-track-index="0"
  src="video.mp4"
  muted
  playsinline
></video>
<audio
  id="el-a"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="video.mp4"
  data-volume="1"
></audio>

時間軸合約

  • 所有時間軸皆以 { paused: true } 開始——播放器控制播放
  • 註冊每個時間軸:window.__timelines["<composition-id>"] = tl
  • 框架會自動巢狀化子時間軸——請勿手動加入
  • 持續時間來自 data-duration,而非 GSAP 時間軸長度
  • 切勿建立空的補間動畫來設定持續時間

規則(不可協商)

確定性: 沒有 Math.random()、Date.now() 或基於時間的邏輯。如果需要偽隨機值,請使用播種的 PRNG(例如 mulberry32)。

GSAP: 僅能動畫視覺屬性(opacity、x、y、scale、rotation、color、backgroundColor、borderRadius、變形轉換)。不要動畫 visibility、display,或呼叫 video.play()/audio.play()。

動畫衝突: 絕不能從多個時間軸同時對同一個元素的同一個屬性進行動畫。

無 repeat: -1: 無限重複的時間軸會破壞捕捉引擎。從合成持續時間計算確切的重複次數:repeat: Math.ceil(duration / cycleDuration) - 1。

同步時間軸建構: 不要在 async/await、setTimeout 或 Promise 內部建構時間軸。捕捉引擎在頁面載入後同步讀取 window.__timelines。字體由編譯器嵌入,因此可以立即使用——無需等待字體載入。

絕對不要:

  1. 忘記註冊 window.__timelines
  2. 使用影片當作音訊——始終使用靜音影片 + 獨立的 <audio>
  3. 將影片巢狀在具有時間的 div 內——使用無時間的包裝器
  4. 使用 data-layer(請使用 data-track-index)或 data-end(請使用 data-duration)
  5. 對影片元素尺寸進行動畫——對包裝器 div 進行動畫
  6. 對媒體呼叫 play/pause/seek——框架擁有播放權
  7. 建立沒有 data-composition-id 的頂層容器
  8. 在任何時間軸或補間動畫上使用 repeat: -1——始終使用有限次數的重複
  9. 非同步建構時間軸(在 async、setTimeout、Promise 內部)
  10. 對來自後續場景的剪輯元素使用 gsap.set()——它們在頁面載入時不存在於 DOM 中。請改為在時間軸內部、剪輯的 data-start 時間或之後使用 tl.set(selector, vars, timePosition)。
  11. 在內容文字中使用 <br>——強制換行無法考慮實際渲染的字體寬度。自然換行的文字加上 <br> 會產生額外的不需要的換行,導致重疊。請改用 max-width 讓文字換行。例外:簡短的顯示標題,其中每個單詞刻意位於獨立行上(例如,130px 的 "THE\nIMMORTAL\nGAME")。

場景轉場(不可協商)

每個多場景合成必須遵循以下所有規則。違反其中任何一條都會導致合成失敗。

  1. 始終在場景之間使用轉場。無跳接剪輯。無例外。
  2. 始終在每個場景上使用入場動畫。每個元素都透過 gsap.from() 動畫進入。任何元素都不得完全成形地出現。如果一個場景有 5 個元素,則需要 5 個入場補間動畫。
  3. 切勿使用出場動畫,最後一個場景除外。這意味著:在轉場觸發之前,不能有將透明度動畫到 0、將 Y 移出螢幕、將縮放動畫到 0 或任何其他「向外」動畫的 gsap.to()。轉場本身就是出場。在轉場開始的瞬間,已退出的場景的內容必須完全可見。
  4. 僅限最後一個場景: 最後一個場景可以淡出元素(例如,淡出到黑色)。這是唯一允許使用 gsap.to(..., { opacity: 0 }) 的場景。

錯誤 — 轉場前的出場動畫:

// 禁止 — 這會在轉場可以使用場景之前清空它
tl.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
tl.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// 轉場在空影格上觸發

正確 — 僅入場,轉場處理出場:

// 場景 1 入場動畫
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// 無出場補間動畫 — 7.2 秒的轉場處理場景切換
// 場景 2 入場動畫
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

動畫護欄

  • 將第一個動畫偏移 0.1-0.3 秒(而非 t=0)
  • 在入場補間動畫中變化緩動函數——每個場景至少使用 3 種不同的緩動函數
  • 不要在一個場景內重複相同的入場模式
  • 避免在深色背景上使用全螢幕線性漸層(H.264 條帶效應——使用徑向漸層或純色加局部光暈)
  • 60px 以上的標題、20px 以上的正文、16px 以上的資料標籤,以適用於渲染的影片
  • 在數字列上使用 font-variant-numeric: tabular-nums

如果未提供 visual-style.md 或動畫方向,請遵循 house-style.md 以獲得美學預設值。

字體排印與素材

  • 字體: 只需在 CSS 中撰寫你想要的 font-family——編譯器會自動嵌入支援的字體。如果字體不受支援,編譯器會發出警告。
  • 為外部媒體加入 crossorigin="anonymous"
  • 對於動態文字溢出,請使用 window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • 所有檔案都位於專案根目錄,與 index.html 同層;子合成使用 ../

編輯現有合成

  • 先讀取完整的合成——匹配現有的字體、顏色、動畫模式
  • 僅更改要求的內容
  • 保留不相關剪輯的時間設定

輸出檢查清單

  • npx hyperframes lint 和 npx hyperframes validate 都通過
  • 對比度警告已處理(請參閱下方的品質檢查)
  • 動畫編排已驗證(請參閱下方的品質檢查)

品質檢查

對比度

hyperframes validate 預設會執行 WCAG 對比度稽核。它會尋找 5 個時間戳記、對頁面進行螢幕截圖、對每個文字元素後方的背景像素進行取樣,並計算對比度。失敗會顯示為警告:

⚠ WCAG AA 對比度警告 (3):
  · .subtitle "secondary text" — 2.67:1 (需要 4.5:1, t=5.3s)

如果出現警告:

  • 在深色背景上:調亮失敗的顏色,直到其達到 4.5:1(正常文字)或 3:1(大字型,24px+ 或 19px+ 粗體)
  • 在淺色背景上:調暗它
  • 保持在調色板系列內——不要發明新顏色,調整現有的那個
  • 重新執行 hyperframes validate,直到沒有警告為止

如果正在快速迭代且稍後會檢查,請使用 --no-contrast 跳過。

動畫地圖

在編寫動畫之後,執行動畫地圖來驗證編排:

npx hyperframes animate-map

(其餘內容因原文截斷而無法提供翻譯,此處按照原文保留佔位符,但由於原文已截斷,skillMarkdown 在此完結。)

相關技能