Graphic specs and review
One JSON file for one graphic: the item, its props, the brand, the shape, the motion and the sound. Every command takes it in place of an item, so the graphic lives in your repo, gets reviewed like code and hands over to an agent whole.
Write a spec
volito spec takes the same options as render and writes them down instead of rendering:
volito spec lower-third --prop name="Priya Sharma" --prop role="Product designer" \
--style ember --aspect 9:16 --out priya.volito.json
volito render priya.volito.json # renders what the spec says
volito render priya.volito.json --aspect 16:9 # options on the command line win{
"$schema": "https://volito.dev/schema/graphic.v1.json",
"volito": 1,
"item": "essentials/lower-third",
"props": { "name": "Priya Sharma", "role": "Product designer" },
"style": "./DESIGN.md",
"aspect": "9:16",
"motion": { "name": { "in": "typewriter" } },
"mood": "elegant",
"seed": 4,
"sound": { "bed": "Dm" },
"render": { "format": "mov", "out": "renders/priya.mov" }
}A spec draws exactly one of item (a pack item), program (a path to your own frame(t, $) file) or code (the program inline). Paths inside it, a DESIGN.md, a program, a transcript or an image prop, are relative to the spec file, so the folder moves as one.
| Field | What it holds |
|---|---|
item · program · code | What it draws; placement (overlay or full) for a program. |
props | The item's props. |
style · colors | A built-in style or a path to a DESIGN.md, and colour overrides. |
aspect · duration · fps · width · background | The frame. |
words · offset | A transcript, inline or a path, and where the graphic starts in it. |
beats · motion · mood · seed · speed | Timing and choreography, as in Motion. |
sound | true, or { "bed": "Dm", "level": 1.2 }. See Sound design. |
render | format and out, used when the command line gives none. |
The JSON Schema
The $schema line gives editors completion and checking as you type. The schema is served at https://volito.dev/schema/graphic.v1.json, and volito schema prints it. It is strict: an unknown field is an error, not a silent no-op.
Validate before rendering
volito validate checks the spec's shape and then the spec against its item: every prop, part and file, the aspect and the duration. A typo is caught before a render spends time on it:
$ volito validate typo.json
✗ typo.json
✗ unknown field "prop" — did you mean "props"?
$ volito validate draft.json --strict
✗ draft.json
! props.nmae: unknown prop "nmae" (props: name, role, side, look)Errors exit 1. Warnings, like a prop the item does not have, pass unless you add --strict, which makes them fail too: the one to put in CI. --json prints the report for scripts.
Bundles
volito bundle priya.volito.json packs the spec and every file it uses, the DESIGN.md, the program, the transcript and the images, into one priya.volito. Every command takes the bundle as it takes a spec, on any machine, so one file carries a whole graphic to a teammate, a server or an agent.
volito bundle priya.volito.json --out priya.volito
volito render priya.volito --format webmReview before you render
volito review lower-third --prop name="Priya Sharma" --aspect 9:16
volito review priya.volito.jsonreview runs the check at each aspect, then measures what the frames show: when the graphic settles, how long it holds still and when it leaves. It warns when the entrance is slow or the hold is too short to read its words, and at 9:16 it measures how much of an overlay sits under the Instagram Reels, YouTube Shorts and TikTok interface.
essentials/lower-third: ready
9:16: ok · in by 0.90 s · holds 3.70 s · leaves at 4.60 s
warning: 9% of the graphic sits under Instagram Reels' username, caption and audio
→ a top or centre placement, or keep it for 16:9 and 1:1
sheet: volito-review/lower-third/lower-third-9x16.png
report: volito-review/lower-third/review.mdEach aspect gets a contact sheet, and review.md collects the report for a pull request. Full-frame items and transitions skip the safe zones; items with interactive states get a note instead of timing warnings, because on a page their holds wait on the viewer.
From Node
import { readFileSync } from "node:fs";
import { loadSpecFile, itemOfSpec, specToOptions, validateSpec, renderVideo } from "volito";
const report = validateSpec(JSON.parse(readFileSync("priya.volito.json", "utf8")), { dir: "." });
if (!report.ok) throw new Error(report.errors.map((e) => e.message).join("\n"));
const loaded = loadSpecFile("priya.volito.json");
const item = itemOfSpec(loaded);
await renderVideo(item, { ...specToOptions(loaded, item), out: "priya.mov" });Agents get the same: every MCP tool takes a spec file in place of an item, motion_validate checks one (inline or a file), and motion_review returns the timing, the safe zones and the contact sheets. See AI agents.