Getting started
Looking at your work
Read the timeline, render export frames, inspect a stretch or storyboard, and measure the sound before saying a change worked.
There are two ways to check what you've made, and they answer different questions. ymotion_read tells you what the document says: the layers in time, their values and their keyframes. ymotion_render shows export frames, sheets of frames and measured sound. A caption hidden behind footage or type that wrapped can read perfectly well as numbers. Render after a picture change, read when you need a value or a path, and use the timeline and sound measurements to check the whole film. What the measurements mean explains their evidence and limits.
Rendering frames
ymotion_render draws the open document at a moment you name in timeline seconds, or at the first frame if you name none:
ymotion_render {"t":1.5}
To see movement rather than a single pose, ask for several moments at once:
ymotion_render {"times":[0.5,0.7,0.9,1.2]}draws the moments you name. Up to 8 distinct export frames come back as separate pictures; 9–48 distinct frames become one labelled sheet (at most two pictures).ymotion_render {"count":5}spreads up to 8 pictures across the film.ymotion_render {"count":24}gives a storyboard sheet and a whole-film structure report.ymotion_render {"count":4,"layerId":"<layer id>"}spreads frames across one layer's time on screen. The last frame is pulled one frame inside the layer's end, because a layer isn't on screen at the exact moment it ends.ymotion_render {"layerId":"<layer id>"}on its own draws every export frame of that layer's time, as a sheet past 8 and sampled past 48; with"count":1it draws the layer's middle.
Frames are the export's
Each film time names the export frame that contains it. The reply gives its frame number and its time to three decimals; copying that printed time back into "t" reaches the same frame. A time before the film gives its first frame, and a time at or after the last frame's start gives its last frame; the reply says when it clamped. "full":true paints the document's own canvas through the export's picture path, before the mp4 encode; a film exported larger for sharper footage is the same picture with more pixels. A smaller preview is labelled preview. The reply also names any reason it cannot promise the export's picture, such as a missing typeface or mixed-rate footage. Motion blur on placed footage is included. See What the measurements mean for fidelity labels and what an image does not prove.
For a sheet, "width" caps each tile's long edge. The server keeps the film's shape and the native/client picture limits, and reports the actual tile size; a region is still cropped at full pixels and enlarged only by whole pixels. A tile must retain at least 96 pixels on its short edge. An impossible width is refused with a precise-frame alternative. "height" and "full":true are for precise frames, and are explicitly refused on sheets.
A region at full pixels
Look at the whole frame first, using an argument every client's tool list has:
ymotion_render {"t":1.5,"full":true}
If your list declares region, a second call can name a layer or give [left, top, width, height] as fractions of the frame. For example, send the same tool again with {"t":1.5,"region":"<layer id>"} or {"t":1.5,"region":[0,0,0.5,0.5]}. The server paints the full frame at the document's own size, crops its own pixels and enlarges them only by whole pixels; it does not redraw the region at a different density. A layer's shadow, blur and motion blur are included in its region; a filter that can move pixels anywhere makes the region the whole frame. A region costs the full frame's painting work. If the reply says your client dropped region, reconnect to refresh its tool list and use the whole frame meanwhile. What the measurements mean gives the four quadrants and the large-frame JPEG option.
A layer region over several selected frames skips instants where that layer has no usable region and reports each skipped frame, exact time and reason. Its images and measurements cover only the surviving frames. A precise frame or a selection with no usable region still gives the existing refusal. Malformed boxes, unknown layer ids and nested-layer region requests remain refusals.
Every frame of a stretch
ymotion_render {"from":2,"to":3}
This makes a sheet of every export frame shown at any instant in [2,3), up to 48 tiles. For a longer stretch, the reply says which frames it sampled and gives calls for all frames in parts. "from" and "to" have been declared since 2026-10-03; a client with an older tool list can use "times" to ask for 9–48 chosen moments. The sheet prints each frame number and time. Its reply names the ranged export call that would paint exactly those frames; a ranged export rounds its ends differently, so copying the original from and to into an export can differ by one frame at either end. The sheet measures its tiles and motion trace, but fine detail calls for a full frame or an optional region. See What the measurements mean.
The whole film at once
ymotion_render {"count":24}
This storyboard includes the first and last export frames, a settled frame of each shot when they fit, and frames spread across the rest. Its structure report describes beginning, middle, end, pacing, consistency and delivery. Measured facts remain available while measured findings are off; findings appear only when the owner enables them. Look at any suspected moment as a full frame, then ask the person to check the playable preview and the sound as heard. What the measurements mean explains what was checked and what remains for a person.
The reply lists the layers on screen at the first moment, from the bottom of the stack to the top, and adds a note for anything it couldn't draw: footage with no pixels available, or a typeface that couldn't be fetched. A layer named in such a note is missing from the picture, which is different from footage that is black.
Size
Frames come back 1080 pixels on the long edge unless you ask otherwise. Every length in a document is measured relative to the frame, so the engine draws the same composition with fewer pixels for a preview; its fidelity is labelled separately from a full export frame.
ymotion_render {"t":1.5,"full":true}draws at the film's own size, for judging a hairline or small type.ymotion_render {"t":1.5,"width":540}sets the long edge. It never draws larger than the film.
You can pass width and height together for an exact size that keeps the film's aspect ratio, allowing integer rounding. Another shape is refused because it would stretch the preview rather than show the export. width alone sets the long edge; height needs width too. The short edge must remain at least 16 pixels. To reframe, change the canvas instead. On the hosted server each call also has a painting budget measured in megapixels, about eight previews or two full 4K frames, and each account has a per-minute allowance that refills as time passes. If a call is refused for size, ask for fewer frames or a smaller size; if the minute's allowance is spent, the refusal says how long to wait.
A frame as a link
ymotion_render {"t":1.5,"link":true} stores the frame and answers with a URL instead of the image. A link costs a line of text rather than a picture, which makes it a cheap way to check often, and it's something the person can open.
- Without
"public", the link is private and lasts about 15 minutes. ymotion_render {"t":1.5,"link":true,"public":true}gives a stable link that anyone can open and that doesn't expire. The reply includes the frame's id, andymotion_media {"action":"share","id":"<frame id>","public":false}turns the link off.
A call for several frames stores each frame and gives one link for each. A sheet stores its picture, or both pictures when it has two. The same complete picture under the same document, frame, size and encoding has the same id however often it's asked for: a public link comes back identical, and a private one is signed afresh for that stored picture. A server on the person's own machine signs these links only over HTTP, with its public address set in YMOTION_PUBLIC_URL; over stdio it signs none.
On a server running on the person's own machine, "file" also writes the image beside the documents, for example ymotion_render {"t":1.5,"file":"title-check.png"}. It won't overwrite an existing file.
The whole film, playing
ymotion_render {"what":"preview"} answers with a link that plays the whole film, sound and all, in a browser. It's the way to show the person what you made: give them the link rather than a frame or an export. It plays the film as it is when you ask, so ask again after changing something. See Exporting a film for what the page shows and how long a link lasts.
Check the authored passage
Compare the actual edit with its source-moment plan: which planned ideas changed structure, hierarchy, graphics, timing, colour or sound, and which were left out as unsuitable? Look at the source's important relationship or turning point and the completed treatment: is it clearer than captions and a zoom, does it stay on long enough after its entrance to read, and does attention return cleanly? A deliberately quiet source can need no extra graphics. The check is the viewer's understanding, not a number of effects.
Review with frames, never with the preview. Playing the link in a browser and taking screenshots gives a smaller, later and less exact picture than a frame: a playing page lands near a time rather than on it, and can stall while it loads. ymotion_render frames are the export's own picture at the times you name, so look across the opening, the treated passage and the ending with them, and give the link to the person to watch and listen.
Seeing the sound
You can't listen to the film, but you can look at it:
ymotion_render {"what":"waveform"}
This measures the sound the export delivers: none, a copied stream or the export's mix, before its final encode. It reports integrated loudness, loudness range, peaks, silences and each sound's contribution, including speech against the rest and sound effects against events when those records exist. Its picture draws measured 100 ms loudness for the mix and its sound lanes on one −60 to 0 LUFS scale; a lane can be a nested composition's sound. If measurement is still running, the reply says when to ask again with the same call. Any interim stored-peaks picture says explicitly that those peaks are not loudness. See Sound, music and sound effects and What the measurements mean.
ymotion_render {"what":"audio"} mixes the sound into a file for the person to hear, with the same plan. It's m4a by default; "format" can be mp3 or wav, and "seconds" limits how much is mixed, up to 180.
Reading the document
ymotion_read changes nothing. Its readings:
ymotion_read {"what":"summary"}gives the canvas, duration, tracks, assets, compositions, and what undo would take back.ymotion_read {"what":"tracks"}is the timeline: layers ordered by start time, with the track named in each row, source and sound clocks, keys, and a first-page footer for cuts, gaps, delivery and unchecked work. It is paged; copy the reply'snextcall until there is no next page."limit"controls rows (60 by default, at most 200), and"like"filters rows by id, name or kind. See What the measurements mean.ymotion_read {"what":"layer","layerId":"<layer id>"}returns one layer in full: transform, crop,trimIn, speed, masks, filters, effects, sound, and which properties are animated.ymotion_read {"what":"properties","layerId":"<layer id>","like":"opacity"}lists the layer's properties, each with its path, range, current value, number of keys and the verb that writes it. It's the quickest way to find the exact path to animate and which verb keys it."like"filters by path, label or group, and"limit"raises the default of 120 rows.ymotion_read {"what":"keys","layerId":"<layer id>","path":"opacity"}returns one property's keyframes with their eases, handles and holds. Leave out"path"for all of them.ymotion_read {"what":"value","layerId":"<layer id>","path":"opacity","t":0.2}gives what a property works out to at a moment, keyframes included. Heretis measured from the layer's start, as keyframe times are.ymotion_read {"what":"scene","t":1}lists what is drawn at a timeline moment, bottom to top, with each layer's opacity, blend mode and filters.ymotion_read {"what":"box","layerId":"<layer id>","t":0.5}measures a layer the way After Effects'sourceRectAtTimedoes:lettersis the geometry,inkadds what the layer's own stroke or shadow reaches past it (not layer styles or filters),onCanvasis where it lands on the frame after its transform, andmarginis the difference between the first two. Sizes are in pixels with the same box as a fraction beside them; a box'sleftandtopare measured from the frame's top-left corner, not from its centre astransform.xandtransform.yare.tis from the layer's start. The server loads the needed faces before measuring text and saysnot_observableif one is still missing; a fallback font's box is not passed off as the layer's.ymotion_read {"what":"json","path":"canvas"}returns part of the document as saved, by path. Without a path it returns the whole document, cut at 200 KB unless you add"full":true.ymotion_read {"what":"ask","verb":"nextCut","args":{"t":0}}calls one of the verbs that answer a question rather than change anything, such askeyTimes,propAt,fits,snaporslipRange.ymotion_help {"topic":"verbs","like":"nextCut"}shows any verb's arguments.
Every reading takes "compId" to read inside a nested composition, as ymotion_edit does.
What to look for
Before telling the person something worked, a render answers most of these in one call.
- Type that wrapped or ran off the frame. Paragraph text wraps at its width, so a long headline can drop onto a second line. Look at the frame, or read
boxand check thatonCanvasstays within the frame. A line meant to stay on one line can be point text; see Type and titles. - A layer hidden behind another. The render reply and
sceneboth list layers from the bottom up. If a title comes before the footage in that list, the footage is covering it, which happens when footage is placed after the title. Move the title's track up withmoveTrack; see Footage, images and the library. - An animation that happens somewhere else. Keyframe times are measured from the layer's own start, not the timeline's, so a key written at a timeline time lands later than meant by the layer's start, often after the layer has gone. Render a strip across the layer with
"count"and"layerId". If nothing changes from frame to frame, the move didn't happen where you meant it. - A caption above or over a face. Ordinary speech captions stay below the face; headroom belongs to hooks and graphics. Inspect the longest phrase, its entrance, the biggest face move and closest crop. Compare its full ink bounds with the chin in received frames. A bottom anchor alone is not proof. Shorten or reflow the phrase, reduce travel or make a lower band, then render again; never solve this by moving it above the face.
- Footage that didn't draw. A note saying a layer had no pixels means the frame is missing that layer. Check the asset with
ymotion_media {"action":"describe","id":"<upload id>"}. - A box that cannot be measured. If a face is still missing after the server tries to load it,
boxsays it isnot_observable. Supply that face or use the picture to inspect the visible fallback, keeping its fidelity caveat in mind. - Levels in the waveform. Read the measured LUFS and speech margin, alongside the lanes. A speech margin under 6 LU is a concern and under 0 LU means the rest measures louder than speech; neither number means anyone listened. Music 12 to 18 dB below speech is a useful starting gain, then check the measured result and have the person listen.
setLevelchanges a layer's gain in decibels; see Sound, music and sound effects. - Caption times from a transcript. They're measured from the start of the file. At forward constant positive speed, a word is at the footage layer's
startplus (word time −trimIn) ÷speed.rate; ramps, rate keys, reverse and holds need the source-clock mapping instead, which captions withsourceuse. In the constant-rate formula, leaving out the start or the trim puts every caption on the wrong words. See What an upload says.