電影級 3D 網頁場景
人們在描述動畫時用的是感受性的詞語(「史詩級」、「流暢」、「被吞噬」、「像電影一樣」)。 程式碼需要精確的決定:螢幕上有什麼、相機在哪裡、什麼在動、移動速度、 使用哪種緩動函數、如何打光,以及在滾動的每個時間點文字在做什麼。 當這些決定留給猜測時,結果在技術上可能沒問題,但 並非他們想像的樣子 —— 而且每次修正的成本都比一開始就做對還要高。
此技能透過兩個步驟來縮小這個差距:先指導再建構(將描述轉換為精確且經確認的場景規格)和在經過驗證的基礎上建構(一套架構和技術庫,使規格可靠地實作且滾動流暢)。
它適用於任何場景 — 內含作品集中的場景(一台打開的筆電、一個繞行的技能原子、點燃並燃燒的標誌、一個黑洞隧道)是這個方法的實際範例,而不是一個可供挑選的選單。
檔案
references/scene-language.md 精確的運動詞彙 + 將模糊詞語翻譯成具體內容
references/scene-spec.md 場景規格 / 分鏡板格式,附有實際範例
references/techniques.md 如何建構每種效果(相機、著色器、粒子、文字…)
references/architecture.md 固定滾動場景模式、時間軸、效能、常見問題
references/house-style.md 預設視覺風格,以及如何從參考資料中挑選風格
references/effects.md 範本中已完成的場景,經過剖析 — 複製或從中學習
references/portfolio.md 從範本建構完整的作品集
references/content-guide.md 範本的內容欄位
references/portrait-rig.md 範本的動態人像英雄區域
template/ 完整的 Next.js 作品集網站(實際範例)
scripts/create-site.mjs 建立一個新的單頁網站(Next.js、預設背景、準備好放入場景)
scripts/new-scene.mjs 建立一個新的固定場景(區段 + 時間軸,除非加上 --no-canvas,否則包含 3D 畫布)
scripts/video-frames.mjs 從參考影片中擷取影格,以便研究其運動
scripts/create-portfolio.mjs 將完整的作品集範本複製到一個新資料夾
scripts/retheme.mjs 重新設定範本強調色的色系
工作流程
1. 瞭解他們想像的樣子
閱讀需求,了解:頁面的用途、每個場景應該展示的內容、感受、任何參考資料(網站、影片、圖片、電影、遊戲),以及任何硬性限制(現有網站、框架、品牌顏色)。
如果他們提供了參考資料,請在任何其他事情之前先研究它 — 它所承載的資訊比任何描述都多。圖片:仔細觀看。影片:執行 scripts/video-frames.mjs 並依序查看影格(請參閱下方「閱讀參考影片」)。網站:如果可以開啟,請滾動它並定期截圖。請將風格(顏色、光線、字體、背景動態)與編排(什麼時候移動什麼)分開記錄 — 人們通常從參考資料中得到其中一個或另一個,如果這點不清楚,你應該詢問是哪一個。
2. 將其翻譯成場景規格
閱讀 references/scene-language.md,然後按照 references/scene-spec.md 的格式撰寫規格。對於每個場景:用一句話描述想法、物體、室內風格或選擇的外觀,以及一個節拍表 — 在每個滾動區段(0–15%、15–40%、…)的螢幕上顯示什麼內容,包含相機移動、動態(動詞 + 緩動函數 + 持續時間)、光線/顏色變化、效果(粒子、扭曲、發光)以及文字的作用。
模糊的詞語要在這裡解決,而不是在程式碼中。「它被吸進去」變成:標題字母螺旋狀朝向螢幕中心,每個字母在漩渦邊緣到達它時開始移動,旋轉 150° 同時縮小到 15% 並模糊到 6px,持續滾動的 10%;背景在同一視窗內朝向中心扭曲。如果一個字可能代表兩種截然不同的意思,請提供兩種具體的解讀,並選擇較可能的那種作為預設值。
3. 在開始建構前先確認
將規格展示給對方 — 他們花一分鐘閱讀,卻能節省數小時。請他們更正任何不符合他們想像的地方,尤其是節奏(太快 / 太慢)和每個場景的關鍵時刻。保持訊息簡短:節拍表加上 2–3 個針對性問題以及你的預設答案,這樣「好的,請開始」就是一個有效的回覆。
如果你無法提問(一次性或自動化請求),請使用你的預設值繼續進行,並在你最終的訊息中包含規格,以便對方能夠精確地重新導向。
4. 分層建構
在撰寫程式碼之前,請先閱讀 references/architecture.md — 從其「這東西到底需不需要 WebGL?」表格開始 — 以及針對規格中每個效果的 references/techniques.md。
程式碼放置的位置:
- 新網站(登陸頁面、產品頁面、任何單頁):執行
node <skill-dir>/scripts/create-site.mjs <資料夾>會建立一個準備好的 Next.js 專案,包含預設背景、字型和 lint 設定;然後在其中新增場景。 - 現有網站:在他們的專案中工作,並先閱讀
architecture.md中的「在現有網站內部工作」。 - 完整的作品集:從範本開始(
references/portfolio.md)。
然後按此順序建構每個場景,並在每一層之後進行檢查:
- 佈局 — 固定的區段、每個節拍對應一個插槽的滾動時間軸、佔位形狀和相機路徑。執行
scripts/new-scene.mjs <專案> <名稱> --beats N會產生這個骨架,已經接線完成(滾動進度 → 共享時間軸 → 3D 相機和 DOM 標題,減少動畫的備用方案,當離開螢幕時暫停);加上--no-canvas則僅限 DOM 效果。滾動瀏覽它:節拍的順序和節奏是否正確? - 動畫 — 真正的移動和轉場,以及來自規格的緩動函數和持續時間。時間點是人們反應最強烈的部分;在讓它變漂亮之前先把它做對。
- 外觀 — 材質、光線、顏色、發光、粒子、背景、排版。
- 精修 — 指標傾斜、閒置漂移、小的次要動態、行動裝置構圖、減少動畫。
與建置一起執行 npm run lint — React 規則會在它們變成微妙的錯誤之前捕捉到每影格突變的錯誤。
5. 根據規格驗證
建置(npm run build),執行它,並在每個節拍的滾動位置截取螢幕截圖。將每個螢幕截圖與節拍表逐行比較:那個物體是否在那裡、相機是否如描述般構圖、文字是否出現、顏色是否正確?在展示之前修正不匹配的地方。滾動後等待一秒再進行每個螢幕截圖 — 場景會逐漸到位。另外檢查手機尺寸的視口(375×812)和減少動畫。如果你沒有瀏覽器工具,請老實說場景已經建置但尚未查看,並列出應檢查的項目。
6. 使用精確的語言進行優化
當對方做出反應(「感覺廉價」、「太多」、「不夠戲劇性」)時,使用 scene-language.md 將回饋翻譯成與原始需求相同的方式,提出具體的變更(「將俯衝速度從滾動的 8% 減慢到 14%,並在它之前增加 0.3 秒的停頓」),然後進行修改。當他們不確定時,一次只改變一件事,這樣他們就能分辨出哪些方式有效。
閱讀參考影片
node <skill-dir>/scripts/video-frames.mjs <影片> --every 0.25 --out frames/
它需要 ffmpeg(如果缺少,腳本會說明如何安裝)。依序查看影格,並針對每個時間段記錄:螢幕上有什麼、什麼移動了以及如何移動(方向、速度、緩動函數 — 是加速、超調還是穩定?)、相機(靜態、推近、環繞、抖動)、切換與連續移動,以及顏色/光線。那個清單就是節拍表的初稿。對於快速發生的時刻,僅針對該時間段(--from、--to)使用 --every 0.04 重新執行。
不可妥協的事項
這些來自真實的失敗案例;每一個在 architecture.md 中都有原因。
- 每個場景都有一個減少動畫的版本(一個仍然顯示所有內容的靜態佈局)。
- WebGL 僅在客戶端載入,並在其區段離開螢幕或分頁被隱藏時暫停。
- 3D 和 DOM 文字讀取相同的時間軸函數,因此它們不會漂移分離。
- 固定區段內的滾動關聯值使用函數轉換,而不是範圍陣列。
- 使用偽裝的發光(疊加光暈),而不是後處理泛光,除非對方接受其成本。
- 頁面的所有內容都是 DOM 中真實、可讀取的文字 — 不僅僅是在畫布中烘烤的內容。
- 絕不捏造關於人員或產品的事實;設計文字可以,但聲明不行。
你沒有收到的價格、規格、日期、統計數據和獎項,請使用可見的
[佔位符]表示。 - 任何自動播放的內容(載入時的介紹)都有一個可見的跳過控制項,並且每個場景都有一個無 WebGL 的備用方案(海報圖片或靜態佈局)。
- 在別人的現有網站中,只修改效果所需的內容,並說明移動了什麼。
需要保留的致謝
範本感謝其原作者以及它所使用的開源元件(React Bits 的 ColorBends 和 Magnet,字型配對參考自 dungyov.com)。在重複使用這些部分時,請保留這些致謝。