Skip to content

Charts & media

View .mdllms.txt
Layer.video("assets/footage/clip.mp4", { width: 1920, height: 1080, fit: "cover", trimStartSec: 2, muted: true });
Layer.image("assets/images/still.webp", { width: 800, height: 600, fit: "contain" }); // .png .jpg .webp
Layer.svg("assets/images/logo.svg", { width: 400, height: 120, fit: "contain" });
Layer.lottie("assets/lottie/badge.json", { width: 400, height: 400, fit: "contain", loop: true }); // .json .lottie
Layer.caption("assets/captions/subs.srt", { /* bottom-anchored, auto-wrapping cues */ });
Builder Notes
Layer.video decoded with mediabunny/WebCodecs; fit, trimStartSec, muted, volume
Layer.image raster only. Passing .json/.lottie/video/audio is an error (unsupported_image_format)
Layer.svg vector image
Layer.lottie Lottie JSON and dotLottie via ThorVG; fit: "contain" | "cover" | "fill", loop, speed, autoplay
Layer.caption SRT-driven subtitles

All of them position, animate, matte, take effects and tilt into 3D like any layer. Asset paths resolve from the working directory; build them from import.meta.url if the preview must load them too.

Process a single clip outside the layer tree, e.g. to grade footage or extract a still.

import { ApplyLUT, Media } from "framefields";
const graded = Media.video("assets/footage/raw_log.mp4").apply(new ApplyLUT({ lutUrl: "assets/luts/rec709.cube" }));
await graded.renderFrame({ atMs: 1500 }); // PNG Buffer
await graded.renderVideo({ outputPath: "output/graded.mp4" });

Media.video, Media.image, Media.lottie, Media.audio; each has apply, renderFrame, renderFrameGrid, renderVideo.

Layer.chart(options, boxProps) builds a chart out of ordinary boxes, paths and text — d3 does the scales and geometry, framefields draws it with your fonts.

Layer.chart(
{
type: "bar", // line | area | bar | scatter | candlestick | pie | donut
width: 900, height: 480,
categories: ["Q1", "Q2", "Q3", "Q4"],
series: [
{ name: "Revenue", data: [12, 19, 24, 31] },
{ name: "Costs", data: [8, 11, 13, 15] },
],
yAxis: { min: 0, ticks: 4, format: "$,.0f" }, // d3-format string or (v) => string
fontFamily: "Inter", fontSize: 24, textColor: "#e6e8e6", gridColor: "#2a2b2d",
animate: { start: 10, duration: 30, stagger: 6, ease: "power3.out" }, // or false
},
{ id: "revenue", position: "absolute", x: 120, y: 200 },
);
Option Notes
series: [{ name, data, color, type, curve, pointRadius }] or data data for pie/donut slices and candles
stacked stack bars/areas
xAxis, yAxis min, max, ticks, grid, format
legend, valueLabels booleans
colors, textColor, gridColor, background, cornerRadius style
innerRadius donut hole
upColor, downColor candlesticks
animate built-in reveal: lines draw on, bars grow, points and slices stagger

Children get stable ids — <id>-bar-<series>-<i>, <id>-line-<series>, <id>-slice-<i> — so you can find them in lint output. Keep scatter plots to a few hundred points: each point is a node.