A scene is the picture of one video, written as code by your agent. An idea like “what’s the difference?” and an idea like “3 facts about octopuses” need different pictures, so the agent writes a new scene for each one. vfrey has no fixed template per idea. The default template is only a fallback. It renders when you pass no --scene.

What a scene is

A scene is a folder. The file inside depends on the engine. The agent can put its own SVG drawings in the folder and use them with <img src="cook.svg">.

What vfrey supplies

vfrey writes these into DIR/vfrey/ when the scene is made and again when it renders. Do not edit them. They are replaced each time. A Remotion scene gets the same timing and art, and imports its helpers from @vfrey/scene instead of vfrey.js. The scene can use any of it or none of it.

What vfrey fixes

These do not change, whatever the scene says.
  • The video is 1080×1920 at 30 fps. It lasts as long as the voice, plus 0.3 seconds.
  • vfrey burns the AI-GENERATED label on top after the engine renders. Nothing a scene draws can hide it.
  • The network is blocked while a scene renders. A request to the outside gets a warning on the run. It does not hang. A scene cannot load a CDN, so use the local files.
  • A scene folder can be 50 MB at most. SVGs are sanitized.
  • vfrey copies the scene for each job. It keeps the copy with the run, in the data folder’s scenes/JOB_ID/ (.vfrey/scenes/JOB_ID/ in a project).

The workflow

1

Start from a starter

This writes my-scene/index.html and the vfrey/ files. Add --script script.json to time the scene from your script; without it, vfrey/timing.json comes from a sample script and says "placeholder": true. Add --engine remotion for index.tsx. --engine also takes framey (the default) and hyperframes. The starter is a short example. Replace it.
2

Edit

The agent designs the picture for the idea in front of it.
3

Look at a frame

This writes one frame, with the label on it. It is silent. Always pass --script: without it the sample script times the frame. Until a voice exists, the timing is estimated from your script. Once a run has made the voice for that script, the same command times the frame by the real voice, so beats land where they will in the final render (the Timing: line says which). Open it, fix the layout, and check a second moment such as --frame 9.
4

Make the video

The summary says Scene: agent-written. --json has a scene field.
5

Look again after the first render

After the first full render, re-check the frames at the beat times in vfrey/timing.json (beats[].start). Run the same --frame command again: the preview now uses the real voice and can differ from the first estimate. Fix what moved, then render again.
render --scene DIR without --frame renders the whole scene to an MP4. Pass --engine whenever you use a scene, so the scene file and the engine match.
An HTML scene needs vfrey-framey or hyperframes. A React scene needs remotion. A mismatch stops with a ✗ line and a Fix: line that names the matching engine. There is no fallback and no automatic switch.

Look before you change, and edit by eye

Two commands help when you change an existing scene. Both are for HTML scenes only.
  • npx vfrey scene inspect DIR finds the exact element, CSS rule, and GSAP tween (with file and line) behind the thing you name, so a “change just this” edit touches only that. --at SECONDS seeks the timeline. --selector CSS or --text "words" narrows it. --script FILE sets the text. --json prints it for a machine.
  • npx vfrey scene studio DIR opens the scene in a visual editor (timeline, code, and live preview) and saves your edits back into DIR. It runs on your machine at 127.0.0.1, on a free port from 47000, until you press Ctrl+C. --port N picks the port. --no-browser prints the address only.

Blocks

For a lower third, a chart, a chat card, or an overlay, the agent can copy a ready-made block into the scene with npx vfrey scene add BLOCK DIR and time it with vfrey.block. See Scene blocks.

Transitions

To cut between two shots with a shader, such as a glitch, a light leak, or an iris, an HTML scene calls vfrey.transition. There are 15 types, listed by npx vfrey scene transitions. A Remotion scene does not support them. See Shader transitions.

An HTML example

This is a short scene for vfrey-framey. A dot grows when the second line is spoken, and the captions follow the voice.
The helper has these functions. Keep every visible thing a function of timeline time. Do not use Date.now or unseeded random, or a frame will differ from render to render.

A Remotion example

This is the same idea for remotion. Use npx vfrey scene init my-scene --engine remotion to start.

The timing data

vfrey.timing and useTiming() return the same shape, in seconds.
  • durationSec: the length of the voice.
  • words: { i, text, start, end, line } for each word.
  • lines: { i, text, start, end, firstWord, lastWord } for each line.
  • beats: { i, role, text, caption, start, end, firstLine, lastLine } for each beat.

For agents

  • Design the picture for the idea. Do not copy a starter or an example.
  • Run scene init DIR for a start, then replace it.
  • Look at a frame with --frame before you make the video. Check a second moment.
  • Pass --engine with --scene. Say whether the scene was agent-written or the default template.
  • The scene is checked before and after the render. A failed check has a Fix: line: do it. See Quality checks.
  • If a run stops with a Fix: line, relay it. Do not switch engines quietly.
See Engines for how to choose an engine and Commands for the flags.