> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beta.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Styles and captions

The style presets and overrides that frame screenshots and videos, the colors they take, and how render times and draws word-level captions.

Screenshots, videos and restyles take the same `style` object: one preset for each of five parts, plus `overrides` for anything a preset does not set.

```json
{
  "style": {
    "background": "midnight",
    "frame": "browser-dark",
    "cursor": "arrow",
    "captions": "default",
    "click_effect": "ripple",
    "overrides": { "padding": 48, "corner_radius": 16, "shadow": "float" }
  }
}
```

Every field is optional. A screenshot request without `style` is a plain screenshot: the capture as the page painted it. A `style` object, even `{}`, gets the B3OS look for whatever it leaves out: an `auto` background, no frame, padding 64, corner radius 12 and a soft shadow.

## Presets

`GET /v1/render/presets` lists every preset with a preview image, and `?kind=background` narrows it to one kind. A `style` that leaves a part out gets `auto` for the background, `none` for the frame, `arrow` for the cursor, `default` for captions and `ripple` for the click effect. Preset IDs are unique across kinds, so a frame name never works as a cursor.

| Part | Presets, each linked to its preview |
|---|---|
| `background` | [`b3os-light`](https://beta.b3os.org/assets/presets/b3os-light.webp), [`b3os-dark`](https://beta.b3os.org/assets/presets/b3os-dark.webp), [`b3os-blue`](https://beta.b3os.org/assets/presets/b3os-blue.webp), [`midnight`](https://beta.b3os.org/assets/presets/midnight.webp), [`aurora`](https://beta.b3os.org/assets/presets/aurora.webp), [`sunset`](https://beta.b3os.org/assets/presets/sunset.webp), [`ocean`](https://beta.b3os.org/assets/presets/ocean.webp), [`arctic`](https://beta.b3os.org/assets/presets/arctic.webp), [`dusk`](https://beta.b3os.org/assets/presets/dusk.webp), [`forest`](https://beta.b3os.org/assets/presets/forest.webp), [`ember`](https://beta.b3os.org/assets/presets/ember.webp), [`graphite`](https://beta.b3os.org/assets/presets/graphite.webp), [`paper`](https://beta.b3os.org/assets/presets/paper.webp) |
| `frame` | [`mac`](https://beta.b3os.org/assets/presets/mac.webp), [`mac-dark`](https://beta.b3os.org/assets/presets/mac-dark.webp), [`browser`](https://beta.b3os.org/assets/presets/browser.webp), [`browser-dark`](https://beta.b3os.org/assets/presets/browser-dark.webp), [`windows`](https://beta.b3os.org/assets/presets/windows.webp), [`windows-dark`](https://beta.b3os.org/assets/presets/windows-dark.webp), [`phone`](https://beta.b3os.org/assets/presets/phone.webp), [`tablet`](https://beta.b3os.org/assets/presets/tablet.webp) |
| `cursor` | [`arrow`](https://beta.b3os.org/assets/presets/arrow.webp), [`arrow-light`](https://beta.b3os.org/assets/presets/arrow-light.webp), [`dot`](https://beta.b3os.org/assets/presets/dot.webp) |
| `captions` | [`default`](https://beta.b3os.org/assets/presets/default.webp), [`bold`](https://beta.b3os.org/assets/presets/bold.webp), [`minimal`](https://beta.b3os.org/assets/presets/minimal.webp), [`light`](https://beta.b3os.org/assets/presets/light.webp) |
| `click_effect` | [`ripple`](https://beta.b3os.org/assets/presets/ripple.webp), [`ring`](https://beta.b3os.org/assets/presets/ring.webp) |

Three values are not presets and have no preview: `none` (any part: draw nothing, so `captions: "none"` drops burned-in captions on a restyle), and `auto` and `transparent` for `background`. `auto` picks `b3os-light` or `b3os-dark` from how light the page is; `transparent` leaves the background transparent in PNG and WebP output, and JPEG fills it with the `matte` color.

## Overrides

`overrides` is a closed set of keys; anything else is refused. Lengths are CSS pixels, scaled with the capture's device pixel ratio for screenshots and with the output size for videos.

| Key | Value |
|---|---|
| `padding` | A number from 0 to 400, or `{x, y}` |
| `corner_radius` | 0 to 64 |
| `shadow` | `none`, `soft`, `float`, `hard` or `glow`; or `{x, y, blur, spread, color}`; or a list of up to 4 of those |
| `border` | `none`, or `{width, color}` with a width from 0 to 16; by default a hairline matched to the background |
| `background_color` | A color, for a solid background |
| `background_gradient` | `{angle, stops}` for a linear gradient, or `{kind: "radial", stops}`; stops are colors or `{color, at}` |
| `aspect_ratio` | `auto`, `16:9`, `16:10`, `4:3`, `3:2`, `1:1`, `4:5`, `3:4`, `9:16` or `21:9`; a screenshot's canvas grows to it |
| `canvas` | `{width, height}`, a fixed screenshot size from 16 to 7680 a side; the page is fitted by `fit` |
| `fit` | `contain` (the default) or `cover`, which fills the width and crops the bottom |
| `frame_title`, `frame_url` | Text for the window's title bar and address pill, up to 200 characters, drawn by the compositor and never parsed as HTML |
| `theme` | `light` or `dark`: flips the frame and the `auto` background |
| `cursor_size`, `cursor_zoom` | A scale from 0.5 to 3 (1 by default); `cursor_zoom: false` keeps the cursor's size while the camera zooms |
| `click_color`, `click_duration_ms` | The click effect's color, and how long it lasts: 100 to 2000 ms, 450 ms by default |
| `caption_size`, `caption_color`, `caption_highlight`, `caption_background`, `caption_position` | Caption text size in pixels at 1080p (12 to 120, 44 by default), colors, and `bottom` or `top` |
| `motion_blur` | Smear the cursor while it moves; on by default |
| `matte` | The color behind transparent pixels when the output is JPEG; white by default |

Colors are written `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, `rgb(r,g,b)`, `rgba(r,g,b,a)`, `rgb(r g b / a)`, or the names `white`, `black` and `transparent`.

A style that does not validate is refused with `422` [`style_invalid`](/errors#style_invalid), and `errors[]` lists every problem at once, each with a pointer such as `/style/overrides/padding/x`, so one fix-and-retry covers them all. Style values are drawn by the compositor in Rust and escaped before they reach any HTML or CSS.

## Captions

A video's `captions` decides how the narration appears on screen:

| Field | Meaning |
|---|---|
| `burn_in` | `none` (only the caption files), `static` (draw each cue) or `karaoke` (draw each cue and highlight the word being spoken, held through pauses) |
| `sidecars` | Caption files to produce: `vtt`, `srt` or both |
| `max_chars_per_line`, `max_lines`, `max_chars_per_second` | Line limits: 42 characters, 2 lines and 20 characters per second by default |

The timing comes from the speech model's word timestamps, so each cue starts on its first word. Cues follow the usual subtitle rules for English: one sentence per cue, at most 7 seconds on screen, a pause of 700 ms or more ends a cue, and a cue that would be read too fast stretches into the silence after it. Lines break after punctuation and before conjunctions and prepositions, never after an article or inside a name, and a two-line cue keeps the longer line at the bottom. The look comes from the `captions` preset and the `caption_*` overrides.

Restyling a video can change the caption preset, the overrides and the line limits without recording again; see [restyle a video](/render/videos#restyle-a-video).

## Voices

Narration uses the node's speech model. `GET /v1/infer/audio/voices` lists the voices, each with a `sample_url` you can play before you choose; see [speech](/infer/speech).