---
name: promo
description: Turn an app URL into a product promo with the app's real screens, a chosen frame and style, voiceover, and music. Use when asked to make a promo, demo, or marketing video of a website or app. A Chrome window opens once so a person can sign in. Frames are 16:9, 9:16, or 1:1. Styles are editorial, blueprint, swiss, chalkboard, or match.
---

# Promo

You are an agent making a WatchRecap product promo. Follow this file. Do not invent a different pipeline.

The film shows the real product. Screenshots are captured from the live app, then composed into a motion piece with a voiceover and music. Run from `pipeline/` in the WatchRecap repo, with `pipeline/.venv` (`./scripts/setup.sh` from the repo root). `OPENROUTER_API_KEY` must be set in the repo `.env`. Google Chrome is required for capture.

Only do this for an app the person owns or can sign in to.

## 1. Capture

```
.venv/bin/python capture.py "https://app.example.com"
```

A Chrome window opens. The person signs in once. The session is saved and reused later. Capture the richest, most populated screens, not empty states. Screens land in `data/promo/<host>/shots/`.

Copy the 3–5 strongest into a `pick/` directory. Put a keyword in the filename so the caption matches the view: `00-map.png`, `01-notes.png`, `02-today.png`. Known keywords: map, notes, sprint, today, now, view, full.

## 2. Compose

```
.venv/bin/python promo.py --shots data/promo/<host>/pick \
  --name "App name" --url "https://app.example.com" \
  --tagline "The app's real tagline" \
  --seconds 30 --format 9:16 --style blueprint
```

- `--seconds` is the target length. Promos are meant to be short (about 30 or 60 seconds).
- `--format` is `16:9` (1920×1080), `9:16` (1080×1920), or `1:1` (1080×1080). The capture stays a desktop screenshot. The film is composed into the frame you pick.
- `--style` is `editorial`, `blueprint`, `swiss`, `chalkboard`, or `match`. A named style changes the palette, the motion and type, the Gemini voice, and the music bed. `match` takes the palette from the screenshots and keeps the film in the product's own tone.
- `--tagline` must be the product's real line. Do not invent features or numbers.

The model places each screenshot with `data-shot="N"` and does not emit image data. The pipeline injects the images afterward.

The model also emits the voiceover, already timed to its beats:

```
<script type="application/json" id="narration">
[ {"t": 0.8, "say": "One spoken line."}, {"t": 5.9, "say": "The next line."} ]
</script>
```

Read together, those lines are one continuous narration. `t` is when that line should start. Do not speak the URL. The URL is on the closing card.

## 3. What the pipeline does next

`promo.py` checks that every frame is a pure function of time, regenerating up to three times if a frame depends on how it was reached. It then records the narration, ducks a music bed under it, and mixes both onto the picture.

## What you get

`video.mp4` under the output folder (`--out`, or `data/promo/<name>/film`): the film, the voice, and the music.

## The contract

`window.__seek(t)` draws exactly the frame at second `t` and is a pure function of `t`. No timers, no `Date`, no `Math.random`. Elements are created once and only updated inside `__seek`.

## Do not

- Do not mock the product. If a screen was not captured, it is not in the film.
- Do not use this skill for a paper or a topic with no app. Those are the explainer and cinematic skills.
