Extracting a style

Draft a style from stills, clips, live web pages, front-end code, or Figma with rapid style extract, then finish it with the extractor agent.

rapid style extract measures stills and clips, reads live pages and front-end code, and writes a draft style; the rapid-extractor agent finishes it. Values read from a source (tokens, type, faces, easing) win over values measured from pixels, so give it the page or the repository when there is one.

Extraction takes the feel of a look, never its identity: no logos, no marks, no faces you aren't licensed to use.

Run it

rapid style extract refs/*.jpg refs/clip.mp4 --name warm-field --out ~/styles/warm-field
  • <sources...>: any mix of stills and clips to measure, https:// pages to read, and folders of front-end code. A folder that holds only stills and clips is taken as references.
  • --name <name>: the draft's name (lowercase, a-z, 0-9, -).
  • --out <dir>: an empty or new folder for the draft. A folder that already holds files is refused.
  • --frames <n>: frames sampled from each clip, 1 to 120 (default 12).
  • --timeout <seconds>: how long to wait for each web page at each width (default 30).
  • --assets <dir>: keep what a web page shows, in a new or empty folder; see keeping a page's assets.
rapid style extract https://example.test/ ./checkouts/site refs/clip.mp4 --name warm-field --out ~/styles/warm-field

It needs ffmpeg and ffprobe on your PATH. Run on a two-scene render and one still, it prints:

drafted /Users/you/styles/warm-field
palette
  field      #14171a   50.4%
  ink        #fefefe    4.2%
  paper      #f0ede4   45.4%
shots     median 3.1s over 2 (even, steady)
tempo     200.3 BPM (confidence 0.389)
margins   top 26.8%  right 22.0%  bottom 43.8%  left 6.3%
motion    0.204/s (moderate)
formats   reel, square

Few references give rough numbers, as the low tempo confidence says. Give it several clips and stills of the look.

What it measures

WhatHow
paletteweighted k-means in OKLab over every sampled pixel, each frame weighing the same, then named as tokens
pacingffmpeg's scene-cut detection on clips: shot lengths, their median and mean, rhythm, and trend
musictempo from the onset envelope of a clip's audio, with a confidence, and loudness per second
layoutwhere content stands apart from each frame's background colour, as insets from the edges
motionhow much the picture changes per second: a calm-to-kinetic number
formatsthe built-in format nearest each reference's aspect ratio: reel, square, or wide

From a live page

An https:// address opens in the headless Chrome rapid renders with, in its own browser context, closed after, with a time limit. The page's own scripts run; this is extraction, not rendering, so the render page's "nothing outside the page" rule does not apply. It loads the page at a phone width (390 px) and a desktop width (1440 px) and reads, from the page's computed styles:

WhatHow
tokensevery custom property on :root, with its colour as hex where it is one
typeheadings h1–h3, the body text (the style most text is set in), buttons, links, and small text: font-family stack, weight, style, size, line height, letter spacing, case, colour, and background
facesthe faces the page loaded (document.fonts): family, weight, style, and their url() and local() sources. Only names and addresses are recorded; no font file is downloaded or copied
coloursbox backgrounds by the share of the screen they cover, and text colours by how much text is set in them
shapesthe commonest button and card: corner radius, border, and shadow
motioncomputed transitions and animations (durations and timing functions), and @keyframes from the page's own stylesheets
marginswhere the text starts in the first screen at each width: the container's real padding

Before it reads, rapid waits out the page's loader and intro animations, then scrolls it a screen at a time so lazy pictures load and scroll-triggered sections play, and shoots every screen. Each stop waits briefly for the network and for motion to settle, so a long page takes a while.

Screenshots at both widths join the references, so the pixel analysis and the extractor agent see them; they land in refs/. A page that answers with an error, shows a sign-in form, or does not finish loading is reported plainly, and rapid continues with whatever did load.

Keeping a page's assets

With --assets <dir>, rapid also keeps what the page showed, for a video about the site. The files are the site's own: use them only for a video about that site.

rapid style extract https://example.test/ --name site --out ~/styles/site --assets ~/rapid/site-video/assets
KeptNotes
picturesat the largest size their srcset offers
video clips and postersthe clip files and their poster pictures
backgroundsCSS background images
inline vectorssaved with their drawn size and inherited colour, so each stands alone
icons and the share imagethe page's icons and its og:image

Each file is named for its alt text, else for the heading of its section, else for its address. The folder holds:

assets.json     every kept file: what it is, where it came from, and its section
screens/        every screen of the scrolled page
contact.png     every kept picture, clip frame, and vector in one labelled grid

contact.png shows the set at a glance, which is how a storyboarder chooses. Pointing --assets at a project's assets/ folder puts the files where scenes reach them.

From front-end code

A folder that is not a folder of stills is read as code, statically. Nothing in it runs. rapid skips dependencies and build output and reads:

FormatWhat it reads
CSS, SCSS, Lesscustom properties (--name: value, var() resolved within the folder) and @font-face families with their sources
Tailwind config (tailwind.config.{js,ts,cjs,mjs})theme and theme.extend: colors, fontFamily, fontSize, borderRadius, transitionTimingFunction, transitionDuration; values the config computes in code are skipped
design tokens JSONW3C design tokens ($value, $type, aliases such as {color.white}), and Style Dictionary value trees in files named for tokens or a theme
SwiftColor(red:green:blue:), Color(hex:), UIColor(red:…), and Font.custom / UIFont(name:) faces with their sizes

Every value in analysis.json keeps the file it came from.

From Figma

rapid holds no Figma keys. When Figma's MCP server is connected in your Claude Code, ask the extractor agent to read a file or a frame: it uses that server's tools for the variables (colours, type, radii) and screenshots of the frames, saves the screenshots into the draft's refs/, and fills the same fields a page or a repository does, noting the source in taste.md. Run rapid style extract on the screenshots (or on the matching page or repository) first, so the draft has its measurements.

How exact values are used

The draft takes exact values over pixel guesses wherever a source gives one:

  • palette: field is the background covering the most screen, ink the colour most text is set in, accent the buttons' background (else the links' colour), paper the cards' ground; a theme's colours are matched to those roles by their names (background, text, primary, card). Other token colours follow under their own names, then pixel colours none of them has.
  • type scale: hero, title, body, and small from the real sizes of h1, h2, the body text, and the small text, at the width nearest the format, scaled so the page's width fills the frame (390 CSS pixels to a reel's 1080). A theme's sizes are read as a phone's.
  • leading: from the headings' and the body's line heights.
  • faces: each role (display from h1, voice from the body text, ui from buttons) names the source's face in analysis.json; the draft uses it when it is installed here, else the first installed family of its stack, else a generic family.
  • margins: from the container's padding, as a share of the frame.
  • easing: the commonest timing functions, as motion.easing.in and out.
  • components: the card's and the button's radius, border, and shadow.

taste.md gets an Exact section that says where each of these came from.

What it writes

warm-field/
  manifest.json    kind style, version 0.1.0, tagged "draft", its file list filled in
  style.json       the measured palette, margins per format, shot length, and tempo
  style.css        the kit styled from the tokens alone, to make the style's own
  taste.md         the measurements as facts, with Motion, Type, and Composition left to write
  analysis.json    everything measured, by reference, and everything read from pages and code, by source
  refs/            stills taken at the references' largest scene changes, and page screenshots

What code can't measure stays a placeholder: with no page or theme to read, every type role's face is sans-serif; and taste.md has no rules yet. The draft has no proof, and its style.css is the default kit sheet, which looks the same in every draft.

Finish it with the extractor agent

A video in the look finishes it itself: start it with rapid video <project> --look <draft> (or new_video with look), and the job runs the extractor, holds the draft to rapid style check, and pins it in the project's rapid.lock before the storyboard. To finish a draft on its own, the plugin's rapid-extractor agent does it. In Claude Code, ask for it:

Use the rapid-extractor agent to finish the draft style in ~/styles/warm-field.

It reads analysis.json and the refs, keeps every exact value over its own impression and notes where each came from, names the class of each type role, picks the closest installed face that is licensed for rendered videos, writes taste.md's rules (checkable ones with numbers from the analysis, and judgment ones in plain words), tunes style.json, and runs rapid style check --write until it passes. It keeps measured values unless the refs plainly contradict them, and records its reasoning in analysis.json.

Proving the draft against its references (rendering a sample in the new style beside them and tuning it until a judge says it reads right) is planned, not built. rapid style proof proves a style against itself, once you have written its sample.

Then

Review the faces and rules yourself, make style.css the style's own, render a scene in the style, and follow making a style from step 8 to prove it and pack it.