Quickstart.
One script, one render, one preview. Every example below is the full file.
1: Write a script
Save this as intro.lgv. A ball glides left to right over two seconds at thirty frames.
scene(2, 30)
shape("ball", "circle", table{
"0": table{x: 100, y: 180, r: 40, color: "#e64c40"},
"2": table{x: 540, y: 180, r: 40, color: "#e64c40"},
})
Read it top to bottom: scene(2, 30) sets duration and fps. shape("ball", "circle", tableEllipsis) declares one circle named ball at two times: t=0 at x=100, t=2 at x=540. The engine fills the middle.
2: Render it
Flags go anywhere. Before or after the script path — both parse. Examples keep flags-first by convention.
kyfram render --out out.mp4 intro.lgv
A single still frame at t=0, no ffmpeg needed:
kyfram render --format png --out frame.png intro.lgv
Higher quality: --crf 18 --preset slow. See the CLI page for every flag.
3: Preview it live
kyfram view intro.lgv # opens http://localhost:7070
Scrub slider, play button, keyboard stepping, and hot reload: every request re-reads the script from disk, so saving the file updates the preview with no watcher and no restart. The transport has a time ruler, loop toggle, PNG export of the current frame, and a fullscreen stage (F). Space plays, arrows step, Home/End jump.
What you should see
A red circle centered at y=180, gliding from x=100 to x=540 over 2 seconds. Past t=2 the value holds — kyfram never extrapolates past the last keyframe. Change 540 to 320, save, and the preview retimes itself.
4: Render a still (0 timestamps)
Animation is optional. Give every entity a single keyframe and the frame is the picture — values hold forever, so one timestamp renders a finished image. No ffmpeg involved:
kyfram render --format png --out still.png intro.lgv # frame at t=0
Two helpers for still work: transparent(true) clears with RGBA(0,0,0,0) for overlays, and the image kind composites existing PNGs into the scene. This project's own logo is a still — examples/logo.lgv renders assets/logo.png.