视觉效果 (Vfx)
用于雨、雪、花瓣等全屏循环视频叠加层的 `Vfx` 元素,支持预加载、淡入淡出与倍速控制
自 0.16.0 起可用
Vfx 以全屏循环视频叠加层的形式播放粒子与氛围效果(落樱、光尘、雨、雪、雾、光斑),无需 canvas 或 WebGL
叠加层渲染在场景与正在播放的 Video 之上、舞台摄像机边界之内:Camera 的平移/缩放/晃动会带着天气效果一起运动,而对话框 UI 保持固定
import {Vfx} from "narraleaf-react";
// 真 alpha 素材:任意背景下色彩保真(含暗色边缘的花瓣)
const petals = new Vfx({src: "/fx/petals-alpha.webm"});
// 黑底发光素材 + screen 混合:体积极小、可硬件解码
const dust = new Vfx({src: "/fx/dust-black.webm", blendMode: "screen", opacity: 0.9});
scene.action([
petals.preload(), // 现在就加载;屏幕上还没有东西
dust.preload(),
character`起风了。`,
petals.show({duration: 800}), // 淡入;动作会等待淡入完成
dust.show({opacity: 0.4}), // 仅本次显示生效
character`花瓣飘下来了……`,
petals.setPlaybackRate(0.5), // 慢速飘落
dust.pause(), // 冻结在当前帧
dust.resume(),
petals.hide({duration: 1200}), // 淡出并停止播放
]);素材路线
通过 blendMode 支持两条互补的素材路线:
| 路线 | 素材 | blendMode | 取舍 |
|---|---|---|---|
| 真 alpha | VP9 yuva420p alpha WebM | "normal"(默认) | 任意背景色彩保真;体积较大,alpha 解码走软解 |
| 黑底发光 | VP9 yuv420p,效果绘制在黑底上 | "screen" | 体积小 5–10 倍、可硬件解码;加法混合会冲蚀暗色像素,只适合纯发光类效果 |
自 0.31.4 起,"normal" 以外的 blendMode 才真正生效。 在此之前,无论声明的是哪个值,叠加层
一律按 "normal" 合成,因此黑底素材会以一块不透明的矩形盖住场景,而不是把它的光叠加上去。构造参数没有变化,
"normal" 的表现也一如既往
# 真 alpha 路线
ffmpeg -i frames_%04d.png -c:v libvpx-vp9 -pix_fmt yuva420p -auto-alt-ref 0 -b:v 0 -crf 34 fx-alpha.webm
# 黑底路线
ffmpeg -i frames_%04d.png -c:v libvpx-vp9 -pix_fmt yuv420p -b:v 0 -crf 34 fx-black.webm含暗色或不透明像素的素材必须走 alpha 路线。循环素材应保证首尾帧一致,以获得无缝循环
行为
- 玩家跳过(skip)时,
show/hide的淡变立即完成;素材加载失败会记录错误并立即完成动作,因此损坏的资源不会阻塞剧情 - 舞台上的叠加层会被存档捕获,读档后直接重现,播放中或(若被暂停)冻结,不重放淡入。自
0.33.0起预加载的叠加层同样在内,读档后保持隐藏。0.16.0之前的旧存档可以正常读取 - 存档中的叠加层若已不在剧情里,读档会跳过它并记录告警。其余元素仍会报错
- 撤销(undo)会恢复叠加层此前的可见性
公共方法
constructor
config: Partial<VfxConfig> & {src: string}- VfxConfig
const rain = new Vfx({src: "/fx/rain-black.webm", blendMode: "screen"});可链式方法
preload
自 0.33.0 起可用
将叠加层加入舞台但不显示。片段开始加载,动作立即完成
在显示它的前几行调用。show 会等待首帧就绪,预加载过的叠加层因此立即出现。对已在舞台上的叠加层调用不会有任何效果
scene.action([
rain.preload(),
character`天阴了一下午。`,
rain.show({duration: 800}),
]);show
options?: VfxFadeOptions- VfxFadeOptions
将叠加层加入舞台,等待首帧就绪后淡入,并开始循环播放。动作会等待淡入完成。在已显示时调用是幂等的(从当前不透明度重新应用淡入)
自 0.33.0 起,options.opacity 与 options.rate 仅对本次显示生效,缺省取叠加层自身的配置值,因此覆盖过一次之后的普通 show() 会回到配置值。两者都不进存档:读档后按配置的不透明度与速度播放
petals.show({duration: 800, easing: "easeOut"});
petals.show({opacity: 0.35, rate: 2}); // 仅本次:更淡、更快hide
options?: VfxFadeOptions- VfxFadeOptions
将叠加层淡出并停止播放。动作会等待淡出完成。在未显示时调用是 no-op
自 0.33.0 起,叠加层会留在舞台上,不可见也不播放;之后的 show 从停住的那一帧继续,而不是从头重放。只有新开游戏与读档会清空舞台
petals.hide({duration: 1200});pause
将叠加层冻结在当前帧
dust.pause();resume
从当前帧继续播放
dust.resume();setPlaybackRate
rate: number- 播放速度(例如0.5表示慢速飘落)
调整播放速度。运行期的速度变更不会持久化;读档后速度回到 config.playbackRate
petals.setPlaybackRate(0.5);