← Commit history

Correct recording doctrine + add dedicated native-browser-recording skill

John Lauer ·2791e030f4 · ·parent a295aba
7 files changed +124−39
README.md+7−3
@@ -115,6 +115,7 @@ to its full readme. | Skill | What it covers | |---|---| | [`driving-the-extension`](https://wiki.adom.inc/john/adom-browser-extension/files/skills/driving-the-extension/SKILL.md) | The full `nbrowser_*` surface: the CDP-vs-native "debugging" bar, `isTrusted` input + xy-finding, multi-profile driving, the credential-library query + login automation, the taskbar status feature. |+| [`native-browser-recording`](https://wiki.adom.inc/john/adom-browser-extension/files/skills/native-browser-recording/SKILL.md) | Full-framerate **background** recording of the user's real, logged-in Chrome — the occlusion-flag mode, the restart-into-background-recording flow, and the offer-to-revert-for-battery step (the unique capability). | | [`driving-the-desktop`](https://wiki.adom.inc/john/adom-browser-extension/files/skills/driving-the-desktop/SKILL.md) | OS-level control via `desktop_*` when CDP can't reach (extension lifecycle, `chrome://` pages, native dialogs, popups) — including the ⛔ never-drive-a-PWA-window guard and the v20 saved-password ban. | | [`driving-the-extension-demo`](https://wiki.adom.inc/john/adom-browser-extension/files/skills/driving-the-extension-demo/SKILL.md) | A runnable demo playbook — recipes + the recording gotchas (window-capture-vs-CDP white pages, the keep-awake guard). | | [`cross-platform-dev`](https://wiki.adom.inc/john/adom-browser-extension/files/skills/cross-platform-dev/SKILL.md) | The Windows-first → Kyle-ports-Mac dev flow for the bridge/host/extension. |@@ -229,9 +230,12 @@ node bridge/server.js ## Recording — full-framerate, in the background (the doctrine)  > **Why this matters — and why we keep relearning it.** Demos must look **amazing**, which means-> **full-resolution, high-framerate (30–60 fps)** capture. That single requirement drives every choice-> here. ⛔ We do **NOT** record via CDP `Page.startScreencast` — it's low-fps JPEG and looks like garbage;-> CDP is for screenshots/driving, never demo video.+> **full-resolution, high-framerate (20–60 fps)** capture. That single requirement drives every choice+> here. **The enemy is *paint-throttling*, not the codec:** Chrome correctly stops painting occluded /+> background / static windows (battery), and capture is event-driven, so a throttled page silently drops to+> ~5 fps ("frozen" / sped-up video). Every technique below keeps frames flowing. *(Pup's `browser_record_start`+> CDP screencast is a perfectly good 20–30 fps engine when the page paints — the full cross-surface reference,+> incl. Hydrogen and the foreground-rebump trick, is in the demo-recording skill's `recording-mechanics.md`.)*  **Background recording needs TWO things, both required:** 1. **A high-fps engine** — `wgc` (60 fps, Windows, picker-free) or `getdisplaymedia` (the WebRTC/Meet
extension/src/record.js+11−9
@@ -1,16 +1,18 @@ // record.js — SW-side control for browser recording (nbrowser_record_*). //-// 🎥 DOCTRINE — why it's built this way (full detail: README "Recording" + driving-the-extension skill):-//   GOAL: demos must look AMAZING → full-res, HIGH FRAMERATE (30–60fps). That drives every choice.-//   ⛔ NEVER record demo video with CDP Page.startScreencast — low-fps jpeg, ugly. CDP = screenshots/driving only.-//   Background capture needs BOTH (1) a high-fps engine AND (2) a browser launched with the occlusion/throttle--//   disable flags (--disable-features=CalculateNativeWinOcclusion --disable-backgrounding-occluded-windows-//   --disable-renderer-backgrounding --disable-background-timer-throttling) so it keeps PAINTING the occluded-//   window. Without them Chrome stops painting occluded windows (its CORRECT battery-saving default) → blank frames.-//     • No login needed  → record via PUP (we launch it already-flagged; full-fps background; real Chrome untouched).+// 🎥 DOCTRINE — why it's built this way (full detail: the native-browser-recording skill + README "Recording"):+//   GOAL: demos must look AMAZING → full-res, HIGH FRAMERATE (20–60fps). The enemy is PAINT-THROTTLING, not the+//   codec: Chrome correctly stops painting occluded/background/static windows (battery) → capture freezes/drops fps.+//   (CDP screencast is NOT garbage — it's pup's browser_record_start engine, 20–30fps when the page paints.)+//   The NATIVE-browser methods here are 'wgc' + 'getdisplaymedia' (real high-fps engines). Background capture of+//   the user's REAL Chrome (the only browser with their logins) needs it to PAINT while occluded — which means+//   launching it with the occlusion/throttle-disable flags (--disable-features=CalculateNativeWinOcclusion+//   --disable-backgrounding-occluded-windows --disable-renderer-backgrounding --disable-background-timer-throttling).+//   Default Chrome lacks them (correctly — battery). So:+//     • No login needed  → record via PUP/Hydrogen (see the demo-recording skill); don't touch the user's Chrome. //     • Login needed      → native Chrome: ASK+WARN, FULLY kill the whole chrome.exe process tree, relaunch with the //       user's profile + the flags, record full-fps in the BACKGROUND, then OFFER TO REVERT later (battery saver).-//   ⛔ NEVER foreground the window to "fix" a blank frame; NEVER leave the flags on globally/forever.+//   ⛔ NEVER foreground the user's real Chrome to fix framerate (use the flags); NEVER leave the flags on forever. // // TWO methods (caller picks via args.method; README has the full pros/cons): //   • 'getdisplaymedia' (desktopCapture) — CROSS-PLATFORM (Mac/Ubuntu/Windows). High-fps (the WebRTC
install.sh+1−1
@@ -3,7 +3,7 @@ # (The extension itself loads into Chrome/Edge via "Load unpacked" from extension/, or the Web Store.) set -e DEST="${HOME}/.claude/skills"-for name in cross-platform-dev driving-the-extension driving-the-extension-demo driving-the-desktop driving-sites driving-gusto; do+for name in cross-platform-dev driving-the-extension native-browser-recording driving-the-extension-demo driving-the-desktop driving-sites driving-gusto reading-google-messages; do   mkdir -p "$DEST/$name"   cp "skills/$name/SKILL.md" "$DEST/$name/SKILL.md"   echo "installed skill: $name"
package.json+1
@@ -15,6 +15,7 @@     "README.md",     "skills/cross-platform-dev/SKILL.md",     "skills/driving-the-extension/SKILL.md",+    "skills/native-browser-recording/SKILL.md",     "skills/driving-the-extension-demo/SKILL.md",     "skills/driving-the-desktop/SKILL.md",     "demo/adom-native-browser-demo.mp4",
skills/driving-the-extension/SKILL.md+31−25
@@ -198,40 +198,46 @@ windows in the background. So: adom-desktop -t AdomLapper desktop_bring_to_front '{"titleContains":"<page title>","state":"restore"}'  # or {hwnd} ``` -## 🎥 Recording doctrine — full-framerate, in the background (READ THIS; we keep relearning it)+## 🎥 Recording doctrine — full-framerate background recording of the NATIVE browser -**The point:** demos must look **amazing** → **full-resolution, high-framerate (30–60 fps)**. That one-requirement drives everything. ⛔ **NEVER record demo video with CDP `Page.startScreencast`** — it's low-fps-JPEG, looks like garbage. CDP is for screenshots/driving only. The real engines are **`wgc`** (60 fps,-Windows, picker-free) and **`getdisplaymedia`** (WebRTC/Meet pipeline, 30–60 fps, cross-platform).+**Goal:** demos must look **amazing** → full-resolution, **high framerate (20–60 fps)**. **The enemy is+PAINT-THROTTLING, not any codec.** Chrome correctly stops painting occluded / background / static windows+(its battery-saving default), and screencast-style capture is event-driven, so a throttled page silently+drops to ~5 fps ("frozen" / sped-up video). Every technique exists to keep frames flowing. *(The full+cross-surface reference — Hydrogen vs pup, the foreground-rebump trick, page-side animation, the keyframe+re-encode — lives in the **demo-recording** skill's `recording-mechanics.md`. CDP screencast is NOT garbage —+it's pup's `browser_record_start` engine and does 20–30 fps when the page paints.)* -**Background capture needs BOTH:** (1) a high-fps engine, AND (2) a browser that keeps **painting the-occluded window** — which needs the launch flags `--disable-features=CalculateNativeWinOcclusion---disable-backgrounding-occluded-windows --disable-renderer-backgrounding --disable-background-timer-throttling`.-Without them Chrome stops painting an occluded window (its **correct, battery-saving default**) and the-engine records blank/frozen frames. The flags are an exception we want **only for the recorded window,-only while recording**, then revert.+**When to use the NATIVE browser (this extension) to record:** only when the demo needs the **user's real+session / cookies / logins** (a logged-in tool). If no login is needed, record via **Hydrogen or pup**+(see demo-recording) and don't touch the user's real Chrome. -**Scenario 1 — no login needed → use `pup`.** Pup is launched by us, already flagged → full-framerate-background recording, the user's real Chrome untouched. **Preferred whenever the app needs no real session.**+**Native-browser recording = `nbrowser_record_start {method:"wgc"|"getdisplaymedia"}`** (the native path+does NOT use CDP screencast — that's pup's). Both are real high-fps engines: **`wgc`** (60 fps, Windows,+picker-free) and **`getdisplaymedia`** (WebRTC/Meet pipeline, 30–60 fps; picker auto-skipped with+`--auto-select-desktop-capture-source` when *we* launch Chrome). -**Scenario 2 — login/session needed → native Chrome (this extension).** Only the user's real Chrome has-their cookies/logins. To record it full-framerate in the background:-1. Check if native Chrome already has the flags.+**The key constraint that makes this different from pup:** you must **NOT foreground-rebump the user's real+working browser** (pup does that on a throwaway window, but on the user's real Chrome it wrecks their work).+Instead, make the real Chrome **paint while occluded** by launching it with the occlusion/throttle-disable+flags `--disable-features=CalculateNativeWinOcclusion --disable-backgrounding-occluded-windows+--disable-renderer-backgrounding --disable-background-timer-throttling`. Default Chrome lacks them (correctly+— battery). So for a logged-in background recording:+1. Check whether native Chrome already runs with the flags. 2. If not → **ASK + WARN the user we must fully restart their Chrome**, then **kill the entire `chrome.exe`-   process tree** (it spawns many helper/background processes — closing the window is NOT enough; the flags-   don't apply until every `chrome.exe` is gone), wait for full shutdown, and **relaunch with their real-   profile** (logins survive; tabs restore) **plus the flags**.-3. Record full-framerate in the background (`wgc`, or `getdisplaymedia` + `--auto-select-desktop-capture-source`)-   while they keep working.-4. **Later OFFER TO REVERT:** "Chrome is in full-background mode (more battery) — back to normal?" → if yes,-   fully restart Chrome again **without** the flags. Real session + amazing recordings + normal battery.+   process tree** (many helper/background processes — closing the window is NOT enough; the flags don't apply+   until every `chrome.exe` is gone), wait for full shutdown, and **relaunch with their real profile** (logins+   survive; tabs restore) **plus the flags**.+3. Record full-framerate **in the background** while they keep working.+4. **Later OFFER TO REVERT** (battery): "Chrome's in full-background recording mode — back to normal?" → if+   yes, fully restart Chrome again **without** the flags. Real session + amazing recordings + normal battery.  **Hard requirement under both transitions:** a robust **full-restart of native Chrome** (kill the whole tree, confirm down, relaunch with profile + flags — and again to revert). -**⛔ NEVER:** foreground the window to "fix" a blank recording (defeats the point — the user must keep-working) · leave the flags on globally/permanently (battery drain) · use CDP screencast for demo video.+**⛔ NEVER:** foreground the user's *real* Chrome to fix framerate (use the flags) · leave the flags on+globally/permanently (battery drain) · upload a raw recording to the wiki without the `-g 30 -keyint_min 30`+keyframe re-encode (see recording-mechanics.md).  ## Captions (two systems) - **In-page** `nbrowser_caption {text, style, position}` — `style:"subtitle"` (calm white-on-dark, the
skills/native-browser-recording/SKILL.mdadded+72
@@ -0,0 +1,72 @@+---+name: native-browser-recording+description: How to record full-resolution, high-framerate demo videos of the user's REAL, logged-in Chrome/Edge through the Adom browser extension — in the BACKGROUND, so the user keeps working. Use this ONLY when a demo needs the user's real session/cookies/logins (a logged-in tool); when no login is needed, record via pup or Hydrogen (see the demo-recording skill) and never touch the user's real browser. Covers the paint-throttling problem, the occlusion/throttle-disable launch flags, the restart-native-Chrome-into-background-recording-mode flow (ask + warn + full process-tree kill + relaunch with profile + flags), the wgc/getdisplaymedia engines, and the offer-to-revert-for-battery step. Match on: record the native browser, record a logged-in demo, demo of the real browser, background recording of Chrome, nbrowser_record, full-framerate native recording. Part of the adom-browser-extension.+---+Part of **adom-browser-extension** (see **driving-the-extension** for the verb surface). The broad demo+pipeline (Hydrogen vs pup, scripting, TTS, storyboard, mux, wiki upload) lives in the **demo-recording**+skill — this page is ONLY the part that's unique to recording the user's **real, logged-in native browser**.++## When to use the native browser to record (and when NOT to)+- **Use it ONLY when the demo needs the user's real session** — cookies, SSO, logins (e.g. a tool gated+  behind their account). Only the user's real Chrome has those.+- **Otherwise, don't.** If the app is reachable without the user's login, record via **pup** or **Hydrogen**+  (demo-recording skill) — those are throwaway/managed surfaces you can drive freely without disturbing the+  user's real browser.++## The goal forces everything: full-resolution, HIGH FRAMERATE (20–60 fps)+Demos must look amazing. **The enemy is PAINT-THROTTLING, not the codec.** Chrome *correctly* stops painting+occluded / background / static windows (it's the right battery-saving default), and capture is frame-driven,+so a throttled window silently drops to ~5 fps ("frozen" / sped-up video). CDP screencast is **not** the+problem — it's pup's good 20–30 fps engine. The native-browser engines are real high-fps too:+- **`wgc`** — Windows Graphics Capture (via adom-desktop), 60 fps, **picker-free**, mp4 on disk (preferred on Windows).+- **`getdisplaymedia`** — the WebRTC/Meet pipeline, 30–60 fps, cross-platform; the share picker is auto-skipped+  with the Chrome flag `--auto-select-desktop-capture-source="<window title>"` **when we launch Chrome**.++## Why the native path is different from pup: you must NOT foreground the user's real Chrome+pup beats paint-throttling with the **foreground-rebump** trick (raise the throwaway window before each+action). **You must NOT do that to the user's real working browser** — it wrecks their flow. Instead, make+the real Chrome **keep painting while occluded** by launching it with the occlusion/throttle-disable flags:+```+--disable-features=CalculateNativeWinOcclusion --disable-backgrounding-occluded-windows+--disable-renderer-backgrounding --disable-background-timer-throttling+```+A default Chrome does **not** have these (correctly — they cost battery: every occluded window keeps+rendering). So enabling them is a **temporary, opt-in mode** we enter for recording and **leave afterward**.++## The flow — record a logged-in demo in the background+1. **Confirm you actually need the real session.** If not, go use pup/Hydrogen.+2. **Check whether native Chrome already runs with the flags** — read its launch command line+   (`adom-desktop process_list {nameContains:"chrome"}` → the main `chrome.exe` with no `--type=`). pup's+   "Chrome for Testing" already has them; the user's real Chrome usually does not.+3. **If the flags are missing → ASK + WARN, then fully restart Chrome into background-recording mode:**+   - Tell the user plainly: *"To record at full framerate while you keep working, I need to fully restart+     your Chrome once. Your tabs and logins come back."*+   - **Kill the ENTIRE `chrome.exe` process tree** — native Chrome spawns many helper/background processes+     (GPU, utility, crashpad, the `--no-startup-window` background-mode launcher); closing the window is NOT+     enough and the flags won't apply until *every* `chrome.exe` is gone. Kill them all, confirm shutdown.+   - **Relaunch with their real profile + the flags** (default `--user-data-dir`/`--profile-directory`, so+     **logins survive** and tabs return via session-restore), e.g. via `launch_process`.+   - Wait for the extension to reconnect (`nbrowser_status`).+4. **Record in the background** — `nbrowser_record_start {method:"wgc", hwnd:<window>}` (or `getdisplaymedia`+   with `--auto-select-desktop-capture-source`). Drive the app (CDP, background) + `nbrowser_caption`. The+   occluded window now paints, so the capture is full-framerate and not blank. **Never foreground it.**+5. **Stop + fetch** — `nbrowser_record_stop {method:"wgc", recordingId}` (wgc is bridge-side; the stop needs+   the `recordingId`, not just a sessionId). The mp4 lands on the laptop under `%TEMP%\adom-desktop-recordings`;+   pull it with `pull_file {filePaths:["C:\\...\\window-….mp4"]}` (it saves into the container `/tmp`).+6. **OFFER TO REVERT (battery):** when the recording session is done, ask *"Chrome's in full-background+   recording mode, which uses more battery — want me to put it back to normal?"* → if yes, **fully restart+   Chrome again WITHOUT the flags**. Best of all worlds: real session + amazing recordings + normal battery.++## The hard requirement under both transitions+A **robust full-restart of native Chrome**: enumerate + terminate the whole `chrome.exe` process tree, confirm+it's down, relaunch with the real profile (+ flags to enter, or without to revert). This is the load-bearing+primitive — get it solid and the rest is easy.++## ⛔ Never+- Foreground the user's **real** Chrome to "fix" framerate or a blank recording — use the flags instead.+- Leave the flags on **globally/permanently** — it drains laptop battery. Enter the mode, record, offer to revert.+- Upload a raw recording to the wiki without the `-g 30 -keyint_min 30` keyframe re-encode (see demo-recording).++## Hand-off+Post-production (speedup, voiceover, storyboard review, concat, hero, wiki upload) → the **video-post** skill.+Surface selection, scripting, TTS, the keyframe rule, the cross-surface mechanics → the **demo-recording** skill.
uninstall.sh+1−1
@@ -1,5 +1,5 @@ #!/usr/bin/env bash DEST="${HOME}/.claude/skills"-for name in cross-platform-dev driving-the-extension driving-the-extension-demo driving-the-desktop driving-sites driving-gusto; do+for name in cross-platform-dev driving-the-extension native-browser-recording driving-the-extension-demo driving-the-desktop driving-sites driving-gusto reading-google-messages; do   rm -rf "$DEST/$name" && echo "removed skill: $name" done