Screenshots and demos, rendered from a script.
render captures a page in a warm browser, composes the background and frame, and encodes once. Each video follows a script of beats, and each beat pairs a line of narration with the steps to perform. The narration is spoken by text-to-speech on the node, with word-timed captions.
- API
- /v1/render
- CLI
- b3os screenshot · b3os video
- MCP tools
- render_*
[01/03] What it does
Styled screenshots
Background and browser-frame presets, a viewport or a single element, at 1x or 2x. JPEG, WebP or PNG.
POST /v1/render/screenshots
Scripted videos
Each beat pairs a line of narration with steps: click, type, scroll, wait. Capture runs on a virtual clock, so the same script gives the same frames.
POST /v1/render/videos
Narration and captions
Kokoro text-to-speech on the node's GPU with word timings. Captions burn into the video or ship as WebVTT and SRT files.
/v1/infer/audio/speech
Restyle without re-recording
Change the background, frame, captions or cursor of a finished video from its saved capture.
POST /v1/render/videos/{id}/restyle
Outputs
MP4 (H.264, 60 fps), GIF, a poster frame and caption files, at signed URLs on usercontent.b3os.org.
GET /v1/render/artifacts/{id}
Left: the raw capture. Right: the same capture with a background and browser frame applied in compose. Illustration, not a real render.
curl -sS -X POST https://beta-api.b3os.org/v1/render/screenshots \
-H "Authorization: Bearer $B3OS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","viewport":{"width":1600,"height":900},"style":{"background":"midnight","frame":"browser-dark"},"format":"webp"}' \
-D - # print response headers, including Server-Timingconst res = await fetch("https://beta-api.b3os.org/v1/render/screenshots", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.B3OS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com",
viewport: { width: 1600, height: 900 },
style: { background: "midnight", frame: "browser-dark" },
format: "webp",
}),
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const data = await res.json();
console.log(res.headers.get("server-timing"));import os
import httpx
res = httpx.post(
"https://beta-api.b3os.org/v1/render/screenshots",
headers={"Authorization": f"Bearer {os.environ['B3OS_API_KEY']}"},
json={
"url": "https://example.com",
"viewport": {"width": 1600, "height": 900},
"style": {"background": "midnight", "frame": "browser-dark"},
"format": "webp",
},
timeout=65,
)
res.raise_for_status()
data = res.json()
print(res.headers.get("server-timing")){
"name": "render_screenshot",
"arguments": {
"url": "https://example.com",
"format": "webp",
"width": 1600,
"height": 900,
"background": "midnight",
"frame": "browser-dark"
}
}- Style strings are escaped before they reach any HTML or CSS, and the browsers that compose frames never load a profile or reach the network.
- Artifacts are kept for 7 days by default.
[02/03] Measured
What we measure for render
Values appear here only from published benchmark runs, each with its raw data. A row that says measuring has no published run yet.
Styled screenshot
1600×900 at DPR 1, JPEG or WebP, quiet window included, server side.
Styled screenshot at DPR 2
The same capture at device pixel ratio 2.
Each extra variant
Time each additional encoding of the same capture adds.
10-second scripted demo
From request to finished MP4 on a HAR-cached app. The first recording pass is reported separately.
30-second narrated demo
With text-to-speech on the GPU slice; a CPU text-to-speech row is separate.
Encode throughput
Frames encoded per second across concurrent jobs, x264 veryfast CRF 20, on a named content mix within render's CPU budget.
screenshot total, PNG with a transparent background
video job total on the first (recording) pass, no HAR cache yet
narrated video job total, 30 s output, TTS on CPU
[03/03] Beta limits
Free during the beta, with caps
Caps per organization
- Renders at once
- 2
Metered units
- Screenshots
- render.screenshot
- Video output
- render.video_s