关于 framefields-effects
framefields-effects 是面向使用 framefields 的创作者与开发者的技能指南,介绍如何为图层、合成和媒体添加 GPU 效果。它还涵盖设备端视觉模型及其结果驱动的响应式信号。
主要功能
- 01为图层、合成和媒体应用效果
- 02提供调色、镜头与纹理效果
- 03支持时间变化和响应式参数
- 04包含空间照明与材质效果
- 05运行视觉检测、分割和姿态模型
适用场景
- 01为视频片段应用色彩分级与镜头效果
- 02为合成添加局部模糊或空间照明
- 03用视觉模型跟踪对象或生成蒙版
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gatewai-dev/ framefields --skill framefields-effects安装后在 Claude Code 中输入/framefields-effects确认已加载。
附带文件references/effects-catalog.mdreferences/style-guide.md
详细介绍
framefields-effects
设置
从 framefields npm 包中导入所有内容。如果项目尚未设置 framefields,请先按照 framefields 技能进行操作(安装、项目脚手架、首次渲染)。
概述
framefields 提供原生 WebGPU 着色器执行管线,用于 2D 视觉特效、色调分级、电影镜头模拟、空间重新打光和实时神经视觉条件处理。
framefields 中的特效是强类型的 Effect 子类,其 uniform 属性可由静态值、随时间变化的关键帧、响应式 Signal 实例或音频提取管线驱动。
有关生成的属性级目录、默认值和类型范围,请参阅 references/effects-catalog.md。
添加特效
引擎中有 4 种主要的添加模式:
1. 图层级特效管线
通过 .withEffect(effect) 或 .withEffects([...]),直接为任意图层(box、flex、shape、text、media)添加一个或多个特效:
import { Layer, Curves, Vignette, Blur, Pixelate } from "framefields";
// Media layer with color grade and lens effects
const videoLayer = Layer.video("assets/footage.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: 0.4, radius: 0.85, softness: 0.6 }))
.withEffect(new Blur({ strength: 8, blurType: "Gaussian" }));
// Styled container box with blur
const cardLayer = Layer.box({ width: 400, height: 300, background: "#1e1e24" })
.withEffect(new Blur({ radius: 12 }));
// Kinetic text with pixelation
const titleLayer = Layer.text("CYBERPUNK", { fontSize: 72 })
.withEffect(new Pixelate({ size: 8 }));
2. 整个合成的主乳剂效果
在所有渲染图层上应用整体后期处理色调分级或胶片乳剂效果:
import { Composition, FilmGrain, ColorBalance } from "framefields";
const comp = new Composition({ width: 1920, height: 1080, fps: 30 });
// Shared organic 35mm grain applied across titles, background video, and vector graphics
comp.apply(new FilmGrain({
strength: 0.06,
size: 1.5,
monochrome: true,
animated: true,
speed: 1.0,
}));
comp.apply(new ColorBalance({
shadows: { cyanRed: 4, yellowBlue: -6 },
highlights: { cyanRed: 2, yellowBlue: -4 },
preserveLuminosity: true,
}));
3. 空间与跟踪区域(comp.section / Layer.section)
隔离底片或画布的子区域,以应用局部特效:
// Box blur on a tracked object or explicit bounding rectangle
const blurredPlate = comp.section({
source: "assets/interview.mp4",
x: 400,
y: 200,
width: 300,
height: 300,
borderRadius: 150,
effects: [new Blur({ strength: 25, blurType: "Gaussian" })],
});
4. 流畅的媒体链式处理(Media)
在挂载或导出前,于布局树之外处理片段:
import { Media, ApplyLUT, Crop } from "framefields";
const clip = Media.video("assets/raw_log.mp4")
.apply(new ApplyLUT({ lutUrl: "assets/luts/cinematic.cube", intensity: 1.0 }))
.apply(new Crop({ cropType: "rectangle", topPercentage: 10, heightPercentage: 80 }));
const pngBuffer = await clip.renderFrame({ atMs: 1500 });
特效类别
1. 色彩分级与色调动态
Curves:使用样条插值的色调曲线,涵盖主曲线、红、绿、蓝,以及色相/饱和度曲线(hueVsHue、hueVsSat、lumVsSat、satVsSat)。ColorBalance:分别调整阴影、中间调和高光颜色,并支持preserveLuminosity。Levels:主通道和各通道的输入/输出黑白场及伽马。SelectiveColor:采用 CMYK 风格的摄影选择性色彩调整,针对红色、黄色、绿色、青色、蓝色、洋红色、白色、中性色和黑色。GradientMap:使用多节点渐变重新映射(stops: [{ position: 0, color: "#000" }, { position: 1, color: "#FFF" }])。ShadowsHighlights:分别提亮阴影和恢复高光,并提供半径和色调宽度控制。ApplyLUT:1D 和 3D.cube色彩查找表应用器。Modulate:实时 HSL/对比度控制:hue、brightness、contrast、exposure、saturation、sepia。
2. 光学、纹理与电影乳剂效果
FilmGrain:由 GPU 合成的胶片颗粒,支持颗粒尺寸、阴影/高光遮罩和时间动画速度。Vignette:椭圆形或圆形镜头衰减,可自定义中心、圆度和柔化程度。Blur:高性能多模式模糊:"Gaussian"、"Box"、"Median"、"Motion"、"Bilateral"、"Edge-preserving"、"Radial"、"Zoom"。支持局部模糊区域和跟踪对象边界框。UnsharpMask:高频边缘锐化,并抑制低于阈值的部分。HighPass:隔离边缘和频率,并增强对比度。HalftoneScreen:程序化印刷网屏,可使用"Circle"、"Diamond"、"Line"或"Square"网点,并采用"Monochrome"或"CMYK"角度。TileOffset:无缝 UV 环绕,支持"wrap"、"clamp"、"mirror"或"transparent"边界模式。MotionBlur:方向性快门模拟,支持自定义快门角度和速度限制。TemporalDeflicker:多帧光流混合,用于消除生成式 AI 片段或高速镜头中的闪烁。
时序(带记忆的效果)
Trails:将图层叠加在自身逐渐衰减的历史画面之上。mode: "blend"(默认;在完整画面素材上产生回声效果)、"over"(抠图和文字)、"add"(在暗场景中绘制光轨)、"max"(光迹)。decay取值为 0.8 时产生短暂回声,0.97 时产生长光轨;逐帧设置zoom(1.02 = 隧道效果)、rotation、offsetX/Y、hueShift(循环变换色相,产生迷幻效果)。Datamosh:将上一帧画面沿新帧的光流拖动,而非刷新画面,直到keyframes中的帧(I 帧)显示干净画面。在希望画面干净的位置设置关键帧;省去剪切点,即可用下一个镜头的运动拖抹当前镜头。strength、bleed(逐帧混回干净画面的程度)。- 两者都会随帧渲染而逐步处理;跳转之后(拖动时间轴或单次调用
renderFrame),会重放最近的帧(warmup),以重建历史状态。
3. 3D 空间光照与材质
Relight3D:使用屏幕空间法线贴图重新打光,支持点光源、聚光灯和方向光,以及镜面高光、粗糙度和金属度 uniform。SSAO:利用深度缓冲生成接触阴影的屏幕空间环境光遮蔽。PBRGlass:基于物理的透射、折射率(IOR)、光学色散和菲涅耳反射。DepthOfField:模拟相机镜头,支持光圈大小、焦距、焦平面距离和弥散圆(CoC)模糊。
4. 遮罩、键控与边缘处理
ColorKey:适用于摄影棚绿幕/蓝幕的抠像工具,带有溢色抑制和平滑度控制。Crop:按矩形、圆形或任意多边形路径裁剪,并支持圆角。
5. 风格化效果(Styles.*)
**根据需求选择风格:**参见 references/style-guide.md。该指南将“VHS”“8-bit”“漫画”或“液态 Logo”等描述对应到预设、效果和技巧。每当有人提及某种风格时,都应阅读该指南。
Styles.<name>(options?) 会返回一个效果堆栈:layer.withEffects(Styles.vhs())。预设:pixelArt、gameBoy、teletext、ledWall、ascii、oneBit、risograph、comic、cartoon、thermal、vhs、crt、glitch、oilPainting、watercolor、topographic、kaleidoscope、opArt、holographic、noir、film。
这些预设背后的效果可用于更精细的控制:
Pixelate:放大像素;shape: "square" | "circle" | "diamond"(LED 墙效果)、gap。Posterize:减少颜色数量,或匹配到某个palette(gameboy、teletext、cga、pico8、c64、grayscale、sepia、custom+colors),并支持 Bayerdither和pixelSize。Dither:bayer/noise/halftone;支持 1-bit 双调色(dark/light)或按通道设置levels。Ascii:根据亮度选择字形;colorMode: "mono" | "source" | "green"、cellSize、fg/bg、invert。Toon:亮度分区加 Sobel 墨线(edgeColor、edgeWidth、edgeThreshold)。RGBSplit:沿angle方向或以径向方式产生色差。CRT:曲率、扫描线、孔径掩模、噪点、闪烁、暗角;tracking和chroma可产生 VHS 抖动和色彩渗漏。Painterly:Kuwaharaoil/watercolor(颜料边缘、纸张纹理)。Contour:在source上叠加地形等高线,也可使用flat纸张颜色,或不使用底色。Kaleidoscope:围绕中心镜像segments;可为rotation/zoom添加动画。OpArt:条纹/圆环/棋盘格/波纹会随图像弯曲并变粗。Iridescence:根据亮度或浮雕效果生成薄膜彩虹;可为shift添加动画。Gooey:模糊 + Alpha 阈值(融合球)。用于带透明度的图层(SVG、粒子),不要用于不透明素材。
设备端视觉
framefields 在渲染后的帧上运行视觉模型,并将结果作为响应式信号公开。模型会在首次使用时按需下载,并缓存到 $FRAMEFIELDS_MODELS_DIR(默认为 ~/.cache/framefields/models)。
| 选项 | 模型 | 提供内容 |
|---|---|---|
enableDetection(默认) | RTMDet-Ins | COCO-80 边界框,随时间跟踪 → vision.objects |
enableSegmentation | RTMDet-Ins(同一次推理) | 软逐实例掩码 → vision.masks、vision.segmentation |
enablePose | RTMO | 每个人的 17 个 COCO 关键点 → vision.poseLandmarks、track.pose |
enableMatte | Selfie Segmenter | 快速生成人物 Alpha → vision.segmentation.matte |
variant: "t" | "s" | "m" 可在速度与准确度之间权衡(默认为 "s")。confidence(默认为 0.3)和 classes: ["person", ...] 用于筛选检测结果。
// Whole composition: returns the reactive bundle
const vision = comp.withVision({ enableSegmentation: true, enablePose: true });
// One layer: renders through a node mode
Layer.video("assets/dancer.mp4").withVision({ mode: "matte", enableSegmentation: true });
节点模式:passthrough、mask、matte、crop、skeleton、boxes、tracking。对于 mask / matte / crop,matteSource: "instance"(默认;适用于任意 COCO 类别,重叠部分(例如并入主体的裙子))或 "selfie"(仅限人物,速度最快)。
选择设置
在 CPU 上对每帧 1280–2048 px 的画面进行测量(onnxruntime-node):
| 任务 | t | s(默认) | m |
|---|---|---|---|
| 检测 / 分割(一次共享推理) | 150–300 ms | 200–340 ms | 420–700 ms |
| 姿态 | ~50 ms | ~120 ms | ~280 ms |
| Matte(Selfie Segmenter) | ~20 ms | ~20 ms | ~20 ms |
- 从
"s"开始。快速运动模糊或背景杂乱的主视觉镜头可使用"m";"t"主要能缩短姿态估计时间。 - 同时启用
enableDetection和enableSegmentation只需一次推理,而非两次。 - **Selfie Matte 仅适用于近景构图。**它针对人物占据画面较大部分的情况进行了调优:无法检测远处人物,而且在没有人物的特写画面中也可能报告检测到“person”。其他情况请保留
matteSource: "instance"。 - 对抽象或风格化画面,提高
confidence(例如0.5)——在默认值0.3下,模型会给烟雾、眼睛和行星贴上宽泛的标签(如“teddy bear”“donut”)。 - 只关心某个对象时,限制
classes;这样也能防止人物离开画面后主体切换为其他对象。
GPU 或 CPU
推理会通过 onnxruntime-web 的 WebGPU 后端(framefields 的可选依赖,默认安装)在硬件适配器上使用 GPU 运行;否则会通过 onnxruntime-node 使用 CPU 运行:当缺少 onnxruntime-web、唯一的适配器为软件适配器(lavapipe、SwiftShader)或 WebGPU 失败时,将使用 CPU。在 Apple Silicon Mac 上,GPU 的渲染时间大约是 CPU 的一半。使用相同 variant 的图层会共享模型,显示相同像素的图层会共享一次检测 / 分割推理。
| 变量 | 作用 |
|---|---|
FRAMEFIELDS_VISION_PROVIDER | auto(默认)、webgpu、cpu 或 cuda(Linux x64 上 onnxruntime-node 的 CUDA EP;需要 CUDA 12 和 cuDNN 9 库)。强制指定的后端若运行失败,会抛出错误,而不会回退。 |
FRAMEFIELDS_VISION_THREADS | 每个模型使用的 CPU 线程数。Linux 上的默认值为进程可使用的 CPU 数量(包括 cgroup 配额);其他平台使用 ONNX Runtime 的默认值。 |
渲染时的行为
- 延迟一帧。 Vision 会读取该图层上一帧渲染的画面,因此第一帧没有结果(抠像会渲染为透明),蒙版也会比底片晚一帧。这在正常播放速度下无法察觉。若合成也通过
comp.vision读取了该片段,则不会出现这些情况(见下文的 Clip Vision)。 - 按顺序渲染 Vision 帧。
renderVideo会为你完成这项工作。对于静帧,请使用同一个渲染器连续渲染至少两帧,并保留最后一帧。直接跳到较后的帧(或使用帧网格)会从之前渲染的画面中抠出像素,导致主体出现重影。 - 主体选择。
mask/matte/crop会选择面积最大的人物;没有人物时,则选择置信度最高的实例。与主体重叠且面积不超过主体两倍的实例会合并进来(如裙子、手持乐器);周围的大型物体(如隧道、窗框)则不会。classes用于限制主体类别,而非限制合并到主体中的内容:COCO 没有服装类别,因此飘动的裙子常被识别为“风筝”或“雨伞”,但仍会并入classes: ["person"]的抠像结果中。 - 每个 Vision 图层都会独立跟踪对象;不同图层中的跟踪 ID 互不相关。
故障排除
| 问题 | 解决方法 |
|---|---|
| 快速移动的衣物有部分未被抠出 | 使用 variant: "m",或设置 keyBackground: true,将主体扩展到相连的前景区域 |
| 抠出的对象不正确 | 设置 classes: ["person"](或你想要的类别) |
| 深色背景下抠像周围有淡淡的光晕 | 降低 featherRadius,或提高 maskThreshold(例如 0.6) |
| 离线或在 CI 中渲染 | 使用 runner.preload([...]) 将模型预下载到 $FRAMEFIELDS_MODELS_DIR,或将 FRAMEFIELDS_MODELS_BASE_URL 指向镜像 |
| 检查模型本身 | 在全新的模型目录上运行 await runner.preload([...]);该命令会下载每个模型并验证其 SHA-256(全部模型约为 380 MB) |
1. 主体夹层效果(“文字置于主体后方”)
从素材中抠出前景主体,并将文字或图形直接置于其后:
comp.addSubjectSandwich({
source: "assets/dancer.mp4",
behind: [
Layer.text("HEADLINE BEHIND", {
fontSize: 120,
fill: "#FF5A1F",
fontWeight: 900
})
],
feather: 4,
fit: "cover"
});
2. 智能重新构图(16:9 转 9:16 自动裁切)
通过虚拟摄像机阻尼跟随被跟踪主体,将横向视频平滑地重新构图为竖屏短视频:
const vision = comp.withVision({ enableDetection: true });
comp.addSmartFraming({
source: "assets/action.mp4",
target: vision.objects.primary,
targetAspect: 9 / 16,
damping: 0.15,
leadHeadroom: 0.1
});
3. 主体轮廓辉光与霓虹脉冲
为分割出的主体边界描边,添加随音频变化的轮廓辉光:
const vision = comp.withVision({ enableSegmentation: true });
comp.addSubjectOutline(vision.segmentation.subject, {
source: "assets/character.mp4",
color: "#FF5A1F",
width: 6,
blur: 12
});
4. 跟踪区域模糊
跟随实时跟踪对象,对人脸、车牌或任何检测到的类别进行模糊处理:
const vision = comp.withVision({ classes: ["person"] });
layer.blurRegion(vision.objects.byCategory("person"), { strength: 30 });
5. Clip Vision:在画面渲染前获取结果
withVision 会分析图层上一帧的渲染结果,因此结果会滞后一帧,而且仅在渲染期间存在。当某项功能必须知道当前帧的运动情况时(例如物理模拟、布局、关键帧),请使用 comp.vision,按需分析剪辑自身的帧:
const dancer = comp.vision("assets/dancer.mp4", { startFrame: 0 }); // pose + silhouette (person)
const person = dancer.person.place({ width: W, height: H, fit: "cover" });
person.point("rightWrist", 48); // { x, y, visibility } in composition px, smoothed over ±2 frames
person.signals("nose").x; // a signal for .signal("x", …)
person.sample(48, x, y); // silhouette alpha + inward gradient (dress and held things included)
await dancer.ready(0); // analyse a frame (or a range: ready(0, 120)) to read it at build time
- 合成会在绘制每一帧之前分析其中的剪辑,并在所有渲染路径和预览中执行;在步进之前,也会分析实时物理世界(
world.live(comp))。不会预先运行任何内容,因此预览会立即开始。 - 结果会持久保存在 Node 中(
~/.cache/framefields/vision,或$FRAMEFIELDS_VISION_CACHE_DIR;设置cacheDir: false可选择退出),并以文件和设置为键,因此后续运行以及预览后的渲染会立即完成。 - 选项:
startFrame/trimStartSec(剪辑播放的位置)、pose、mask、maskCell(轮廓网格,默认为 8 px)、smoothing(帧数,默认为 2)、variant。检测不到人物时,会将最后一个姿势保持最多一秒。 - 同一剪辑的
withVision({ mode: "matte" })抠像(或mask/crop)会复用这些结果:合成会将当前绘制帧对应的剪辑主体交给它,因此只需分割一次,无需在渲染时再次分割;抠像也会与同一帧的底片对齐。使用classes、keyBackground、matteSource: "selfie"或其他不同于剪辑的模型设置的图层,会保留各自的处理流程。 - CPU 上的分析每帧约耗时 200 ms(主要耗时在分割);在 WebGPU 上速度更快。在实时预览中,播放头会等待尚未分析的帧。
6. 创作前先分析
一次性生成剪辑内容报告(轨迹、类别、遮罩覆盖范围),无需 ffmpeg:
const report = await comp.analyzeVisionSequence("assets/street.mp4", {
tasks: ["detect", "pose"],
categories: ["person"]
});
report.tracks; // [{ trackId, category, frames: [start, end], centerPath, ... }]
响应式信号调制
任何 Effect 上的 Uniform 都可以使用响应式 Signal 实例代替静态值。信号发生变化时,GPU Uniform 缓冲区会自动更新,无需重建管线:
import { Layer, Blur, sineSignal, computed } from "framefields";
// Oscillating breath blur
const blurSignal = sineSignal({
frequencyHz: 0.5,
min: 0,
max: 20
});
const layer = Layer.image("assets/bg.jpg")
.withEffect(new Blur({
strength: blurSignal,
blurType: "Gaussian"
}));
最佳实践:
- **克制使用胶片效果:**让
FilmGrain(0.04–0.08)和Vignette(0.2–0.45)保持轻微。过度滤镜会显得不专业。 - **顺序很重要:**先应用色调分级(
Curves、ColorBalance),再应用镜头光学效果(Blur、DepthOfField),并将颗粒效果(FilmGrain)作为最外层。 - **避免冗余着色器:**对于静态图像导出,将
FilmGrain的animated: false设为false,以保证静态渲染结果一致。