Vfx
The `Vfx` element for full-screen looping video overlays such as rain, snow, or petals, with preload, fade, and playback-rate control.
Available since 0.16.0.
Vfx plays a looping video as a full-screen stage overlay for particle and ambience effects (falling petals, light dust, rain, snow, fog, light flares) without canvas or WebGL.
The overlay renders above the scenes and any playing Video, inside the stage camera boundary: Camera pan/zoom/shake moves the weather with the shot while the dialog UI stays fixed.
import {Vfx} from "narraleaf-react";
// true-alpha material: faithful colors on any background (petals with dark edges)
const petals = new Vfx({src: "/fx/petals-alpha.webm"});
// black-background glow material + screen blending: tiny files, hardware decodable
const dust = new Vfx({src: "/fx/dust-black.webm", blendMode: "screen", opacity: 0.9});
scene.action([
petals.preload(), // load it now; nothing on screen yet
dust.preload(),
character`The wind is picking up.`,
petals.show({duration: 800}), // fade in; the action waits for the fade
dust.show({opacity: 0.4}), // this showing only
character`The petals are falling...`,
petals.setPlaybackRate(0.5), // slow drifting
dust.pause(), // freeze on the current frame
dust.resume(),
petals.hide({duration: 1200}), // fade out and stop playing
]);Asset routes
Two complementary asset routes are supported through blendMode:
| Route | Material | blendMode | Trade-off |
|---|---|---|---|
| True alpha | VP9 yuva420p alpha WebM | "normal" (default) | Faithful colors on any background; larger files, software alpha decode |
| Black-background glow | VP9 yuv420p, effect drawn on black | "screen" | 5–10× smaller, hardware decodable; additive blending washes out dark pixels, so purely luminous effects only |
Since 0.31.4, a blendMode other than "normal" takes effect. Before that, every overlay
composited as "normal" whatever the mode said, so black-background material covered the scene
with an opaque rectangle instead of adding its light to it. The constructor is unchanged, and
"normal" behaves as it always has.
# true-alpha route
ffmpeg -i frames_%04d.png -c:v libvpx-vp9 -pix_fmt yuva420p -auto-alt-ref 0 -b:v 0 -crf 34 fx-alpha.webm
# black-background route
ffmpeg -i frames_%04d.png -c:v libvpx-vp9 -pix_fmt yuv420p -b:v 0 -crf 34 fx-black.webmKeep assets with dark or opaque pixels on the alpha route. Loop assets should start and end on the same frame so the loop is seamless.
Behavior
show/hidefades complete instantly when the player skips, and a source that fails to load logs an error and resolves immediately, so a broken asset never blocks the story.- Overlays on the stage are captured by save/load and re-appear without a fade, playing or frozen if paused. Since
0.33.0this covers preloaded overlays as well, which restore hidden. Saves created before0.16.0load fine. - A save naming an overlay the story no longer has loads without it, and logs a warning.
- Undo restores the overlay's previous visibility.
Public Methods
constructor
config: Partial<VfxConfig> & {src: string}- VfxConfig
const rain = new Vfx({src: "/fx/rain-black.webm", blendMode: "screen"});Chainable Methods
preload
Available since 0.33.0.
Put the overlay on the stage without showing it. The clip starts loading, and the action resolves immediately.
Use it a few lines before the overlay is shown. show waits for the first frame, so a preloaded overlay appears at once. Calling it on an overlay already on the stage does nothing.
scene.action([
rain.preload(),
character`The sky has been grey all afternoon.`,
rain.show({duration: 800}),
]);show
options?: VfxFadeOptions- VfxFadeOptions
Add the overlay to the stage, wait for the first frame, fade it in, and start looping playback. The action waits for the fade-in to finish. Calling it while the overlay is already shown is idempotent (the fade-in is re-applied from the current opacity).
Since 0.33.0, options.opacity and options.rate apply to this showing only and fall back to the configured values, so a plain show() after an overridden one is back to normal. Neither is persisted: a loaded save plays at the configured opacity and rate.
petals.show({duration: 800, easing: "easeOut"});
petals.show({opacity: 0.35, rate: 2}); // faint and fast, this time onlyhide
options?: VfxFadeOptions- VfxFadeOptions
Fade the overlay out and stop playback. The action waits for the fade-out to finish. Calling it while the overlay is not shown is a no-op.
Since 0.33.0 the overlay stays on the stage, invisible and not playing, and a later show resumes from the frame it stopped on rather than restarting. Only a new game or a load clears the stage.
petals.hide({duration: 1200});pause
Freeze the overlay on its current frame.
dust.pause();resume
Continue playback from the current frame.
dust.resume();setPlaybackRate
rate: number- The playback speed (e.g.0.5for slow drifting).
Adjust the playback speed. Runtime rate changes are not persisted; after loading a saved game the rate returns to config.playbackRate.
petals.setPlaybackRate(0.5);