Files
workbuddy_skills/oil-ui-pro/references/scroll-narrative.md
T
admin d9445b5888 oil-ui-pro 0.15.4 → 0.22.2(上游 ui.oiloil.org 正式包)+ 记 P0-98 跨盘 rename 坑
- oil-ui-pro 升到 0.22.2:references 13→28 份(新增 16、删 imagery.md)、assets 增 cards/(22 组)与 fonts/、SKILL.md 顶层五步结构未改名。
- 升级路径:官方 `npx github:oil-oil/oil-cli update` 稳定失败(error=replace、报「检查目录权限」)。
  真身为 EXDEV —— 解压在 os.tmpdir()(C 盘)、技能目录在 E 盘,Windows 上 rename 不能跨盘;
  CLI 的 catch 把非 CliError 原生异常一律兜底成 replaceFailed,真错误一个字不吐。
  做法=借其 prepare() 只做下载+校验,再 cp 到同盘 stage、rename 交换;官方命令复验 up_to_date。
- 回归:product-planning 按名引用的 visual-review.md/tools.md/design-direction.md/style-explorer.md 全部健在;命名闸门 2061|0|27。
- session-mechanism/references/pitfalls.md 新增 P0-98(含通则:更新器把原生错误兜底成指错方向的人话)。
2026-10-14 10:21:46 +08:00

