Quickstart Guide
GETTING STARTEDVide compiles a strictly deterministic subset of JavaScript. All elements are structured as nodes with local timelines, assembled via parallel and sequence composition.
Declare visual elements (`src`, `text`, `circle`, `rect`).
Attach tweens via `animate()` and `fade()`.
Layer with `parallel()` or sequence with `sequence()`.
Pass the root node to `output()` to render.
// 1. Assets
const bg = src("./assets/river.mp4", { in: 0, out: 6 });
const title = text("VIDE MOTION", {
x: 960,
y: 540,
fontSize: 64,
fontFamily: "Rajdhani",
fill: "#00f0ff",
duration: 5
});
// 2. Animations
animate(title, "y", { from: 600, to: 540, duration: 1.0, at: "start", ease: "easeOutCubic" });
fade(title, { in: 0.8, out: 0.8 });
// 3. Composition
const main = parallel([
at(0, bg),
at(1.0, title)
]);
// 4. Output
output(main, {
width: 1920,
height: 1080,
fps: 60,
backgroundColor: "#02050b"
});1. The 4-Step Mental Model
CORE PRINCIPLEVide scripts are deterministic JavaScript evaluated with Acorn into an immutable AST graph. Every video is created in four simple stages:
// 1. ASSETS & SHAPES: Declare your visual layers
const bg = src("./assets/bg.mp4", { in: 0, out: 8 });
const title = text("CYBER CORE", { fontSize: 64, fill: "#00f0ff", duration: 5 });
const formula = math("e^{i\\theta} = \\cos\\theta + i\\sin\\theta", { fontSize: 48, fill: "#ffffff", duration: 5 });
// 2. ANIMATION: Attach tweens & transitions
animate(title, "y", { from: 600, to: 540, duration: 1.0, ease: "easeOutCubic" });
fade(title, { in: 0.8, out: 0.8 });
// 3. COMPOSITION: Layer simultaneously (parallel) or in series (sequence)
const main = parallel([
at(0, bg),
at(1.5, title),
at(2.0, formula)
]);
// 4. OUTPUT: Designate root scene and render resolution
output(main, { width: 1920, height: 1080, fps: 60, backgroundColor: "#02050b" });math(tex, options)
LATEX MATHRenders publication-quality mathematical formulas on the 2D canvas using KaTeX.
math(tex: string, options?: MathOptions): MathNode| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| tex | string | LaTeX mathematical expression |
| fontSize | number | Equation font size in pixels (default: 48) |
| fill | string | Formula color (default: "#ffffff") |
| displayMode | boolean | Render as block display equation (default: true) |
// Euler's Formula & Derivatives
const euler = math("e^{i\\theta} = \\cos\\theta + i\\sin\\theta", {
x: 960,
y: 540,
fontSize: 54,
fill: "#00f0ff",
duration: 6
});
const derivative = math("\\frac{d}{dx}\\left(e^x\\right) = e^x", {
x: 960,
y: 650,
fontSize: 48,
fill: "#ff9900",
duration: 6
});src(path, options)
MEDIALoads local or remote video/image assets with optional sub-second trimming and volume control.
src(path: string, options?: SrcOptions): SrcNode| PARAM | TYPE | DESCRIPTION |
|---|---|---|
| path | string | File system relative path or URL |
| in | number | In-point trim timestamp in seconds |
| out | number | Out-point trim timestamp in seconds |
| volume | number | Audio volume (0.0 to 1.0) |
// Trim river.mp4 from second 2 to second 12 (calculated duration = 10s)
const video = src("./assets/river.mp4", { in: 2, out: 12, volume: 0.8 });
// Still image with 5-second duration
const logo = src("./assets/logo.png", { x: 960, y: 300, scale: 0.5, duration: 5 });Primitive Shapes & SVG Paths
VECTORS & PATHSHigh-performance geometric primitives and SVG paths drawn directly onto the 2D canvas with stroke trimming and dash offset support.
// SVG Path with write-on trim animation
const wave = path("M -300 0 C -150 -200 150 200 300 0", {
x: 540, y: 960,
stroke: "#00f0ff", strokeWidth: 4, fill: "none",
trimEnd: 0, duration: 5
});
animate(wave, "trimEnd", { from: 0, to: 1.0, duration: 2.0, ease: "easeInOutCubic" });
// Circle & Ellipse
const orb = circle(80, { x: 960, y: 540, fill: "#00f0ff", shadowColor: "#00f0ff", shadowBlur: 20 });
const badge = ellipse(120, 60, { x: 400, y: 200, stroke: "#ff9900", strokeWidth: 2 });
// Rounded Rectangle
const card = rect(400, 240, { x: 760, y: 420, cornerRadius: 16, fill: "rgba(0,240,255,0.1)", stroke: "#00f0ff" });
// Technical HUD Line with Arrowhead
const callout = line([200, 300], [500, 400], { stroke: "#00ffaa", strokeWidth: 2, arrow: "end", duration: 5 });parallel(items, options)
LAYERINGComposites multiple visual layers simultaneously. Uses Painter’s algorithm: items at the end of the array render on top.
parallel(items: (Node | NodePlacement)[], options?: BaseNodeOptions): ParallelNodeconst main = parallel([
at(0, backgroundVideo),
at(1.5, titleOverlay),
at(after(titleOverlay, -0.5), subtitleText) // Starts 0.5s before title ends
]);sequence(items, options)
SERIALPlays clips and scenes in serial order back-to-back. Supports gap pauses and negative offset transitions.
sequence(items: (Node | GapItem | OffsetItem)[], options?: BaseNodeOptions): SequenceNodeconst movie = sequence([
introScene,
gap(0.5), // 0.5s pause
mainScene,
offset(-1.0), // Starts 1.0s early for a smooth crossfade overlap
creditsScene
]);animate() & Path Trimming
MOTION & TRIMMINGAttach property tweens, path drawing animations (trimStart, trimEnd, dashOffset), and Penner easing curves.
// Grow curve / write-on path from 0% to 100%
animate(curvePath, "trimEnd", { from: 0, to: 1.0, duration: 2.0, at: "start", ease: "easeInOutCubic" });
// Flowing dash traveling wave
animate(laserBeam, "dashOffset", { from: 0, to: -200, duration: 4.0, ease: "linear" });
// Slide and scale animation
animate(title, "y", { from: 700, to: 540, duration: 1.2, at: "start", ease: "easeOutCubic" });
fade(title, { in: 0.8, out: 0.8 });Gradients & measureText()
SHADERS & SIZINGCreate reusable linear/radial gradient fills and calculate dynamic text dimensions before layout.
// Linear gradient
const neonGrad = linearGradient({
from: [-200, 0],
to: [200, 0],
stops: [[0.0, "#00f0ff"], [1.0, "#00ffaa"]]
});
// Dynamic measured text bounding box
const titleString = "DYNAMIC BADGE";
const metrics = measureText(titleString, 48, "JetBrains Mono");
const box = rect(metrics.width + 40, metrics.height + 20, {
x: 960 - (metrics.width + 40) / 2,
y: 500,
fill: "rgba(0,240,255,0.1)",
stroke: "#00f0ff"
});output(rootNode, options)
RENDERDesignates the composition root and defines the video scene configuration.
output(main, {
width: 1920,
height: 1080,
fps: 60,
backgroundColor: "#02050b"
});Ready-to-Use Templates
STARTER PRESETSCopy or launch pre-composed motion design recipes straight into your workspace.
A. KINETIC CYBER TITLE
// Kinetic Cyber Title
const glowGrad = linearGradient({
from: [-200, 0],
to: [200, 0],
stops: [[0, "#00f0ff"], [0.5, "#ffffff"], [1, "#00ffaa"]]
});
const title = text("QUANTUM CORE", {
x: 960,
y: 540,
fontSize: 72,
fontFamily: "JetBrains Mono",
fill: glowGrad,
textAlign: "center",
shadowColor: "#00f0ff",
shadowBlur: 30,
duration: 6
});
const sub = text("// 60 FPS DETERMINISTIC CANVAS //", {
x: 960,
y: 620,
fontSize: 20,
fontFamily: "JetBrains Mono",
fill: "#ff9900",
textAlign: "center",
duration: 5.5
});
animate(title, "y", { from: 600, to: 540, duration: 1.2, at: "start", ease: "easeOutCubic" });
fade(title, { in: 0.8, out: 0.8 });
animate(sub, "y", { from: 650, to: 620, duration: 1.0, at: "start", ease: "easeOutCubic" });
fade(sub, { in: 1.0, out: 0.8 });
const main = parallel([
at(0, title),
at(0.4, sub)
]);
output(main, { width: 1920, height: 1080, fps: 60, backgroundColor: "#02050b" });B. TELEMETRY GAUGES & COUNTERS
// Telemetry Gauge Ring
const gauge = arc(160, 0, 6.283, {
x: 960,
y: 540,
innerRadius: 150,
fill: "#00f0ff",
shadowColor: "#00f0ff",
shadowBlur: 20,
duration: 6
});
const centerText = text("100%", {
x: 960,
y: 540,
fontSize: 48,
fontFamily: "JetBrains Mono",
fill: "#ffffff",
textAlign: "center",
duration: 6
});
animate(gauge, "endAngle", { from: 0.1, to: 6.283, duration: 2.0, at: "start", ease: "easeInOutCubic" });
fade(gauge, { in: 0.5, out: 0.5 });
fade(centerText, { in: 0.5, out: 0.5 });
const main = parallel([
at(0, gauge),
at(0, centerText)
]);
output(main, { width: 1920, height: 1080, fps: 60, backgroundColor: "#02050b" });C. EMOTIVE CAPSULE AVATAR (MORPHING EYES)
// ============================================================================
// VIDE EMOTIVE AVATAR // PARAMETRIC CAPSULE EYE EMOTION MORPHING
// 1920x1080 @ 60 FPS // DETERMINISTIC PROCEDURAL CHARACTER RIG
// ============================================================================
const DURATION = 16.0;
const CX = 960;
const CY = 490;
const LX = 860;
const RX = 1060;
const COLOR_CYAN = "#00f0ff";
const COLOR_FACE_BG = "#0b1220";
const COLOR_CHEEK = "rgba(255, 70, 130, 0.4)";
// ----------------------------------------------------------------------------
// 1. VISOR & HOLOGRAPHIC FACE BASE
// ----------------------------------------------------------------------------
const faceBackdrop = circle(260, {
x: CX,
y: CY,
fill: COLOR_FACE_BG,
stroke: "rgba(0, 240, 255, 0.35)",
strokeWidth: 3,
shadowColor: COLOR_CYAN,
shadowBlur: 30,
duration: DURATION
});
const telemetryRing = arc(280, 0, 5.8, {
x: CX,
y: CY,
innerRadius: 276,
fill: "rgba(0, 240, 255, 0.5)",
duration: DURATION
});
animate(telemetryRing, "rotation", { from: 0, to: 6.283, duration: DURATION, ease: "linear" });
const cheekLeft = circle(26, { x: 770, y: 535, fill: COLOR_CHEEK, opacity: 0, duration: DURATION });
const cheekRight = circle(26, { x: 1150, y: 535, fill: COLOR_CHEEK, opacity: 0, duration: DURATION });
// Blush appears during Joy phase (11.8s to 14.2s)
animate(cheekLeft, "opacity", { from: 0, to: 0.85, duration: 0.4, at: 11.8, ease: "easeOutCubic" });
animate(cheekLeft, "opacity", { from: 0.85, to: 0, duration: 0.4, at: 14.2, ease: "easeOutCubic" });
animate(cheekRight, "opacity", { from: 0, to: 0.85, duration: 0.4, at: 11.8, ease: "easeOutCubic" });
animate(cheekRight, "opacity", { from: 0.85, to: 0, duration: 0.4, at: 14.2, ease: "easeOutCubic" });
// ----------------------------------------------------------------------------
// 2. PARAMETRIC MORPHING CAPSULE EYES
// ----------------------------------------------------------------------------
const leftEye = rect(46, 116, {
x: LX,
y: CY,
anchor: "center",
cornerRadius: 23,
fill: COLOR_CYAN,
shadowColor: COLOR_CYAN,
shadowBlur: 24,
duration: DURATION
});
const rightEye = rect(46, 116, {
x: RX,
y: CY,
anchor: "center",
cornerRadius: 23,
fill: COLOR_CYAN,
shadowColor: COLOR_CYAN,
shadowBlur: 24,
duration: DURATION
});
// --- Phase 1: Bootup & Double Blink (0.0s - 2.0s) ---
animate(leftEye, "height", { from: 0, to: 116, duration: 0.5, at: 0.0, ease: "easeOutBack" });
animate(rightEye, "height", { from: 0, to: 116, duration: 0.5, at: 0.0, ease: "easeOutBack" });
animate(leftEye, "height", { from: 116, to: 8, duration: 0.08, at: 1.10, ease: "easeInQuad" });
animate(leftEye, "height", { from: 8, to: 116, duration: 0.12, at: 1.18, ease: "easeOutBack" });
animate(rightEye, "height", { from: 116, to: 8, duration: 0.08, at: 1.10, ease: "easeInQuad" });
animate(rightEye, "height", { from: 8, to: 116, duration: 0.12, at: 1.18, ease: "easeOutBack" });
animate(leftEye, "height", { from: 116, to: 8, duration: 0.08, at: 1.50, ease: "easeInQuad" });
animate(leftEye, "height", { from: 8, to: 116, duration: 0.12, at: 1.58, ease: "easeOutBack" });
animate(rightEye, "height", { from: 116, to: 8, duration: 0.08, at: 1.50, ease: "easeInQuad" });
animate(rightEye, "height", { from: 8, to: 116, duration: 0.12, at: 1.58, ease: "easeOutBack" });
// --- Phase 2: Surprise & Curiosity (2.0s - 4.2s) -> Spherical Dilation ---
animate(leftEye, "width", { from: 46, to: 92, duration: 0.4, at: 2.0, ease: "easeOutBack" });
animate(leftEye, "height", { from: 116, to: 92, duration: 0.4, at: 2.0, ease: "easeOutBack" });
animate(leftEye, "cornerRadius", { from: 23, to: 46, duration: 0.4, at: 2.0, ease: "easeOutBack" });
animate(leftEye, "y", { from: CY, to: CY - 20, duration: 0.4, at: 2.0, ease: "easeOutCubic" });
animate(rightEye, "width", { from: 46, to: 92, duration: 0.4, at: 2.0, ease: "easeOutBack" });
animate(rightEye, "height", { from: 116, to: 92, duration: 0.4, at: 2.0, ease: "easeOutBack" });
animate(rightEye, "cornerRadius", { from: 23, to: 46, duration: 0.4, at: 2.0, ease: "easeOutBack" });
animate(rightEye, "y", { from: CY, to: CY - 20, duration: 0.4, at: 2.0, ease: "easeOutCubic" });
// --- Phase 3: Suspicion & Scanning Glance (4.2s - 6.8s) -> Slit Glances ---
animate(leftEye, "width", { from: 92, to: 64, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(leftEye, "height", { from: 92, to: 24, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(leftEye, "cornerRadius", { from: 46, to: 12, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(leftEye, "y", { from: CY - 20, to: CY, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(rightEye, "width", { from: 92, to: 64, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(rightEye, "height", { from: 92, to: 24, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(rightEye, "cornerRadius", { from: 46, to: 12, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(rightEye, "y", { from: CY - 20, to: CY, duration: 0.4, at: 4.2, ease: "easeOutCubic" });
animate(leftEye, "x", { from: LX, to: LX - 40, duration: 0.4, at: 4.8, ease: "easeInOutCubic" });
animate(rightEye, "x", { from: RX, to: RX - 40, duration: 0.4, at: 4.8, ease: "easeInOutCubic" });
animate(leftEye, "x", { from: LX - 40, to: LX + 40, duration: 0.5, at: 5.6, ease: "easeInOutCubic" });
animate(rightEye, "x", { from: RX - 40, to: RX + 40, duration: 0.5, at: 5.6, ease: "easeInOutCubic" });
animate(leftEye, "x", { from: LX + 40, to: LX, duration: 0.3, at: 6.4, ease: "easeOutCubic" });
animate(rightEye, "x", { from: RX + 40, to: RX, duration: 0.3, at: 6.4, ease: "easeOutCubic" });
// --- Phase 4: Combat / Anger Mode (6.8s - 9.2s) -> Inward Slanted Blades ---
animate(leftEye, "width", { from: 64, to: 48, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(leftEye, "height", { from: 24, to: 96, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(leftEye, "cornerRadius", { from: 12, to: 16, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(leftEye, "rotation", { from: 0, to: 0.42, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(rightEye, "width", { from: 64, to: 48, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(rightEye, "height", { from: 24, to: 96, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(rightEye, "cornerRadius", { from: 12, to: 16, duration: 0.4, at: 6.8, ease: "easeOutBack" });
animate(rightEye, "rotation", { from: 0, to: -0.42, duration: 0.4, at: 6.8, ease: "easeOutBack" });
// --- Phase 5: Sadness / Glitch Droop (9.2s - 11.8s) -> Outward Droop ---
animate(leftEye, "width", { from: 48, to: 44, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(leftEye, "height", { from: 96, to: 80, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(leftEye, "cornerRadius", { from: 16, to: 22, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(leftEye, "y", { from: CY, to: CY + 25, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(leftEye, "rotation", { from: 0.42, to: -0.32, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(rightEye, "width", { from: 48, to: 44, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(rightEye, "height", { from: 96, to: 80, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(rightEye, "cornerRadius", { from: 16, to: 22, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(rightEye, "y", { from: CY, to: CY + 25, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
animate(rightEye, "rotation", { from: -0.42, to: 0.32, duration: 0.5, at: 9.2, ease: "easeOutCubic" });
// --- Phase 6: Joy & Cheeky Wink (11.8s - 14.2s) -> Left Wide, Right Wink ---
animate(leftEye, "rotation", { from: -0.32, to: 0, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(leftEye, "y", { from: CY + 25, to: CY - 15, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(leftEye, "width", { from: 44, to: 54, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(leftEye, "height", { from: 80, to: 100, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(leftEye, "cornerRadius", { from: 22, to: 27, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(rightEye, "rotation", { from: 0.32, to: 0, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(rightEye, "y", { from: CY + 25, to: CY - 15, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(rightEye, "width", { from: 44, to: 60, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(rightEye, "height", { from: 80, to: 8, duration: 0.4, at: 11.8, ease: "easeOutBack" });
animate(rightEye, "cornerRadius", { from: 22, to: 4, duration: 0.4, at: 11.8, ease: "easeOutBack" });
// --- Phase 7: Symmetrical Neutral Standby (14.2s - 16.0s) ---
animate(leftEye, "width", { from: 54, to: 46, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(leftEye, "height", { from: 100, to: 116, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(leftEye, "cornerRadius", { from: 27, to: 23, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(leftEye, "y", { from: CY - 15, to: CY, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(rightEye, "width", { from: 60, to: 46, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(rightEye, "height", { from: 8, to: 116, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(rightEye, "cornerRadius", { from: 4, to: 23, duration: 0.4, at: 14.2, ease: "easeOutBack" });
animate(rightEye, "y", { from: CY - 15, to: CY, duration: 0.4, at: 14.2, ease: "easeOutBack" });
// ----------------------------------------------------------------------------
// 3. EMOTION STATUS HUD READOUT & MOUTH
// ----------------------------------------------------------------------------
const statusLabel = text("// EMOTE PROTOCOL: ONLINE //", {
x: CX,
y: 840,
fontSize: 20,
fontFamily: "JetBrains Mono",
fill: COLOR_CYAN,
textAlign: "center",
duration: DURATION
});
const smileMouth = arc(42, 0.2, 2.94, {
x: CX,
y: CY + 110,
stroke: COLOR_CYAN,
strokeWidth: 4,
lineCap: "round",
opacity: 0,
duration: DURATION
});
animate(smileMouth, "opacity", { from: 0, to: 1.0, duration: 0.4, at: 11.8, ease: "easeOutCubic" });
animate(smileMouth, "opacity", { from: 1.0, to: 0, duration: 0.4, at: 14.2, ease: "easeOutCubic" });
const avatarGroup = group([
faceBackdrop,
telemetryRing,
cheekLeft,
cheekRight,
leftEye,
rightEye,
smileMouth,
statusLabel
], { duration: DURATION });
const main = parallel([
at(0.0, avatarGroup)
]);
output(main, {
width: 1920,
height: 1080,
fps: 60,
backgroundColor: "#050811",
duration: DURATION
});