Effects are typed classes. Construct one with props, attach it, and the GPU runs it each frame. The full list with every prop is in the Effects reference.
import { Blur, Curves, FilmGrain, Vignette } from "framefields"; // or "framefields/effects"Where to attach
Section titled “Where to attach”// 1. One layer (chain as many as you like, in order)Layer.video("assets/footage/plate.mp4", { fit: "cover" }) .withEffect(new Curves({ master: [{ x: 0, y: 0.05 }, { x: 0.5, y: 0.52 }, { x: 1, y: 0.95 }] })) .withEffect(new Vignette({ strength: 40, radius: 0.85, softness: 0.6 }));
// 2. The whole framecomp.apply(new FilmGrain({ strength: 12, size: 1.5, animated: true }));
// 3. A region of a plate (rectangle, rounded, or a tracked object)comp.section({ source: "assets/footage/interview.mp4", x: 400, y: 200, width: 300, height: 300, borderRadius: 150, effects: [new Blur({ strength: 25, blurType: "Gaussian" })],});
// 4. A clip outside the layer treeimport { ApplyLUT, Crop, Media } from "framefields";const clip = Media.video("assets/footage/raw_log.mp4") .apply(new ApplyLUT({ lutUrl: "assets/luts/cinematic.cube", intensity: 1 })) .apply(new Crop({ cropType: "rectangle", topPercentage: 10, heightPercentage: 80 }));await clip.renderFrame({ atMs: 1500 });.withEffects([a, b]) attaches several at once. Lowercase factories work too: Effect.blur({ strength: 9 }).
Value ranges
Section titled “Value ranges”Ranges come from each effect’s schema; out-of-range values warn (set FRAMEFIELDS_STRICT_PROPS=1 to throw). Many “strength” props are 0–100, not 0–1:
| Effect | Prop | Range | Default | Tasteful |
|---|---|---|---|---|
Vignette |
strength |
0–100 | 50 | 20–45 |
FilmGrain |
strength |
0–100 | 15 | 8–20 |
FilmGrain |
size |
0.5–4 | 1.5 | 1.2–1.8 |
Blur |
strength |
0–100 | 5 | — |
ColorBalance |
cyanRed / magentaGreen / yellowBlue |
−100–100 | 0 | ±4–12 |
ColorKey |
similarity, smoothness |
0–1 | 0.4, 0.1 | — |
Modulate |
brightness, contrast, saturation |
multiplier | 1 | 0.9–1.2 |
- Tonal grading first:
Curves,Levels,ColorBalance,SelectiveColor,ApplyLUT. - Then optics:
Blur,DepthOfField,Vignette. - Grain last, as the outermost pass:
FilmGrain.
For a still export, set animated: false on FilmGrain so the frame is deterministic across renders of different lengths.
Drive props with signals
Section titled “Drive props with signals”Any numeric effect prop accepts a signal instead of a number. The uniform updates per frame without rebuilding the pipeline.
import { Blur, Layer, Signal } from "framefields";
const breathe = Signal.sine({ frequency: 0.5, min: 0, max: 20 }); // Hz, sampled at the composition frame
Layer.image("assets/images/bg.jpg").withEffect(new Blur({ strength: breathe, blurType: "Gaussian" }));Vision signals plug in the same way, e.g. new Vignette({ strength: vision.segmentation.subject.coverage }). See Vision.
Families
Section titled “Families”| Family | Effects |
|---|---|
| Grading | Curves, Levels, ColorBalance, SelectiveColor, GradientMap, ShadowsHighlights, ApplyLUT, ExtractLUT, Modulate, ChannelSplitter, ChannelMerger |
| Texture & lens | FilmGrain, Vignette, Blur, MotionBlur, UnsharpMask, HighPass, HalftoneScreen, TileOffset, TemporalDeflicker |
| Distortion | DisplacementMap, Liquify, MeshWarp, CornerPin, Rotate, Flip, KenBurns, ResizerScaler |
| 3D & light | Relight3D, SSAO, PBRGlass, DepthOfField, RefractionCaustics3D, CameraParallax3D |
| Mattes & keying | ColorKey, Crop, RefineEdge, MaskMath, PatchHeal |
| Generators & style | NoiseGenerator, ProceduralVFX, Paint, LayerStyle |
| Audio | AudioFade, AudioCompressor, AudioParametricEq, AudioReverb, AudioDelay, AudioNoiseGate, StereoPanning, AudioSignalExtractor |
| Vision | Vision (prefer withVision, see Vision) |
Restraint
Section titled “Restraint”Grain and vignette should be felt, not seen. If a viewer notices the effect before the content, halve it.