---
title: The site is the story
summary: A launch film built from the live product. GroundSlate records the real pages scrolling, on desktop and on a phone, with cookie banners refused during capture, and your agent cuts them into a narrated film. No mockups, no recreations, and nobody has to sit and screen record.
lede: Built from the live product, no mockups and no recreations
tools: get_context, list_profiles, browser_policy, request_browser_site, capture_page, record_page, open_browser_window, close_browser_window, list_browser_windows, composition_doctor, voice_status, check_fonts, import_fonts, import_asset, get_asset, fetch_asset, index_folder, index_image, add_media_to_project, search_projects, create_project, project_manifest, write_project_file, read_project_file, list_project_files, add_project_note, write_composition, preview_html, render_html, author_film, save_kit, get_kit, remove_background, list_effects, apply_effect, reframe_vertical, make_reframe, list_voices, preview_voice, synthesize_speech, transcribe, audio_beats, mix_audio, render_ffmpeg, list_transitions, transition_motion, render_sequence, extract_clip, sample_frames, job_events, request_review, review_status, withdraw_review, commit_to_library, name_video, list_project_outputs
works_with: agent-skills, claude-design, elevenlabs
order: 6
---

Most product films never show the product. They show a mockup floating at an angle over a gradient, because real footage of a website meant booking someone to screen record it and then cutting around their cursor.

GroundSlate records pages itself: WebKit on the Mac, desktop or a true phone viewport, the whole page scrolling as video, with the cookie banner refused before the first frame. So the film shows the real thing: your type, your photography, your interface, moving. This skill has your agent produce that film.

> Use /groundslate-site-film on <<YOUR PRODUCT URL>>. The story is <<WHAT LAUNCHED OR CHANGED>>. It is for <<WHO WATCHES IT>>, and it should run about <<LENGTH>>. Bring me a cut.

The site needs to be reachable without a login. If the good part is behind a sign in, say so in the ask, and the skill will open a window for you to log in once.

## Install it

Copy or download SKILL.md above.

For Claude Code, save it as `~/.claude/skills/groundslate-site-film/SKILL.md`.

For claude.ai and the Claude desktop app, put it in a folder named `groundslate-site-film`, zip the folder, and upload it under Settings, Capabilities, Skills.

## The skill

````markdown
---
name: groundslate-site-film
description: Build a launch or product film out of the live site itself. GroundSlate records the real pages with capture_page and record_page, in desktop and phone viewports, with consent banners refused at capture, and the agent cuts them into a narrated film with ducked music. Use when somebody wants a product launch video, a feature reveal, a site tour or a release film and the product is on the web.
---

# The site is the footage

The product is the footage. Everything else supports it. Your job is to
capture the real thing well, then cut it with an argument.

## Permission comes first, and you cannot grant it

Web capture is off until the human turns it on, and then answers to their site
policy. Do this before you promise a film.

- `browser_policy` reads the current state: enabled or not, the mode, and the
  lists.
- `request_browser_site` ASKS for a host, with your reason, and the human
  decides in GroundSlate. Asking twice increments a counter rather than
  creating a second request, so ask once and say what you need.
- If the policy is a LIST, third party frames on the page are refused too, and
  most of a commercial page's furniture is third party. The result says so.
  RELAY THAT. A capture shown as "the page" when a third of it did not load is
  a misrepresentation, and only the human can widen the policy.
- A capture that redirects somewhere the policy does not permit is discarded
  rather than returned.

## Capture the site properly

- `capture_page` for stills. `device` is desktop (1440x900) or mobile
  (390x844 with a phone user agent, so the site serves its real mobile layout
  rather than a squeezed desktop one). `full_page` for the whole scroll,
  `scale` for retina.
- `record_page` is video. `scroll=True` walks the page top to bottom across
  the recording, and that is what turns a static site into footage.
- Record at 24fps. A scrolling page repaints continuously and holds about 7
  percent of its frames at 24 against 16 to 26 percent at 30, measured. More
  frames is not more motion here, it is more duplicates.
- `consent="reject"` refuses the cookie banner at capture time so it is never
  in your plate. There is no accept option and you should not want one.
- For a 9:16 cut use `device="mobile", width=360, height=640, scale=3`. That
  is a true phone viewport upscaled, not a desktop page squeezed.
- Behind a login: `open_browser_window` with a `reason` written for the human,
  they sign in, and then `session="shared"` on the capture sees it. Nothing
  here solves a challenge for you and nothing should try. `close_browser_window`
  when you are done, or it closes itself after thirty minutes.

Capture more than you need, in both form factors, and capture the flows rather
than only the landing page. Pricing, the app itself, the docs, the empty
state, the thing the release actually changed.

## Shoot list before capture list

A page scrolling is not automatically interesting. Decide what each capture is
FOR before you take it.

