Pryne 前端架构约定 是做什么的?
Pryne 的 vanilla-JS 构建中承重结构决策、它们存在的原因以及您不得破坏的不变量。参考实现:design-demos/ 在 Portfolio (test) 仓库中 (~/Documents/Coding Folder/Portfolio (test)),活动构建 v4-d-hybrid.html + js/roll-*.js,截至 2026-07-22。
术语,一次定义: IIFE = 立即调用函数表达式,(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 使用 SRI 哈希
async加载 (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.*。 - 危险的视觉接管被防御性地包装 — 在递归路径上,而不仅仅是设置时。 自定义光标在三个层受到保护,每个层都有一个恢复性 catch,将
Roll.cursorUpdate置空并移除.custom-cursor(后者隐藏操作系统光标):设置 (roll-cursor.js:9-32,catch 在 32),每个事件处理程序的函数体 (roll-cursor.js:17-20),以及pointermove调用点 (roll-core.js:26-29)。任何点的失败 — 设置时或任何后续的鼠标移动 — 都会恢复操作系统光标(2026-07-22 修复;文件头中的故障安全契约,roll-cursor.js:1-5)。当将此模式应用于任何隐藏/替换原生功能的事物时,也要保护递归路径,而不仅仅是设置。 - clip-path 展示存在于内部包装器上,决不存在于 IntersectionObserver 监视的元素上(“concept-C 修复” — 以 v4 concept 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);代码注释记录了最初的 bug:板块在任何人滚动到它们之前就完成了解析,“静默地破坏了‘随着你的参与而发展’的交互。”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/ 模块),因此变体可以作为完整的工件进行差异比较、截图和 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;仅在使用Roll.onMotionReady内部时使用 GSAP - 任何隐藏原生功能的事物都被 try/catch 包裹,并带有一个恢复性 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 (test) 仓库的提交 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