用途:让飘落物被识别为树叶,而非纸屑、硬币或彩纸。需要可辨识形状时用它;只需笼统氛围粒子时用 ambient-section-particles。
主要能力与要点:
- 先做翻滚。每片叶绕自身长轴旋转,正面朝前、侧立变薄至近乎消失、再从另一面展开;这一瞬的“消失”是眼睛读作树叶的关键。2-D canvas 用水平缩放穿过零点实现:ctx.scale(Math.cos(l.spin), 1)。驱动两个轴:roll 在画面平面内转动,spin 穿过平面转动,每片叶各自速率。3-D 必须用实例化四边形,不能用点精灵,因为点精灵永远朝向相机、无法侧立。
- 滑移与翻滚耦合。横向运动由翻滚角驱动、相位差九十度:l.x += Math.sin(l.spin) * l.slip * dt; l.y += l.fall * dt; 不要给 x 加独立正弦,否则像风或缓动错误。
- 烘焙正反两面。按翻滚符号选图:const img = Math.cos(l.spin) < 0 ? sprite.back : sprite.face; 背面更暗更淡。
- 每片叶随机化下落速度、翻滚率、roll 率、滑移量、相位、缩放与不透明度,共享任一参数就会变成滚动的纹理。
- 回收位置决定屏上数量。2-D 跨视口回收;3-D 在相机视线前方而非周围回收,并保留远处回绕作为兜底。
- 密度按带宽面积而非数量设定:半径减半,同数量下屏上密度翻四倍。按视口面积缩放数量。
- 用两三层做景深,近层可越过文字,但只用两三片。
- 颜色取自小色阶并逐叶变化饱和度;3-D 用 alpha-test 而非 alpha-blend;暗场景自发光红要把绿蓝归零(0x780200)。
- 成本在填充与绘制:2-D 每叶一次 drawImage,预渲染最大尺寸精灵;3-D 用一个 InstancedMesh,暂存对象提到模块作用域。
- 停止不可见工作:document.hidden 与 IntersectionObserver 暂停,恢复时重置 lastTime,dt 钳制约 1/30 秒,DPR 上限 2,用 ResizeObserver 取尺寸,防止零视口。
- 尊重读者:prefers-reduced-motion: reduce 下渲染一帧精心构图的静止画面,不隐藏叶子,控件变化时重绘。
限制与验证:需逐项检查翻滚是否穿过侧立、滑移是否由翻滚角驱动、正反面是否不同、参数是否逐叶变化、回收带是否够紧、3-D 是否在相机前方回收、自发光红绿蓝是否归零、数量是否随视口缩放、隐藏或离屏是否暂停、dt 是否钳制、DPR 是否封顶、减弱动效下是否有静止帧,并在 390px 与 1440px 下保持控制台干净。具体平台、收费与价格资料暂未提供。