- The hero: the page as the subject, full frame, sharp, moving.
- The detail: a crop magnified out of the page with the rest ghosted, so a
  small piece of interface becomes readable at a distance.
- The comparison: before and after, or two states side by side, where the
  difference is the point.
- The scale shot: many captures at once, a grid, where the repetition is the
  argument.
- The device: a capture held in a frame, angled, moving, when the fact that it
  is a phone matters.
- The cutout: `remove_background` lifts a subject off a still on device and
  writes a transparent PNG at source resolution with the subject in place, so
  it drops back over the original as a layer. Check `foreground_fraction`,
  because near 1.0 means nothing came off.

A blurred page behind a headline is the weakest use of a capture and it is the
one everybody defaults to. Spend the vocabulary.

## Cut it as an argument, not a tour

- Open on the change, not on the logo. What is different, in one line.
- One statement per scene, set large. The narration carries everything else.
- Show, then say. The capture lands, then the line about it, not the reverse.
- The demo is a sequence of decisions, not a scroll. If a capture runs longer
  than the point it is making, cut it.
- Close on what to do next, and make it specific.

## The scene rules

- Small type is only ever verbatim evidence, a URL, a label, a line of code.
  A sentence set small is the narration leaking onto the picture.
- Motion is how a thing arrives and leaves, not a state it lives in.
- The layout is fixed from t=0. Nothing on screen moves because something new
  arrived.
- Composition varies between scenes, never inside one.
- The captured page is the layer that moves. The type over it holds still.

## Everything happens inside GroundSlate

- `write_composition` writes an authored page where the renderers can open it.
  Never reach outside the framework for a filesystem bridge.
- `render_html` bakes a page. `render_sequence` assembles N clips with N-1
  seams in one call, encoding every frame once. `author_film` expresses
  scenes and seams as one composition.
- `mix_audio` IS the ducking: voice plus music in, `ffmpeg_argv` out, bake it
  with `render_ffmpeg`. Its `threshold` is a linear amplitude, not decibels.
- `list_transitions` and `transition_motion` for the moves. Choose on the
  measured `seam_seconds`.
- `reframe_vertical` or `make_reframe` when the same film has to ship 9:16,
  but prefer recapturing in a phone viewport, which is a real mobile layout
  rather than a crop of a desktop one.

## Timing is frames

- A transition overlaps its two shots and never adds time:
  `sum(clip frames) - sum(seam frames)`.
- Declare durations that land on whole frames at your fps.
- Freeze scene durations before you place a single audio cue, or you will
  re-derive every cue downstream by hand.
- Verify frame counts with ffprobe on the delivered file, not from the job
  record.
- A recorded page is not always constant frame rate. Normalise it explicitly
  before it enters the cut, or a later step drops frames without saying so.
- One pixel format and one colour range across the whole film. A single full
  range clip among limited range ones is a visible black level jump.

## Motion has a floor

- A drift under about 0.3 px per frame emits identical frames. Clear 8 px per
  second on a ground you can actually see.
- A scrolling capture under a still headline is the trap this format invites.
  If you paused the capture, would the scene still be moving? Measure the type
  and graphic layers separately from the footage.

## An instrument that cannot fail is not evidence

- Prove the red before you trust the green.
- Look at every capture before you cut it. A page can render with a missing
  font, a blank third party frame, an interstitial or a consent wall, and the
  file will still be a valid mp4 of exactly the right length.
- Never present a capture as the page when part of it did not load. Say what
  was refused.

## The project is the source of truth

A DIFFERENT agent, tomorrow, with only the profile and the project id, must be
able to continue this. If they cannot, it failed.

- `create_project` early, hold the `prj_` id, bind everything.
- Captures are media: bind them, and record which page and which viewport each
  one came from. A folder of screenshots nobody can attribute is not an asset
  library.
- `write_project_file` for the shoot list, the script, the cue tables and the
  note map from each review round.
- `add_project_note` for a decision and its reason.
- `commit_to_library` the finals with the project.
- The site will change. Record the capture date beside every asset, because a
  re-cut in three months is against a different site.

## Show them, every round

- End every round with `request_review(source, ask, agent=, profile=)`.
  ALWAYS pass an `ask`, or it is a show: it accepts notes and offers no way to
  submit them. ALWAYS pass `agent=`.
- Read `placed` back and say what it says: `opened`, `waiting` (running, not
  frontmost, Dock bouncing), `saved` (app shut).
- `review_status` for the notes and their anchors. Work from the anchor.
- `withdraw_review` for a superseded question of your own.
- Report per note: DONE, NOT DONE or PARTIAL, with evidence.

## Report like a producer

- Keep working while captures and renders run.
- Say which hosts were allowed, which were refused, and what that cost the
  picture.
- End with where the film is, what it is called, and the date the site was
  captured.
````
