Pryne 前端架構契約 是做什麼的?
Pryne 的 vanilla-JS 建置中承載結構性決策、它們存在的原因以及你不得破壞的不變量。參考實作:Portfolio(測試)倉儲(~/Documents/Coding Folder/Portfolio (test))中的 design-demos/,現行建置 v4-d-hybrid.html + js/roll-*.js,截至 2026-07-22。
術語,一次定義: IIFE = Immediately Invoked Function Expression(立即呼叫函式運算式),(function () { ... })(); — 一個檔案作用域的閉包,因此除了檔案明確放在共享命名空間上的內容外,不會有任何洩漏。漸進增強 = 頁面在零 JS 增強的情況下完全可用;只有在其依賴項實際載入時,更豐富的行為層才會疊加。Develop-plate = 此專案的畫布藝術作品,在使用者互動時「發展」(從雜訊解析)。
何時不應使用此技能
- 動畫時序、緩動、編排理論 → pryne-motion-reference
- 變更是否被允許以及如何門控 → pryne-change-control
- 某個功能損壞且你正在診斷 → pryne-frontend-debugging
- 證明變更有效(螢幕截圖、Lighthouse、評分量規) → pryne-validation-and-qa
- React/Next.js 或任何打包工具專案 — 此契約僅適用於無建置的 vanilla 網站。
模組契約
一個檔案一個關注點。一個檔案一個 IIFE。無打包工具,無匯入。
所有跨模組狀態都位於一個全域命名空間物件上 — 此處為 window.Roll。roll-core.js 建立它並首先載入;每個其他模組都以 const Roll = window.Roll; 開頭,並讀取/寫入其上的屬性(roll-core.js:1-7 明確說明了這一點)。彼此不需要知道的模組改為透過 DOM 事件通訊(例如 roll-scroll.js 分派 roll:launch;roll-contact-sheet.js 監聽 — 請參閱 roll-scroll.js:35-37)。
HTML 中的腳本順序就是依賴圖。 來自 v4-d-hybrid.html:429-437:
roll-core.js → roll-shader.js → roll-field.js → roll-audio.js → roll-cursor.js
→ vendor/lenis.min.js → roll-scroll.js → roll-contact-sheet.js → roll-eggs.js
不變量:未先 grep 找出模組從 Roll 讀取了什麼並確認每個產生者都較早載入,絕不重新排序或插入 <script>。 沒有匯入系統可以拯救你;重新排序會靜默失敗或在載入時拋出錯誤。
grep -n "Roll\.\w*" design-demos/js/<module>.js # 它讀取/寫入了什麼
GSAP 特意不在該鏈中 — 請參閱不變量 2。
模組地圖(截至 2026-07-22)
| 檔案 | 一個關注點 | 行數 |
|---|---|---|
roll-core.js | 命名空間、共享狀態、develop-plate 引擎、upgradeMotion | 192 |
roll-scroll.js | 主幹:進入、滾動編排、HUD、主 rAF(requestAnimationFrame)迴圈、Lenis | 226 |
roll-field.js | 背景畫布場域 | 136 |
roll-shader.js | WebGL 顆粒/光著色器 + canvas-2D 備援 | 133 |
roll-eggs.js | 隱藏的人物觸發器(僅低語等級) | 83 |
roll-audio.js | 與滾動速度相關的安靜環境音效 | 79 |
roll-contact-sheet.js | 啟動時揭示聯絡表 | 55 |
roll-cursor.js | 自訂游標(僅限桌面,由 GSAP 門控) | 36 |
新的互動功能?它是一個新的 roll-*.js 檔案(或擁有該關注點之模組中一個清晰劃分的區段),並以依賴位置新增到腳本鏈中 — 而不是 HTML 中的內聯 <script>。
不變量(在程式碼中驗證 — 保持它們為真)
- 減少動畫門控每個動畫模組。
Roll.reduced = matchMedia('(prefers-reduced-motion: reduce)').matches(roll-core.js:9)。每個模組都會查詢它:著色器跳過 WebGL(roll-shader.js:90,124),場域跳過其 rAF 迴圈(roll-field.js:125,135),聯絡表提前返回(roll-contact-sheet.js:12),滾動跳過按住以發展的進入和 Lenis(roll-scroll.js:39-40,152),CSS 取消設定 clip-path 轉場(v4-d-hybrid.html:293-295)。任何新的動畫必須檢查Roll.reduced(JS)或位於減少動畫媒體查詢(CSS)之下。 - GSAP 是漸進增強,絕非依賴項。 它從 CDN 以
async載入,並帶有 SRI 雜湊(v4-d-hybrid.html:440);載入時它呼叫Roll.upgradeMotion(),該函式會翻轉Roll.enhanced並刷新透過Roll.onMotionReady註冊的回呼(roll-core.js:10-15,186-191)。如果 GSAP 從未到達,網站必須保持完全正常運作 — 游標、英雄字型和傾斜僅保持基準狀態(roll-cursor.js:34-35,roll-scroll.js:32-33,89,196)。使用Roll.onMotionReady(fn)註冊依賴 GSAP 的程式碼;切勿無條件呼叫gsap.*。 - 有風險的視覺接管以防禦方式包裝 — 在重複路徑上,而不僅僅是設定。 自訂游標在三層受到保護,每層都有一個還原捕獲,將
Roll.cursorUpdate設為空值並移除.custom-cursor(它隱藏了 OS 游標):設定(roll-cursor.js:9-32,第 32 行的捕獲)、每個事件處理器主體(roll-cursor.js:17-20)以及pointermove呼叫站點(roll-core.js:26-29)。任何一點的故障 — 設定時或之後的任何滑鼠移動 — 都會還原 OS 游標(2026-07-22 已修復;檔案標頭中的故障安全契約,roll-cursor.js:1-5)。將此模式應用於任何隱藏/取代原生功能的事物時,也要保護重複路徑,而不僅僅是設定。 - clip-path 揭示位於內部包裝器上,從不在 IntersectionObserver 監視的元素上(「concept-C 修正」— 以 v4 概念 C
v4-c-ch001.html命名,它在被帶入 v4-d 之前於此起源)。IO 監視.panel;clip-path 為.panel-inner設定動畫(v4-d-hybrid.html:121-122,185-186)。理由:裁剪被觀察的元素會改變其交集幾何形狀,並且揭示會與觸發器衝突。 - 參與驅動的視覺效果根據其自身可見性而非頁面載入進行門控。 功能面板僅在其面板具有
.in時才發展(roll-scroll.js:204-219);程式碼註解記錄了原始錯誤:面板在任何人滾動到它們之前就完成解析,「靜默地擊敗了『隨著參與而發展』的互動。」v4-d-hybrid.html的頭部註解稱此修正是技術審計中最高優先級的項目。 - WebGL 是明確的並且有備援保護。 上下文建立時使用非預乘 alpha(
roll-shader.js:17),每幀明確執行gl.clear(roll-shader.js:95),僅在 WebGL 有機會後才獲取 2D 上下文 — 一個畫布只能永遠擁有一種上下文類型(roll-shader.js:9-12),並且webglcontextlost會靜默失敗,而不是讓渲染迴圈拋出錯誤(roll-shader.js:129-132)。呼叫者使用單一的Roll.shader.render(t)進入點,並且永遠不需要知道 GL 與 2D 的區別。 - 在 Lenis 下滾動保持原生。 Lenis 是隨附的(
js/vendor/lenis.min.js,非 CDN),僅在!Roll.reduced時實例化,並保持window.scrollY有效 — 這是一個感覺升級,而非滾動劫持(roll-scroll.js:148-152,167)。渲染迴圈像以前一樣讀取scrollY。
單檔案示範理念 + 設計標記
每個設計變體都是一個自包含的 HTML 檔案(內聯 CSS、共享的 js/ 模組),因此變體可以作為完整工件進行 diff、螢幕截圖和 A/B 測試 — 請參閱 pryne-design-direction-decision。每個檔案中的一個長頭部註解記錄了該變體是什麼以及它承載了哪些審計發現(在編輯前先閱讀它;它是該檔案的本地變更日誌)。
所有顏色、間距和緩動都是 :root 中的 CSS 自訂屬性(v4-d-hybrid.html:50-63):
:root {
--bg: #0a0a0b; --accent: #d2232e; --ink: #f4f3f1; --dim: #86868c;
--pad-x: clamp(1.25rem, 6vw, 6rem);
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
}
根據 Pryne 的全局規則:在存在標記的地方切勿硬編碼顏色/大小;流體值使用 clamp()。新的動畫必須重用 --ease-out/--ease-snap,除非 pryne-motion-reference 另有說明 — 每個建置使用一種緩動語言。
核取清單:新增模組
- 新的
roll-*.js(或正確的現有擁有者模組),頂層 IIFE,const Roll = window.Roll; -
<script>插入在它從Roll讀取的所有內容之後,在讀取它的任何內容之前 - 檢查
Roll.reduced;GSAP 使用僅在Roll.onMotionReady內部 - 隱藏原生功能的任何事物都使用帶有還原捕獲的 try/catch 包裝
- 如果由參與驅動,則根據可見性門控;IO 目標 ≠ clip-path 目標
- 使用標記,而非硬編碼值
- 然後根據 pryne-validation-and-qa 進行驗證
已知弱點(公開、明確陳述)
- 無建置步驟:無最小化、無打包;對示範來說可以,但對於生產部署尚未解決。
- 字型從 Google Fonts CDN 載入(
v4-d-hybrid.html:47-48),儘管專案傾向於自託管(在design-demos/DECISIONS.md中僅在 Lenis 條目內附帶提及;決策記錄本身早於該檔案;尚未完成)。GSAP 也仍在 CDN 上(固定版本 + SRI)。在「修復」其中任何一個之前,請參閱 pryne-change-control。 - 無自動化測試 — 驗證僅基於瀏覽器的證據(pryne-validation-and-qa)。
- 佔位內容:案例研究/簡介尚未最終確定;不要像對待最終版本那樣潤飾文案。
來源與維護
執行 scripts/verify.sh(在此技能的目錄中)以一次性檢查以下所有項目。
基礎於 Portfolio(測試)倉儲的提交 457868a,2026-07-22。在信任易變事實之前請重新驗證:
- 腳本順序:
grep -n "<script" design-demos/v4-d-hybrid.html - 行數 / 模組列表:
wc -l design-demos/js/*.js - 減少動畫覆蓋範圍:
grep -rn "Roll.reduced\|prefers-reduced-motion" design-demos/ - GSAP 仍在 CDN+SRI,字型仍在 CDN:
grep -n "cdn.jsdelivr\|fonts.googleapis" design-demos/v4-d-hybrid.html - Lenis 仍為隨附:
ls design-demos/js/vendor/ - 現行建置仍是 v4-d:檢查
design-demos/DECISIONS.md和最新的git log --oneline