Read one clip: its elements (positions/sizes in canvas pixels), voiceover (text, voice, duration, voiceover_volume), background and transition. Pass `render` to also get a PNG of the frame.
ASK FOR WHAT YOU NEED. A full read is large — on a dense clip the per-word voiceover array and the element type_data blobs dominate it, and repeated full reads are the main way a long session runs out of context. `select` returns exactly the parts you name:
select: ['elements.x','elements.y','elements.width','elements.height'] → geometry only, to fix a layout
select: ['elements.name','elements.start_time','elements.end_time'] → a timing pass
select: ['words'] → word timings only, to sync visuals to narration
select: ['elements.textdata','words'] → rewrite copy against the VO
select: ['elements'] → whole element rows, no words
select: [] → no JSON at all (pair with render for the PNG alone — smallest read)
(omit select) → everything; fine for a first look, expensive to repeat
`render` is the other output, and it is separate from `select`: `select` shapes the JSON, `render` produces a PNG.
render: {} → the frame at t=0
render: { timestamp: 2.5 } → the frame 2.5s into the clip
render: { save: true } → also uploads the PNG and returns presigned_url
select: [], render: {} → the PNG alone, no JSON
select: ['elements'], render: {} → element rows AND the frame
Omitting `render` renders nothing. `timestamp` and `save` live inside it because they only mean anything for a render — there is no way to ask for them without asking for the image.
`element_ids` is the other axis: it picks WHICH element rows come back, independently of `select`. Combine them for the leanest read — e.g. element_ids: ['el_9'], select: ['elements.x','elements.y'].
Element shape: universal wrapper fields (id, geo, name, x, y, width, height, start_time, end_time, rotation) plus type-specific data (textdata/shapedata/imagedata/videodata/zoomdata) plus an optional `keyframes` array when animated. Keyframes come back in the same flat wire shape add_elements takes — { timestamp, positionX?, positionY?, width?, height?, interpolation? } in canvas pixels — so you can round-trip read → edit → update_elements without reshaping.
Clip-level fields include `transition` (the current transition object — sibling of the update_clips `transition` arg; null if none) and `voiceover_words` (per-word timestamps; null on clips with no transcription).