Get a video's timeline
Returns the compiled timeline of a video that has finished planning: beats, narration with word timings, the timed action list the recorder replayed, cursor path, camera keyframes, captions and style (`timeline.schema.json`). `frames=1` adds the per-frame compositor state (large; for debugging).
GET
/v1/render/videos/{video_id}/timeline
Returns the compiled timeline of a video that has finished planning: beats, narration with word timings,
the timed action list the recorder replayed, cursor path, camera keyframes, captions and style
(`timeline.schema.json`). `frames=1` adds the per-frame compositor state (large; for debugging).
Authentication
Bearer Token (b3os_sk_ API key or b3os_pat_ token) API Key (cookie: __Host-b3os_session)
Path Parameters
video_id
string
required
path
The video ID (`vid_…`).
Example:
"vid_01m5t4c5ep9bdfhtx7nk2k3vq7"Query Parameters
frames
boolean
optional
query
Include the per-output-frame state.
Responses
200
The timeline.
application/json$schema
string (uri)
version
unknown
REQUIRED
Enum:
1job
string
duration_us
integer
REQUIRED
Length of the video. Output frame i exists for every i with round(i * 1e6 / output.fps) < duration_us.
viewport
object
REQUIRED
Browser viewport in CSS pixels. Capture runs at device pixel ratio 1; sharp zoom comes from clip.scale at capture time (ARCHITECTURE 5.2).
width
integer
REQUIRED
height
integer
REQUIRED
capture
object
REQUIRED
fps
integer
REQUIRED
Page capture rate. Capture frame seq is taken at virtual time t(seq) = round(seq * 1e6 / fps) us.
format
unknown
Enum:
jpeg, pngquality
integer
JPEG quality passed to Chrome.
backend
unknown
screenshot: Page.captureScreenshot per virtual tick (any OS). beginframe: HeadlessExperimental.beginFrame with screenshot (Linux chrome-headless-shell; reports damage).
Enum:
screenshot, beginframesegments
integer
Number of segments captured in parallel; 1 means serial.
output
object
REQUIRED
Composed video. Output frame index i is presented at t = round(i * 1e6 / fps) us.
width
integer
REQUIRED
height
integer
REQUIRED
fps
unknown
REQUIRED
Enum:
24, 25, 30, 50, 60seed
integer
Seeds Math.random and crypto.getRandomValues in the page and every PRNG in the director, so every segment worker sees the same sequence.
start_time
string (date-time)
Value of Date at t = 0; the page clock then advances with virtual time only.
source
object
url
string (uri)
REQUIRED
profile
string
style
object
References to style presets resolved by b3os-compose. Restyle replaces only this object.
background
string
A preset id known to b3os-compose (GET /v1/render/presets), e.g. midnight, browser-dark, mac, arrow. Ids are unique across kinds; none (any kind) and auto and transparent (background) are values, not presets.
frame
string
A preset id known to b3os-compose (GET /v1/render/presets), e.g. midnight, browser-dark, mac, arrow. Ids are unique across kinds; none (any kind) and auto and transparent (background) are values, not presets.
cursor
string
A preset id known to b3os-compose (GET /v1/render/presets), e.g. midnight, browser-dark, mac, arrow. Ids are unique across kinds; none (any kind) and auto and transparent (background) are values, not presets.
captions
string
A preset id known to b3os-compose (GET /v1/render/presets), e.g. midnight, browser-dark, mac, arrow. Ids are unique across kinds; none (any kind) and auto and transparent (background) are values, not presets.
click_effect
string
A preset id known to b3os-compose (GET /v1/render/presets), e.g. midnight, browser-dark, mac, arrow. Ids are unique across kinds; none (any kind) and auto and transparent (background) are values, not presets.
overrides
object
Style fields that override the presets, validated by b3os-compose against its Style type (NOTES/render-compose.md 1.1): padding, corner_radius, shadow, border, background_color, background_gradient, aspect_ratio, canvas, fit, frame_title, frame_url, theme, cursor_size, cursor_zoom, click_color, click_duration_ms, caption_size, caption_color, caption_highlight, caption_background, caption_position, motion_blur, matte. Unknown keys and bad values are refused with 422 style_invalid.
layout
object
Where the page layer lands in the output frame, computed by b3os-compose from style and output size and recorded for reproducibility.
page
object
REQUIRED
Output space.
x
number
REQUIRED
y
number
REQUIRED
width
number
REQUIRED
height
number
REQUIRED
corner_radius
number
beats
object[]
Narration-sized units of the story: what is said and what happens while it is said.
Array of:
id
string
REQUIRED
title
string
start_us
integer
REQUIRED
Microseconds on the virtual timeline.
end_us
integer
REQUIRED
Microseconds on the virtual timeline.
narration
string
Narration segment spoken during this beat.
actions
string[]
Array of:
string
narration
object | null
Voice-over. Audio is synthesized before capture so actions can be placed on words (ARCHITECTURE 5.2). Word times are absolute on the timeline: segment.start_us + the voice sidecar's start_ms * 1000.
voice
object
REQUIRED
model
string
REQUIRED
voice
string
REQUIRED
speed
number
sample_rate
unknown
REQUIRED
Enum:
16000, 22050, 24000, 44100, 48000gain_db
number
segments
object[]
REQUIRED
Array of:
id
string
REQUIRED
beat
string
text
string
REQUIRED
start_us
integer
REQUIRED
Microseconds on the virtual timeline.
end_us
integer
REQUIRED
Microseconds on the virtual timeline.
audio
object
REQUIRED
Mono PCM s16le at narration.sample_rate, stored by b3os-render (job-relative path or art_ id).
ref
string
REQUIRED
samples
integer
REQUIRED
words
object[]
REQUIRED
Array of:
text
string
REQUIRED
start_us
integer
REQUIRED
Microseconds on the virtual timeline.
end_us
integer
REQUIRED
Microseconds on the virtual timeline.
byte_start
integer
UTF-8 byte offset of the word in its segment text.
byte_end
integer
actions
object[]
REQUIRED
Timed browser actions in at_us order (ties keep array order). The recorder replays exactly this list in the probe pass and in every capture segment. The virtual clock is frozen while navigate and wait actions settle, so their wall time never shows in the video.
Array of:
id
string
REQUIRED
kind
unknown
REQUIRED
Enum:
navigate, click, hover, type, key, scroll, select, waitat_us
integer
REQUIRED
When the action starts.
beat
string
target
unknown | unknown | unknown
What an action acts on. Resolution (littledemo targeting): candidates matching selector, text (visible text, case-insensitive substring unless exact), or role plus accessible name, limited to within; the best-scored candidate wins, or the nth match when nth is set. A target that is still outside the viewport after scrolling it into view fails the action with target_not_found.
Any of:
Option 1unknown
Option 2unknown
Option 3unknown
url
string (uri)
wait_until
unknown
Enum:
load, domcontentloaded, networkidlebutton
unknown
Enum:
left, right, middlecount
integer
press_us
integer
click: time between mouse down and mouse up.
modifiers
unknown[]
Array of:
unknown
text
string
interval_us
integer
type: delay between characters; character i (a Unicode scalar value) is inserted at at_us + i * interval_us.
key
string
KeyboardEvent.key, e.g. Enter, Tab, a.
to
object
scroll: document scroll offset to reach.
x
number
REQUIRED
y
number
REQUIRED
by
object
scroll: delta from the current offset.
x
number
REQUIRED
y
number
REQUIRED
duration_us
integer
scroll: animation length on the virtual clock.
easing
unknown | object | object
Easing for the segment that ends at this keyframe; u in [0, 1]. linear: u. ease_in_out_cubic: u < 0.5 ? 4u^3 : 1 - (2 - 2u)^3 / 2. ease_out_quart: 1 - (1 - u)^4. smootherstep: 6u^5 - 15u^4 + 10u^3. hold: 0 until u = 1, then 1. cubic_bezier: CSS cubic-bezier(x1, y1, x2, y2). critically_damped: s(u) / s(1) with s(u) = 1 - (1 + w u) e^(-w u). Default ease_in_out_cubic.
One of:
Option 1unknown
Option 2
cubic_bezier
array
REQUIRED
Option 3
critically_damped
object
REQUIRED
omega
number
REQUIRED
value
string
select: option value.
for
object
wait: the condition. The virtual clock is frozen until it holds.
selector
string
text
string
url
string
Substring the page URL must contain.
network_idle
unknown
Enum:
truetimeout_ms
integer
navigate and wait: wall-clock budget for settling.
observed
object
What the probe pass observed when the action ran; filled by the recorder, read by the director to plan cursor and camera. rect and point are viewport space at at_us.
ok
boolean
REQUIRED
rect
object
x
number
REQUIRED
y
number
REQUIRED
width
number
REQUIRED
height
number
REQUIRED
point
object
x
number
REQUIRED
y
number
REQUIRED
selector
string
A unique selector for the resolved element.
url
string
Page URL after the action.
scroll
object
Document scroll offset after the action.
x
number
REQUIRED
y
number
REQUIRED
settled_us
integer
Virtual time at which a navigate or wait finished.
error
object
code
string
REQUIRED
detail
string
cursor
object
Composited cursor (not drawn in the page). Position is linear between consecutive points; pressed and visible keep their last value until a point changes them. Before the first point and after the last, the nearest point applies.
points
object[]
REQUIRED
Array of:
t_us
integer
REQUIRED
Microseconds on the virtual timeline.
x
number
REQUIRED
y
number
REQUIRED
pressed
boolean
visible
boolean
camera
object
Camera keyframes. For t between keyframes k-1 and k: u = (t - t[k-1]) / (t[k] - t[k-1]), e = easing[k](u), zoom = zoom[k-1] * (zoom[k] / zoom[k-1])^e, center = center[k-1] + (center[k] - center[k-1]) * e. Before the first keyframe and after the last, the nearest keyframe holds. The camera rect is width = viewport.width / zoom, height = viewport.height / zoom, x = clamp(center.x - width / 2, 0, viewport.width - width), y likewise. Absent: zoom 1 centered.
keyframes
object[]
REQUIRED
Array of:
t_us
integer
REQUIRED
Microseconds on the virtual timeline.
center
object
REQUIRED
x
number
REQUIRED
y
number
REQUIRED
zoom
number
REQUIRED
easing
unknown | object | object
Easing for the segment that ends at this keyframe; u in [0, 1]. linear: u. ease_in_out_cubic: u < 0.5 ? 4u^3 : 1 - (2 - 2u)^3 / 2. ease_out_quart: 1 - (1 - u)^4. smootherstep: 6u^5 - 15u^4 + 10u^3. hold: 0 until u = 1, then 1. cubic_bezier: CSS cubic-bezier(x1, y1, x2, y2). critically_damped: s(u) / s(1) with s(u) = 1 - (1 + w u) e^(-w u). Default ease_in_out_cubic.
One of:
Option 1unknown
Option 2
cubic_bezier
array
REQUIRED
Option 3
critically_damped
object
REQUIRED
omega
number
REQUIRED
captions
object
burn_in
unknown
REQUIRED
none: sidecar files only. static: draw each cue. karaoke: draw each cue and highlight the word being spoken.
Enum:
none, static, karaokesidecars
unknown[]
Array of:
unknown
max_chars_per_line
integer
max_lines
integer
max_chars_per_second
number
cues
object[]
REQUIRED
Array of:
id
string
REQUIRED
start_us
integer
REQUIRED
Microseconds on the virtual timeline.
end_us
integer
REQUIRED
Microseconds on the virtual timeline.
lines
string[]
REQUIRED
Array of:
string
words
object[]
Array of:
text
string
REQUIRED
start_us
integer
REQUIRED
Microseconds on the virtual timeline.
end_us
integer
REQUIRED
Microseconds on the virtual timeline.
line
integer
REQUIRED
byte_start
integer
REQUIRED
byte_end
integer
REQUIRED
capture_plan
object[]
Per capture frame: the viewport region to capture. Sent to the recorder for each segment. Frames not listed are not captured.
Array of:
seq
integer
REQUIRED
camera
object
REQUIRED
x
number
REQUIRED
y
number
REQUIRED
width
number
REQUIRED
height
number
REQUIRED
scale
number
Explicit clip.scale; default derived as above.
frames
object[]
Optional FrameState dump (debugging, tests, GET .../timeline?frames=1).
Array of:
index
integer
REQUIRED
t_us
integer
REQUIRED
Microseconds on the virtual timeline.
page
object
REQUIRED
segment
integer
REQUIRED
seq
integer
REQUIRED
Latest capture frame with t(seq) <= t_us; when it had damage false, the image of the latest earlier frame with damage.
camera
object
REQUIRED
x
number
REQUIRED
y
number
REQUIRED
width
number
REQUIRED
height
number
REQUIRED
camera
object
REQUIRED
x
number
REQUIRED
y
number
REQUIRED
width
number
REQUIRED
height
number
REQUIRED
cursor
object
REQUIRED
x
number
REQUIRED
y
number
REQUIRED
visible
boolean
REQUIRED
pressed
boolean
REQUIRED
effects
object[]
REQUIRED
Array of:
kind
unknown
REQUIRED
Enum:
clickx
number
REQUIRED
y
number
REQUIRED
age_us
integer
REQUIRED
Time since the effect started; the style decides how long it lasts.
caption
object | null
REQUIRED
cue
string
REQUIRED
lines
string[]
REQUIRED
Array of:
string
highlight
object
line
integer
REQUIRED
byte_start
integer
REQUIRED
byte_end
integer
REQUIRED
opacity
number
REQUIRED
Opacity of the window layer (page, frame chrome, shadow, border, cursor, click effects) over the background; the background and the caption stay opaque.
motion
object
Change since the previous output frame, for motion blur: camera center delta and log-zoom delta of the keyframe path (before the viewport clamp, so a camera held at an edge still reports its path), cursor delta (viewport space).
camera_dx
number
camera_dy
number
camera_dlog_zoom
number
cursor_dx
number
cursor_dy
number
400
The request failed validation (`invalid_request`, `invalid_url`).
401
Missing, malformed, expired or revoked credentials (`unauthorized`).
403
Authenticated but not allowed (`forbidden`, `egress_denied`).
404
No such video in this project (`video_not_found`).
409
The video has not finished planning yet (`conflict`).
429
A rate, concurrency or quota limit applies (`rate_limited`, `concurrency_limited`, `quota_exceeded`).
500
Something failed inside B3OS (`internal`). Retry with backoff.
503
The node or the product is not available right now (`node_unavailable`, `product_unavailable`, `capacity_unavailable`).
curl -X GET 'https://beta-api.b3os.org/v1/render/videos/vid_01m5t4c5ep9bdfhtx7nk2k3vq7/timeline' \ -H 'Authorization: Bearer YOUR_API_TOKEN'
const response = await fetch('https://beta-api.b3os.org/v1/render/videos/vid_01m5t4c5ep9bdfhtx7nk2k3vq7/timeline', { method: 'GET', headers: { "Authorization": "Bearer YOUR_API_TOKEN" }});const data = await response.json();console.log(data);
import requestsheaders = { 'Authorization': 'Bearer YOUR_API_TOKEN'}response = requests.get('https://beta-api.b3os.org/v1/render/videos/vid_01m5t4c5ep9bdfhtx7nk2k3vq7/timeline', headers=headers)print(response.json())
200
Response
{ "version": 1, "job": "vid_01m5t4c5ep9bdfhtx7nk2k3vq7", "duration_us": 2000000, "viewport": { "width": 1440, "height": 900 }, "capture": { "fps": 30 }, "output": { "width": 1920, "height": 1080, "fps": 60 }, "source": { "url": "https://app.example.com" }, "actions": [ { "id": "a1", "kind": "click", "at_us": 600000, "target": { "role": "link", "name": "Billing" } } ]}
API Playground
Try this endpoint
GET
/v1/render/videos/{video_id}/timeline