# Recording and high-FPS windows

> Sub-readme of the [pup bridge README](README.md). Covers background video recording, the
> `highFps` window mode, the lease that keeps it from flattening a battery, and how an AI
> negotiates for the time it actually needs.

## The problem this solves

Chrome throttles a window that is **occluded** (covered by other windows) or backgrounded. It
stops painting, freezes timers, and drops requestAnimationFrame. That is why your laptop sleeps
fine with twenty Chrome tabs open, and it is correct behaviour.

It is also fatal to background video recording. pup windows are backgrounded **by design** (pup
never steals your screen), so recording one through Chrome's normal power behaviour produces a
**1-2 fps** video.

pup used to solve that by launching **every** window with all four of Chrome's power-saving
mechanisms disabled:

```
--disable-renderer-backgrounding            keep rendering in a background tab
--disable-backgrounding-occluded-windows    keep rendering when the window is occluded
--disable-background-timer-throttling       keep timers/rAF firing
--disable-features=CalculateNativeWinOcclusion   skip occlusion detection entirely
```

That made recording work and made every other window a battery hazard. A window in this mode can
never idle down. Three idle pup windows held a Modern Standby laptop out of deep idle overnight,
drew ~13 W, and drained it from 99.9% to 2.5% in about 5.5 hours (wiki issue #14). Nothing looked
wrong on screen because the windows had no visible presence at all.

## What pup does now

**Default: Chrome's own power behaviour.** A normal pup window throttles when occluded and costs
essentially nothing sitting in the background. This is the right mode for driving, scraping,
screenshots, and everything that is not video.

**Opt in for recording: `highFps: true`.**

```jsonc
pup_open_window { "sessionId":"demo", "url":"https://...", "highFps": true }
```

That window renders at full rate even while occluded, so a background take is smooth. Because it
can never idle down, it is **leased**, not open-ended.

## The lease

| | |
|---|---|
| Default lease | **20 minutes** |
| Maximum lease | **120 minutes** |
| Warning | logged ~**2 minutes** before the lease lapses |
| On lapse | the window is **downgraded**, not closed |

Why 20 minutes: long enough for a real demo take, short enough that a window someone forgot about
cannot cost a battery overnight. The incident that motivated this ran for **two days**.

**Downgrade means downgrade.** When a lease lapses, pup relaunches the same session with the same
tabs under normal power behaviour. Your window and its content survive; only the power profile
changes. pup does not close a window that may be holding the user's work.

## You cannot be cut off mid-recording

This is the guarantee that makes the lease safe. **While a recording is actually running, the lease
cannot lapse.** pup keeps pushing it out for as long as frames are being pulled.

This is knowable rather than guessed, because recording runs through pup's own verbs
(`pup_record_start` / `pup_record_stop`), so pup has authoritative state, not a heuristic.

The activity signals, in priority order:

1. **An active recording** — authoritative, holds the lease open indefinitely.
2. **Verb activity** — any `pup_*` call against the session shows it is in use.
3. **An explicit extension** — `pup_highfps_extend`, for when you know up front you need
   longer but will not be recording the whole time.

## Negotiating

pup tells you the lease terms in the `_hint` of every `pup_open_window` response, including
when it will downgrade and how to keep it. If you need longer:

```jsonc
pup_highfps_extend { "sessionId":"demo", "minutes": 45 }
```

You do **not** need to keep extending during a take. Extend when you are staging a long session
that has gaps between recordings.

## Recording a normal window

You can, and pup will not stop you, but if the window is occluded the take will be ~1-2 fps. pup
logs a warning when a recording starts on a normal-power window so a bad video is not a surprise:

```
[highfps] "demo" recording started on a NORMAL-power window — frames will drop to ~1-2 fps
          while it is occluded. Reopen with pup_open_window {highFps:true} for a
          full-rate background take.
```

If the window is genuinely visible on screen for the whole take, a normal window is fine.

## Checking state

`pup_open_window` returns a `highFps` field: `false` for a normal window, or
`{active, minutes, expiresAt, msRemaining, recordingActive}` for a leased one. The same shape comes
back from `pup_highfps_extend`.

## Rules of thumb

- **Driving, scraping, screenshots, waiting?** Normal window. Never ask for `highFps`.
- **Recording a window the user is NOT looking at?** `highFps: true`.
- **Recording something on screen the whole time?** Normal window is fine.
- **Long session with gaps between takes?** `highFps: true` plus an extension sized to the session.
- **Done recording?** Nothing to do. Stop the recording and the lease lapses on its own, and the
  window quietly returns to normal power.
