app
Adom Bridge
Public Made by Adomby adom
Adom Bridge unleashes your AI onto your full PC: full power, full safety. The AI breaks out of the container it runs in and onto your real machine, managing and running your entire laptop as you: launch apps, move files, drive any window, control KiCad, Fusion 360 or your real signed-in browser. Works with any AI, cloud or local (Claude Desktop, Claude Code, Codex), no Hydrogen required. Bridge and its bridges are an operating system for AI, with managed Node and Python runtimes, and a human-onl
← Commit history
docs/recording: how a take spends its bits (recording.md)
1 file changed
+255−133
docs/recording.md+255−133@@ -1,133 +1,255 @@-# Screen recording in Adom Bridge (H.264 / H.265)--Adom Bridge records your screen, a whole monitor or a single window, to an-**MP4** file, on your machine, with the system audio mixed in. It is native:-Windows Graphics Capture for the pixels and Media Foundation for the encode,-with a **hardware encoder** (NVENC / Quick Sync / AMD) doing the work and the-frames staying on the GPU end to end, for both codecs. No browser, no screenshot-loop, no extra capture app.--## It can never record you silently--While a take is running, a **4 pixel teal dot** sits in the corner of your-screen, out of the way of whatever you are recording. It is deliberately tiny-and deliberately still: recordings often get sped up 10x afterwards, and-anything that moves looks wrong at 10x. Starting a desktop recording also forces-the AI to confirm it means the *whole desktop* and not just one window. The clip-is a normal MP4 you keep; Adom Bridge prunes its own recordings folder (oldest-first) so it never fills your disk, and never touches a clip that is still being-written.--If you want the Adom orbital on screen for its own sake, that is a separate-verb: `desktop_orbital {"action":"show","size":220,"corner":"top-left"}` puts-the real Orbital Lab animation up as a transparent, click-through overlay, the-same single-file WebGL loader Hydrogen shows while it installs. It has nothing-to do with recording.--## The verbs--| Verb | What it does |-|---|---|-| `desktop_record_start` | Start a take. `{monitor}` (or `"primary"`) for a screen; `{hwnd}` / `{titleContains}` for one window. Optional `fps` (default 30), `codec` (`h264` default, `h265`), `bitrate` (bits/s), `audio` (default on for a monitor). |-| `desktop_record_stop` | Stop and finalise. Answers within its budget; if the encoder is still closing the file it reports `state:"finalising"` and you poll status, so the take is never dropped. |-| `desktop_record_status` | Live state: `capturedFrames`, `captureFps`, `bytes`, `droppedFrames`, `framePath`, `state`. |-| `desktop_record_list` | Finished clips on disk. |-| `desktop_record_encoders` | Which codecs this machine can hardware-encode. |-| `desktop_orbital` | The Orbital Lab overlay, unrelated to recording. |--**`captureFps` is the honest number.** Windows Graphics Capture only hands over-a frame when the desktop actually changed, so the capture source, not the-encoder, sets the real framerate. Ask for `fps: 60` and you get it if the screen-is doing something; ask for 30 and 30 is your ceiling no matter how fast the-machine is.--## H.264 vs H.265: see it and size it--Ask the machine what it has:--```-desktop_record_encoders--> { codecs: {- h264: { available:true, hardware:true, encoders:[{name:"NVIDIA H.264 Encoder MFT", hardware:true}, ...] },- h265: { available:true, hardware:true, encoders:[{name:"NVIDIA HEVC Encoder MFT", hardware:true}, ...] } },- default:"h264" }-```--- **H.264** is the default, encodes at **High** profile, and plays everywhere.-- **H.265 (HEVC)** reaches the same picture for fewer bits. Halve the `bitrate`- against H.264 and you get a file about half the size that still holds up. It- needs a reasonably modern player.--### Four takes of the same scene--Adom Bridge recorded the **Orbital Lab** (a live Babylon.js 3D hydrogen-orbital-animation, spinning the whole time) in a browser window sized to exactly 80% of-the screen, capturing the **full screen** on an idle test PC with an NVIDIA GPU.-Same scene, 20 seconds, at 60 fps, at two resolutions and in both codecs.--Both codecs were given the **same bitrate** at each resolution. That is the fair-comparison: it shows what each one does with an identical budget, rather than-flattering one of them. Every number is from `ffprobe` on the finished file, and-**no take dropped a single frame**.--| Clip | Resolution | Codec | Bitrate asked for | File size | Bitrate measured | Framerate |-|---|---|---|---|---|---|---|-| 1 | 1080p | H.264 High | 8 Mbps | 18.6 MB | 7.44 Mbps | 55.1 fps |-| 2 | 1080p | **H.265 Main** | 8 Mbps | **17.4 MB** | 6.97 Mbps | 55.2 fps |-| 3 | 1440p | H.264 High | 14 Mbps | 32.5 MB | 12.98 Mbps | 54.9 fps |-| 4 | 1440p | **H.265 Main** | 14 Mbps | **30.4 MB** | 12.15 Mbps | 55.0 fps |--Given the same budget, H.265 comes in a little smaller and spends its bits more-efficiently on the picture. The bigger win is the one this table does not show:-ask H.265 for half the bitrate and you get roughly half the file for a-comparable image. Both codecs ran on the GPU zero-copy path here, and both-captured about 55 real frames per second.--#### Clip 1 of 4 - 1080p, H.264 High - 18.6 MB at 7.44 Mbps, 55.1 fps--<video src="docs/recording/orbital-1080p-h264.mp4" controls muted loop playsinline width="720"></video>--#### Clip 2 of 4 - 1080p, H.265 Main - 17.4 MB at 6.97 Mbps, 55.2 fps--<video src="docs/recording/orbital-1080p-h265.mp4" controls muted loop playsinline width="720"></video>--#### Clip 3 of 4 - 1440p, H.264 High - 32.5 MB at 12.98 Mbps, 54.9 fps--<video src="docs/recording/orbital-1440p-h264.mp4" controls muted loop playsinline width="720"></video>--#### Clip 4 of 4 - 1440p, H.265 Main - 30.4 MB at 12.15 Mbps, 55.0 fps--<video src="docs/recording/orbital-1440p-h265.mp4" controls muted loop playsinline width="720"></video>--If your Markdown viewer does not play inline video, the four files are on this-page under `docs/recording/`.--## Examples--```bash-# Record the primary monitor with system audio, H.264 (default)-desktop_record_start '{"monitor":"primary","audio":true,"reason":"capturing the export walkthrough"}'-desktop_record_stop '{}'--# 60 fps, H.265 at half the bitrate for roughly half the file-desktop_record_start '{"monitor":"primary","codec":"h265","fps":60,"bitrate":7000000,"reason":"..."}'--# Record one window in the background, no audio-desktop_record_start '{"titleContains":"KiCad","codec":"h265","bitrate":6000000,"reason":"..."}'-```--## Under the hood--- **GPU zero-copy, both codecs:** the captured frame goes WGC surface, then a- pooled GPU texture, then the hardware encoder through a shared Direct3D- device. No copy to system memory. `desktop_record_status` reports `framePath`- so you can see which path a take actually took.-- **H.265 path:** the hardware HEVC encoder wants NV12, so Adom Bridge runs a- Direct3D VideoProcessor to convert each frame on the GPU, and writes HEVC into- a standard MP4 (`hvc1`) alongside an AAC audio track.-- **Full colour range** is preserved end to end, so smooth shading on a dark- scene does not band.-- **Timestamps track a wall clock shared with the audio**, so a long screen and- audio recording stays in sync and finalises quickly instead of stalling. A- tick with no new frame behind it is skipped rather than re-encoded, so the- framerate in the file is the framerate that was captured.+# Screen recording in Adom Bridge (H.264 / H.265) + +Adom Bridge records your screen, a whole monitor or a single window, to an +**MP4** file, on your machine, with the system audio mixed in. It is native: +Windows Graphics Capture for the pixels and Media Foundation for the encode, +with a **hardware encoder** (NVENC / Quick Sync / AMD) doing the work and the +frames staying on the GPU end to end, for both codecs. No browser, no screenshot +loop, no extra capture app. + +## It can never record you silently + +While a take is running, a **4 pixel teal dot** sits in the corner of your +screen, out of the way of whatever you are recording. It is deliberately tiny +and deliberately still: recordings often get sped up 10x afterwards, and +anything that moves looks wrong at 10x. Starting a desktop recording also forces +the AI to confirm it means the *whole desktop* and not just one window. The clip +is a normal MP4 you keep; Adom Bridge prunes its own recordings folder (oldest +first) so it never fills your disk, and never touches a clip that is still being +written. + +If you want the Adom orbital on screen for its own sake, that is a separate +verb: `desktop_orbital {"action":"show","size":220,"corner":"top-left"}` puts +the real Orbital Lab animation up as a transparent, click-through overlay, the +same single-file WebGL loader Hydrogen shows while it installs. It has nothing +to do with recording. + +## How a take spends its bits (and why the defaults are what they are) + +Most AIs will never pick an encoder option; they call `desktop_record_start` +with a monitor and a reason and take what they get. So the defaults are the +product, and they were chosen against two opposite jobs the same recorder has +to do well: + +1. **A long take where almost nothing happens.** Someone records a 40-minute + session and the screen is a document or a terminal for most of it. The file + must stay small and the video must still be the right length. +2. **A burst of fast motion.** A video plays, a page scrolls, a 3D model spins. + The picture must stay sharp; a smeared, blocky recording of the one moment + that mattered is worse than no recording. + +### Where the frames come from + +Windows Graphics Capture does not deliver 30 frames a second. It delivers a +frame **when the screen changes**, and nothing at all while it does not. A +still screen therefore yields a handful of frames per minute, and a fast scene +yields the full rate you asked for (30 by default, up to 60). Adom Bridge +records exactly what arrives: it never pads a still screen with duplicate +frames (one held frame every 2 seconds is re-written so any player can seek +into a long pause, and that is all). + +That alone keeps still takes tiny. It also used to make them *short*: the MP4 +writer inside Media Foundation gives the last frame of every 2-second fragment +a fixed length whatever the real gap was, so a 22-second still take played as +18 seconds. Since 2.1.125 the recorder stamps every frame on the take's wall +clock and, after the file is closed, rewrites the container's frame timings +from those stamps. The encoded length now matches the wall clock to within a +few milliseconds for still, moving and mixed content alike; the stop and status +replies report it as `timeline: {repaired, fragments, samples, endBeforeMs, +endAfterMs}`. + +### What the encoder is allowed to spend + +The other half is rate control, and the default changed in 2.1.128. The old +default was a fixed bit-rate cap of about a tenth of a bit per pixel per frame +(11 Mbit/s at 1440p). A still screen never came near it, so it looked free; a +fast scene slammed into it and the encoder smeared. Three modes exist now: + +| Mode | How you get it | What it does | When to use it | +|---|---|---|---| +| **VBR** (default) | say nothing | Peak-constrained variable bit rate: a generous **mean** (3x the old cap, about 33 Mbit/s at 1440p30, 72 at 4K) and a **peak** of twice that. The encoder spends almost nothing on a still screen and up to the peak on motion. | Every ordinary take. It is what you get when you do not think about it, and it is tuned so you do not have to. | +| **CBR** | `bitrate` in bits/s | Constant bit rate at exactly that number. | A hard cap: a slow disk, a known upload budget, a file that must not exceed a size. Expect fast motion to soften at low rates. | +| **Constant quality** | `quality` 1..100 | The encoder holds a picture quality and spends whatever it needs. | Only on content you know. The NVIDIA encoder honours **no cap** in this mode: a noise field at quality 75 wrote 185 Mbit/s with a 20 Mbit/s cap set. Opt-in for that reason. | + +`maxBitrate` (bits/s) moves the VBR peak; `codec:"h265"` halves the file for the +same picture where a modern player is fine (next section). The start reply and +`desktop_record_status` carry `rateControl` (`vbr` | `cbr` | `quality`) so you +can see which mode a take actually ran in, and `desktop_disk_free` tells you +how much room the recordings drive has before you start a long one. + +### Five takes that show it + +All recorded by the released 2.1.128 on an idle 1440p test PC (NVIDIA H.264 +encoder, 30 fps, no audio, full screen, synthetic pages). Every number is from +`ffprobe` on the finished file; `wall` is the take's own clock, `encoded` is +the file's duration. Watch the still one to the end: it is 7 frames and plays +for 9.5 seconds. + +| Take | What is on screen | Mode | Wall | Encoded | Frames | File | Bit rate | +|---|---|---|---|---|---|---|---| +| 1 | a still page, nothing changes | VBR (default) | 9.51 s | 9.51 s | 7 | **0.20 MB** | 0.17 Mbit/s | +| 2 | a full-screen canvas animation (40 bouncing discs, moving text) | VBR (default) | 9.44 s | 9.45 s | 265 | 26.4 MB | 22.3 Mbit/s | +| 3 | worst case: dense scrolling text over a moving noise field | VBR (default) | 9.48 s | 9.49 s | 265 | 36.2 MB | 30.6 Mbit/s | +| 4 | the same worst case | CBR 11 Mbit/s (the old default) | 9.50 s | 9.50 s | 266 | 16.5 MB | 13.8 Mbit/s | +| 5 | still page 4 s, then the animation 7 s, then still again | VBR (default) | 15.63 s | 15.63 s | 200 | 23.7 MB | 12.1 Mbit/s | + +Take 1 is the long-recording case: the file costs nothing while the screen is +still, and the length is right. Take 2 is ordinary motion, where the default +spends about twice what the old cap allowed and the discs keep clean edges. +Takes 3 and 4 are the same 9 seconds of the nastiest content a screen can show, +recorded with the new default and with the old one; the crop below is the same +frame from each. Take 5 is what real sessions look like: the frame count and +the bit rate follow the motion, and nothing is lost in the still parts. + + + +#### Take 1 - still page, 7 frames, 0.20 MB, plays 9.5 s + +<video src="docs/recording/still-default.mp4" controls muted loop playsinline width="720"></video> + +#### Take 2 - canvas animation, default VBR, 26.4 MB at 22.3 Mbit/s + +<video src="docs/recording/moving-default.mp4" controls muted loop playsinline width="720"></video> + +#### Take 3 - stress page, default VBR, 36.2 MB at 30.6 Mbit/s + +<video src="docs/recording/stress-default.mp4" controls muted loop playsinline width="720"></video> + +#### Take 4 - stress page, CBR 11 Mbit/s (the old default), 16.5 MB + +<video src="docs/recording/stress-cbr11.mp4" controls muted loop playsinline width="720"></video> + +#### Take 5 - still, then motion, then still; default VBR, 23.7 MB + +<video src="docs/recording/mixed-default.mp4" controls muted loop playsinline width="720"></video> + +### If you do want to choose + +```bash +# The default: say nothing. VBR, exact length, small when still, sharp when moving. +desktop_record_start '{"monitor":"primary","reason":"recording the export walkthrough"}' + +# A hard cap for a slow disk or a size limit (constant bit rate, 8 Mbit/s) +desktop_record_start '{"monitor":"primary","bitrate":8000000,"reason":"..."}' + +# Raise the VBR peak for a 4K box that plays video (bits/s) +desktop_record_start '{"monitor":"primary","maxBitrate":200000000,"reason":"..."}' + +# Constant quality, opt-in, only on content you know will not be a video or noise +desktop_record_start '{"titleContains":"KiCad","quality":80,"reason":"..."}' + +# Same picture, about half the file, needs a modern player +desktop_record_start '{"monitor":"primary","codec":"h265","reason":"..."}' +``` + +## The verbs + +| Verb | What it does | +|---|---| +| `desktop_record_start` | Start a take. `{monitor}` (or `"primary"`) for a screen; `{hwnd}` / `{titleContains}` for one window. Optional `fps` (default 30), `codec` (`h264` default, `h265`), `bitrate` (bits/s, switches to CBR), `maxBitrate` (the VBR peak), `quality` (1..100, constant quality), `audio` (default on for a monitor). | +| `desktop_record_stop` | Stop and finalise. Answers within its budget; if the encoder is still closing the file it reports `state:"finalising"` and you poll status, so the take is never dropped. | +| `desktop_record_status` | Live state: `capturedFrames`, `captureFps`, `bytes`, `droppedFrames`, `framePath`, `state`. | +| `desktop_record_list` | Finished clips on disk. | +| `desktop_record_encoders` | Which codecs this machine can hardware-encode. | +| `desktop_disk_free` | Free space on the recordings drive (or any path), ungated, so a long take can be refused before it fills the disk. | +| `desktop_orbital` | The Orbital Lab overlay, unrelated to recording. | + +**`captureFps` is the honest number.** Windows Graphics Capture only hands over +a frame when the desktop actually changed, so the capture source, not the +encoder, sets the real framerate. Ask for `fps: 60` and you get it if the screen +is doing something; ask for 30 and 30 is your ceiling no matter how fast the +machine is. + +## H.264 vs H.265: see it and size it + +Ask the machine what it has: + +``` +desktop_record_encoders +-> { codecs: { + h264: { available:true, hardware:true, encoders:[{name:"NVIDIA H.264 Encoder MFT", hardware:true}, ...] }, + h265: { available:true, hardware:true, encoders:[{name:"NVIDIA HEVC Encoder MFT", hardware:true}, ...] } }, + default:"h264" } +``` + +- **H.264** is the default, encodes at **High** profile, and plays everywhere. +- **H.265 (HEVC)** reaches the same picture for fewer bits. Halve the `bitrate` + against H.264 and you get a file about half the size that still holds up. It + needs a reasonably modern player. + +### Four takes of the same scene + +Adom Bridge recorded the **Orbital Lab** (a live Babylon.js 3D hydrogen-orbital +animation, spinning the whole time) in a browser window sized to exactly 80% of +the screen, capturing the **full screen** on an idle test PC with an NVIDIA GPU. +Same scene, 20 seconds, at 60 fps, at two resolutions and in both codecs. + +Both codecs were given the **same bitrate** at each resolution. That is the fair +comparison: it shows what each one does with an identical budget, rather than +flattering one of them. Every number is from `ffprobe` on the finished file, and +**no take dropped a single frame**. + +| Clip | Resolution | Codec | Bitrate asked for | File size | Bitrate measured | Framerate | +|---|---|---|---|---|---|---| +| 1 | 1080p | H.264 High | 8 Mbps | 18.6 MB | 7.44 Mbps | 55.1 fps | +| 2 | 1080p | **H.265 Main** | 8 Mbps | **17.4 MB** | 6.97 Mbps | 55.2 fps | +| 3 | 1440p | H.264 High | 14 Mbps | 32.5 MB | 12.98 Mbps | 54.9 fps | +| 4 | 1440p | **H.265 Main** | 14 Mbps | **30.4 MB** | 12.15 Mbps | 55.0 fps | + +Given the same budget, H.265 comes in a little smaller and spends its bits more +efficiently on the picture. The bigger win is the one this table does not show: +ask H.265 for half the bitrate and you get roughly half the file for a +comparable image. Both codecs ran on the GPU zero-copy path here, and both +captured about 55 real frames per second. + +#### Clip 1 of 4 - 1080p, H.264 High - 18.6 MB at 7.44 Mbps, 55.1 fps + +<video src="docs/recording/orbital-1080p-h264.mp4" controls muted loop playsinline width="720"></video> + +#### Clip 2 of 4 - 1080p, H.265 Main - 17.4 MB at 6.97 Mbps, 55.2 fps + +<video src="docs/recording/orbital-1080p-h265.mp4" controls muted loop playsinline width="720"></video> + +#### Clip 3 of 4 - 1440p, H.264 High - 32.5 MB at 12.98 Mbps, 54.9 fps + +<video src="docs/recording/orbital-1440p-h264.mp4" controls muted loop playsinline width="720"></video> + +#### Clip 4 of 4 - 1440p, H.265 Main - 30.4 MB at 12.15 Mbps, 55.0 fps + +<video src="docs/recording/orbital-1440p-h265.mp4" controls muted loop playsinline width="720"></video> + +If your Markdown viewer does not play inline video, the four files are on this +page under `docs/recording/`. + +## Examples + +```bash +# Record the primary monitor with system audio, H.264 (default) +desktop_record_start '{"monitor":"primary","audio":true,"reason":"capturing the export walkthrough"}' +desktop_record_stop '{}' + +# 60 fps, H.265 at half the bitrate for roughly half the file +desktop_record_start '{"monitor":"primary","codec":"h265","fps":60,"bitrate":7000000,"reason":"..."}' + +# Record one window in the background, no audio +desktop_record_start '{"titleContains":"KiCad","codec":"h265","bitrate":6000000,"reason":"..."}' +``` + +## Under the hood + +- **GPU zero-copy, both codecs:** the captured frame goes WGC surface, then a + pooled GPU texture, then the hardware encoder through a shared Direct3D + device. No copy to system memory. `desktop_record_status` reports `framePath` + so you can see which path a take actually took. +- **H.265 path:** the hardware HEVC encoder wants NV12, so Adom Bridge runs a + Direct3D VideoProcessor to convert each frame on the GPU, and writes HEVC into + a standard MP4 (`hvc1`) alongside an AAC audio track. +- **Full colour range** is preserved end to end, so smooth shading on a dark + scene does not band. +- **Timestamps track a wall clock shared with the audio**, so a long screen and + audio recording stays in sync and finalises quickly instead of stalling. A + tick with no new frame behind it is skipped rather than re-encoded, so the + framerate in the file is the framerate that was captured. +- **The container's frame timings are rewritten from those stamps** after the + file closes (2.1.125), because the fragmented-MP4 writer would otherwise give + the last frame of every fragment a fixed length and shorten still passages.