99 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 滚动叙事
## 落地页的滚动动效
落地页、品牌页、产品发布页和展览页,滚动动效和 [动效](motion.md) 的三处基本动效一起验收;文档、文章、工具和后台不做。用成熟的动效库实现,见下文“动效库”。
**必须有两样**:首屏以下的区块按内容出场;至少一段滑动驱动的叙事,主角在滚动里发生明显变化。**手法按页面挑**:首屏景深、字标收进导航、一镜到底、章节转场镜头、背景随章节变色、宣言逐字亮起,从这个页面的主视觉和内容里选合适的,写进分镜并说明为什么选它。下面先说首屏景深,它是首屏有主视觉和大标题时最常用的一种。
### 首屏景深(适合首屏有主视觉和大标题的页面)
首屏是一个固定住的舞台,滚动直接驱动里面的层次变化,往回滚就倒放:
- 首屏固定 100–200vh 的滚动距离,窄屏可缩到 80–120vh。
- 至少两层以不同速度、不同方向变化。最常用的是主视觉和大标题反向缩放:主视觉从 1 缩到 0.8,标题从 1 放大到 1.25;或者反过来,主视觉推近、标题后退。背景层动得最慢,前景层最快。
- 幅度要大到录屏里一眼看出来:主层缩放不少于 15%,或位移不少于 15vh。小于这个幅度,看起来就是页面在普通滚动。
- 大标题是图形层,可以缩放和视差;正文、按钮和表单不缩放、不做视差,固定后保持可读可点。
- 结束状态要交接给下一节:主视觉缩到下一节的位置,标题退成背景纹理,或者画面让出一条路给下一节的主角。不要固定结束后整块直接被推走。
首屏是满版的品牌字标时,用下面的“字标收进导航”。首屏是其他满版文字、产品界面或纯排版时,不一定适合景深,可以把滑动驱动的叙事放在后面。
### 字标收进导航(适合首屏是满版品牌字标的页面)
首屏就是品牌名本身,滚动时它缩成导航栏里的标志。它用一个元素同时完成满版文字骨架和一段滑动驱动的叙事,适合品牌名短、字形有性格的工作室、品牌和作品集:
- 首屏只有这一个字标,撑满版心宽度,窄屏也保持一行撑满;导航里不再放第二个标志。
- 滑动驱动,滚过 60–100vh,字标沿一条路径缩到导航标志的位置和尺寸,往回滚放大回来。结束状态就是导航里的标志,位置和尺寸按导航实际量出,交接时不跳。
- 缩放同一个元素的变换,不动画字号;字标用 SVG,或按容器宽度算出的字号。
- 字标让出首屏的同时,下一节内容已经进入画面,不留一整屏空白。
- 字标从满版缩成导航标志,是主角明显的缩放和一次交接,算一段滑动驱动的叙事;同一页不再另做首屏景深。
- 减少动态效果时,字标留在首屏不缩放,导航从一开始就显示标志。
### 区块按内容出场(必须,滑动触发)
首屏以下的每个区块,滚到位置时出场一次,往回滚不重播。出场方式从这个区块的内容和材质推出来,并且符合物理直觉:有重量的落下会过冲后稳住,轻的东西有空气阻力,机械的东西咔嗒到位。
| 区块内容 | 出场方式 |
| --- | --- |
| 卡片、实物、价格牌 | 带重量落下后稳住,过冲幅度见 [动效](motion.md) 的“手感”;后一张被前一张带出 |
| 列表、时间线、步骤 | 沿阅读方向依次展开,连接线先画出,节点随后落位 |
| 数字、指标 | 滚到目标值,高位先停、末位后停;不从 0 起跳的用原值起滚 |
| 线条、图表、路径 | 沿数据或流程的方向描出,端点落定时轻微放大一下 |
| 图片、照片 | 遮罩从画面主体的方向揭开,图片同时从 1.08 回缩到 1 |
| 纸、布、标签 | 先快后慢,带一点旋转后摆正,像被放到桌上 |
| 金属、机械、硬件 | 短促到位,没有软弹,可以带一次很小的回震 |
| 大标题、口号 | 按词或按行从遮罩里升起,字距从略松收紧 |
规则:
- 每个区块的出场写进分镜。同一页最多两个区块用同一种出场。
- 曲线用弹簧或惯性,参数从 [动效](motion.md) 的“手感”表里按材质取,不用默认的 ease。
- 主角先到,其余被带出,间隔 40–80ms,单个区块的出场总长不超过 900ms。
- 全页每个区块套同一个淡入上移,不算完成这一层。
### 滑动驱动的叙事(必须至少一段)
可以是首屏景深、字标收进导航,也可以是页面中段一段一镜到底,规则见下一节。主角必须在滚动里发生明显变化:缩放、拆解、变形、穿过或形状接力。一个小点沿着线移动、节点逐个点亮,只能算主叙事里的一个细节,不能单独当作主叙事。
### 分镜
动手前在方向卡的“动效”一栏写出滚动分镜:选了哪些手法、为什么,每一段占多少滚动距离、主角是谁、每个镜头画面里有什么、什么在动、往哪个方向、文字什么时候出现。先拆两个同类顶级落地页的滚动节拍作参照,写清它们每一段在动什么,再写自己的。
## 视差与一镜到底
- **一镜到底。** 整段是一次不切换的镜头。一个主角从头走到尾,可以是产品、一根线、一个形状或一个字,每一步长成、变成或让出下一个画面:推近看到细节,拉远看到全貌,转过去看到背面,穿过去进入下一个场景。
- **主角从产品里找。** 主角是这个产品处理的那样东西,在滚动里走完它自己的过程。找不到只属于这个产品的主角时,退回下面的转场手法,不用通用的漂浮几何。
- **停下来再说话。** 每个镜头留一段静止,文字在静止时出现;边动边读很累。
- **视差要有真实的前后。** 只在画面本来就有远近层次时用:前景的物体、中景、远处的背景,越近动得越多,差别要小。正文、按钮和表单不做视差;大标题作为图形层时,按上面的首屏景深处理。
- **转场也是镜头。** 一个圆从某一点扩开,带出下一节;推进一张图,穿过它到达下一节;背景色在章节之间随阅读慢慢变;一句宣言随滚动逐字亮起。每种手法一页只用一次。
- **倒着滚也成立。** 每一帧只由滚动位置决定,往回滚自然倒放,刷新或跳到中间也立刻是对的画面。不接管用户的滚动。
- **留出口。** 长段落前给一个跳过入口;减少动态效果时,把每个静止画面按顺序排成普通区块。
- **代码做不出来的,交给视频。** 用户想要很强的首屏动画,而效果要靠生成视频或序列帧才做得出来,例如角色转身、产品拆解、镜头穿越场景,可以告诉用户用 [oil-motion](https://github.com/oil-oil/oil-motion) 来做。CSS、SVG、着色器能完成的仍自己做;同一次对话只提一次。
## 滚动交互的两种模式
滚动带来的变化分两种模式:
- **滑动驱动(Scroll-Driven)。** 动画进程与滚动距离严格 1:1 映射(Scrub)。用户停下则动画停下,往回滚则倒放。首屏景深、一镜到底、3D 视角变换和模型解构只用滑动驱动;除首屏景深外,一镜到底一页最多一段。
- **滑动触发(Scroll-Triggered)。** 元素滚入视口阈值时,触发一段按自身时长播放的独立动画(如卡片进场、数字上涨)。它什么时候播完由代码决定,不跟着滚动条走。
- **默认单向一次性(Once)。** 触发后样式固定,用户向上回滚不重播、不复位,不在阅读中途让内容反复飞入或闪烁。
- **离开重置(Reset on Leave)。** 只有强节奏的纯展示页才允许在完全移出视口后重置,不在视口临界点反复触发。
## 平滑滚动与全屏分段
- **平滑滚动只管滚起来顺不顺,不算动效。** 用 Lenis 这类库,是为了消掉鼠标滚轮一格一格的跳动,让滑动驱动的动画和视差走得均匀。后台、仪表盘、表单和长文档不开全局平滑滚动,保持原生滚动的即时响应。
- **慎用全屏分段滚动(Snap Scroll)。** 隐藏滚动条、单次滑动切换整屏的做法只适合特定的全屏展厅与作品封面,常规业务和长文本不用。
## 动效库
落地页的滚动动效必须用成熟的动效库,不手写滚动监听和逐帧计算:
- **没有框架的页面**:GSAP,滚动用 ScrollTrigger(`scrub` 做滑动驱动,`once` 做滑动触发,`pin` 固定舞台),大标题拆字用 SplitText,元素换位置用 Flip。平滑滚动用 Lenis,并接进 GSAP 的时钟:`lenis.on('scroll', ScrollTrigger.update)`、`gsap.ticker.add((t) => lenis.raf(t * 1000))`、`gsap.ticker.lagSmoothing(0)`。GSAP 和它的插件都可以免费使用。
- **React、Vue 等项目**:沿用项目已有的动效库(Motion、GSAP 等);没有时加 GSAP,不另外手写一套。
- **需要离线打开的作品**:把库文件按固定版本放进作品目录,从本地引用,不依赖 CDN。
- **减少动态效果**:用 `gsap.matchMedia()` 分开两套:减少时不固定、不缩放,所有区块直接到位,主叙事排成按顺序的静止画面。
- 只动变换、透明度和滤镜。固定舞台的外层高度就是这段的滚动距离;离屏的动画由库自动暂停。窄屏可以缩短距离、降低幅度,但选定的手法都要保留。
## 检查
从头滚到底,再滚回去,各看一遍:往回滚是否倒放、跳到中段刷新画面是否正确、文字是否在静止时出现、窄屏选定的手法是否都在、开启“减少动态效果”后是否所有内容直接可读。