首先,保持此技能最新 — 自動執行,不需詢問:
npx hyperframes skills update slideshow。當一切為最新時,此操作為快速無操作;否則,它會在您依賴此技能及其依賴的核心領域技能之前,先更新它們。
figma 來源:如果 deck 的內容或故事板來自 figma.com URL,請先執行
/figma— 匯出素材、品牌權杖,並在來源為場景影格序列時重建故事板 — 然後根據其輸出進行建置。不要直接透過原始 MCP 工具驅動 Figma:這會繞過 SVG 清理、.media/manifest.jsonl來源追蹤以及品牌權杖var()綁定,因此後續的品牌變更將無法傳播,而需要完整重新匯入。
投影片秀編寫合約
一個 HyperFrames 投影片秀是一個標準的 HyperFrames 組合 — 包含場景、片段、GSAP 時間軸 — 並擁有額外的一項要素:一個JSON 島,用來宣告哪些場景是投影片以及它們如何連接。播放器的 SlideshowController 會讀取這個島,並將連續的 GSAP 時間軸轉換為離散的、可導覽的 deck。
請先閱讀 /hyperframes-core 以了解基本的組合合約(片段、軌道、data-* 屬性、確定性規則)。此技能僅涵蓋新增的部分:島的結構、投影片撰寫規則、片段、分支、驗證以及包裝元件。
輸出 — 可導覽的 deck,而非線性 MP4
投影片秀的輸出是正在運行的 deck:使用 hyperframes present <project-dir>(或 Studio 簡報模式)來提供服務 — 播放器的 SlideshowController 會讀取島並驅動導覽、片段、分支和簡報者模式。請參閱下方的簡報與交接。
不要對投影片秀執行 hyperframes render 來產生單一 MP4。 Deck 是以數個頂層場景組合(每個投影片一個 data-composition-id)的形式編寫,且沒有包裝它們的主根組合,因此 render 只會解析第一個組合,並產生一個靜默截斷的 MP4(例如,一個 40 秒的 deck 只輸出 6 秒)。線性主線匯出(僅主投影片,排除分支序列)目前延後處理 — 在此功能推出之前,支援的輸出是即時的 present deck 和每個投影片的 snapshot 靜態圖。如果使用者今天需要線性 MP4,請說明此限制,而不是將 render 指向 deck。
意圖確認
如果使用者明確要求投影片秀、slide show 或 HyperFrames 投影片秀,請直接使用此技能。當請求是透過 /hyperframes 送達時,意圖層的分類會負責此確認 — 路由至此表示已確認,因此不要再次詢問;意圖層的執行形狀問題不適用(交付成果是 deck,而非渲染的影片)。當存在 BRIEF.md 時,它承載了已確認的意圖 — 請讀取它。
如果此技能是因相鄰請求(例如「簡報」、「提案」、「deck」、「互動式 deck」或「轉換此頁面」)而觸發,請在編寫前暫停,並在要求確認之前先說明選項。簡短解釋 HyperFrames 投影片秀意味著一個可運行的 deck,具有離散投影片、內建導覽和簡報者模式、可編輯的備註、共享媒體處理以及交接前的驗證。對於來源頁面轉換,請同時提及目標是保留原始頁面的視覺設計、互動、動畫和媒體行為,同時將頁面移動轉換為投影片間的轉場。
然後提出一個簡短的確認問題:
您要將此作為 HyperFrames 投影片秀嗎?
當環境提供時,使用是/否選擇 UI;否則以純文字提問。
在使用者說「是」之前,不要實作投影片秀。如果他們說「否」,請停止使用此技能 — 讀取 /hyperframes 並讓意圖層重新路由。此確認是一個路由決策,而非偏好閘門 — 根據 ../hyperframes-core/references/brief-contract.md 第 1 節,它在自主模式下仍然有效(「驚喜我」不能跳過它):建立錯誤的交付成果類型是品質失敗,而非創意決定。
兩個部分
1. 場景 — 以正常方式宣告
每個投影片都由一個場景支援。使用 data-composition-id、data-start、data-duration 和 data-label 來宣告場景:
<div
data-composition-id="problem"
data-start="0"
data-duration="8"
data-label="The problem"
data-width="1920"
data-height="1080"
>
<!-- 片段放在這裡 -->
</div>
分支投影片(僅能透過熱點到達,不包含在主線中)以完全相同的方式宣告 — 它們僅出現在島的 slideSequences 條目中,而非主 slides 陣列中。
2. JSON 島 — 每個組合一個 script 區塊
在組合 HTML 中新增一個 <script type="application/hyperframes-slideshow+json"> 區塊。它包含所有投影片秀的中繼資料:
<script type="application/hyperframes-slideshow+json">
{
"slides": [...],
"slideSequences": [...]
}
</script>
這個島是投影片順序、備註、片段暫留點、熱點和分支序列的唯一真實來源。將它放在 <body> 頂部附近,在場景 div 之前,以便於尋找。
不要將投影片秀清單隱藏在一個備用的 <script type="application/json"> 區塊加上在執行時建立該島的程式碼之後。present 指令會靜態讀取組合 HTML,並期望真正的 application/hyperframes-slideshow+json 島已經存在。
結構
SlideshowManifest(頂層島物件)
{
"slides": [
/* SlideRef[] — 主線,按順序 */
],
"slideSequences": [
/* SlideSequence[] — 離線分支序列 */
]
}
SlideRef
{
"sceneId": "problem",
"notes": "以痛點為開場,而非公司簡介。",
"fragments": [3.5, 5.2, 7.0],
"hotspots": [
/* SlideHotspot[] */
],
"ttsScript": null,
"ttsAudioUrl": null,
"ttsDurationMs": null
}
| 欄位 | 必要 | 備註 |
|---|---|---|
sceneId | 是 | 必須完全符合場景的 data-composition-id(或提供明確的 startTime/endTime)。lint 規則透過 data-composition-id 解析場景。 |
notes | 否 | 簡報者專用文字。永遠不會顯示給觀眾。 |
fragments | 否 | 投影片 [start, end] 範圍內的時間(秒)陣列 — 請參閱下方的片段。 |
hotspots | 否 | 觸發分支的互動式覆蓋層 — 請參閱下方的分支。 |
startTime | 否 | 可選。覆蓋相符場景的時間範圍;預設為場景的開始/結束。 |
endTime | 否 | 可選。覆蓋相符場景的時間範圍;預設為場景的開始/結束。 |
ttsScript、ttsAudioUrl、ttsDurationMs | 否 | 保留。 結構欄位存在,但 TTS 播放尚未實作。除非您正在為未來建置預先填入,否則請省略。 |
SlideHotspot
{
"id": "h1",
"label": "我們是如何計算出這個結果的?",
"target": "market-deep-dive",
"region": { "x": 60, "y": 10, "w": 35, "h": 20 }
}
| 欄位 | 必要 | 備註 |
|---|---|---|
id | 是 | 在投影片內唯一。 |
label | 是 | 顯示給觀眾的工具提示/按鈕文字。 |
target | 是 | 必須符合 slideSequences 中的 SlideSequence.id。 |
region | 否 | 投影片的百分比邊界框:{x, y, w, h},範圍 0–100。省略時,會將熱點渲染為全投影片的標籤按鈕。 |
SlideSequence
{
"id": "market-deep-dive",
"label": "市場規模計算方法",
"slides": [{ "sceneId": "mkt-1" }, { "sceneId": "mkt-2" }]
}
序列內部的 slides 使用與主線相同的 SlideRef 形狀。允許使用片段和巢狀熱點。
投影片撰寫規則
這些是硬性限制,而非建議。違反規則的投影片會在審查者看到時被直接取代。
- 標題是完整句子的主張,而非標籤。 寫「SMB 每週花費 14 小時在手動排程上」,而不是「排程問題」。這個句子應該能在忽略視覺元素的情況下獨立存在。
- 每個投影片一個概念 + 一個視覺元素。 如果您想添加第二個要點群或第二個圖表,請拆分投影片。
- 以重點開場。 最有力的觀點要放在最前面 — 無論是在投影片內還是在 deck 順序中。投資者從左到右、從上到下閱讀,然後他們會停止。
- 僅限由下而上的市場規模計算。 不要在沒有展示計算過程的情況下寫「500 億美元 TAM」。從單位經濟學向上建構:帳戶數 × ACV,或交易數 × 抽成率。
- 字型最小相當於 30pt。 在 1920×1080 解析度下,標題為 72–96px;內文為 48px。觀眾必須閱讀的任何文字都不得低於 40px。
移植來源頁面
將現有頁面轉換為投影片秀時,來源保真度是合約的一部分。除非使用者明確要求重新設計,否則不要用簡化的近似品取代來源特定的 widget。
- 盡可能貼近地保留原始頁面的視覺設計、動畫語言、互動行為、媒體行為和簡報輔助功能。當投影片秀系統支援簡報者模式時,請使用共享的可編輯備註行為來包含備註,而不是使用特定於 deck 的實作。
- 盡可能精確地從來源 DOM/CSS/JS 移植機械性視覺元素:自訂播放器、畫布可視化工具、時間軸、播放頭、音軌、展開圓圈、懸停狀態和其他互動細節應在轉換後保留。
- 將原生
<video>/<audio>元素視為任何自訂媒體 chrome、畫布可視化工具、波形、節奏網格或播放頭的真實來源。連接來源的媒體事件(play、pause、timeupdate、seeking、seeked、ended、ratechange、volumechange),並從media.currentTime推導視覺狀態;不要執行可能與實際播放產生偏差的獨立計時器。 - 每個帶有
src的複製<video>或<audio>都必須在 lint 之前具有 HyperFrames 時間屬性:data-start和data-duration,以及當應保留有聲原生音訊時的data-has-audio="true"。對特定投影片的媒體使用場景的時間範圍;對於可能從多個聚焦投影片播放的使用者控制證據影片,使用 deck 範圍的時間。不要對媒體保留preload="none";請使用metadata或auto。 - 在驗證之前解析來源字型權杖。如果要保留自訂來源字型,請為本地/擷取的字型檔案新增
@font-face規則。如果使用系統替代字型,請將代幣化宣告(例如font-family: var(--f-body))替換為具體的渲染安全堆疊(例如system-ui, sans-serif或ui-monospace, monospace);不要將var(...)保留為字型系列的值。 - 審查來源中非典型的頁面移動,特別是受滾動、滾輪、觸控、雜湊狀態、調整大小或 requestAnimationFrame 迴圈驅動的行為。將具有翻譯/縮放「世界」圖層、視差、固定面板、水平滾動器、滾動擦洗時間軸、章節吸附和縮放至元素相機的固定視口視為來源行為。滾動通常是來源的轉場觸發器,因此請透過提取其進度停止點、緩動和相機/焦點狀態來保留轉場,然後將該動畫重新託管在投影片秀導覽上,透過時間軸位置、片段或可重複使用的播放器/掛鉤。獨立包裝器跳到投影片暫留點仍然需要明確的導覽-相機轉場掛鉤;僅計算每個投影片的相機變換是不夠的。不要在投影片內部模擬字面上的頁面向下滾動轉場;觀眾應該感覺像是在一個焦點到另一個焦點之間進行相機移動/縮放,而不是看到一個網頁正在被滾動。保持每個投影片間相機移動的連續性:避免在相同邊界處反向 x/y 方向或縮放的中間路線停止點,除非來源在該邊界處明顯這麼做。一個在落地前亂竄的轉場,比一個更簡單的直接焦點移動更糟。
- 保留來源的媒體裁切語意。將螢幕截圖、推文/社交貼文、產品 UI 擷取、圖表、文件、程式碼、排行榜以及任何帶有可讀文字的圖片視為內容證據,而非裝飾性媒體:在穩定框架內使用來源長寬比(
height: auto)或object-fit: contain。僅在來源使用object-fit: cover時,或對於有意作為裝飾/背景/電影縮圖時,才使用object-fit: cover。將這些擷取內容放入投影片後,檢查所有四個邊緣是否有被截斷的文字、標誌、控制項或標題;對有意義內容的可見裁切是一個錯誤,除非來源本身將其裁切。 - 如果一個
…
[為翻譯而截斷]