# Video production How Gritmind videos get made: explainers, social cuts, animated quote cards and title sequences. This page is the process and the production specs. The visual motion language (timing, easing, the signature noise-to-signal move, title cards, lower-thirds, grading) is in the skill's `references/motion.md`; read both. Origin: the process here was proven on the Bison Commerce explainer (Remotion, September 2026, `~/bison/video`). The practices carry over; Bison's visuals, pace and sound do not. See "What we did not borrow" at the end. ## Process Every video moves through these stages in order. Each one ends in a review, and the next stage does not start until the reviewer has approved the last. | Stage | Output | Approved when | | --- | --- | --- | | 1. Brief | The decisions table (below) | Every row has an answer | | 2. Script | Beat sheet: what is on screen, for how long, in what order | Copy and figures signed off | | 3. Style frames | One still per scene, in every format | The look is right before anything moves | | 4. Music | Track chosen, or a decision to run without | Licence confirmed for commercial use | | 5. Build | Every scene animated on the timeline | First full preview watched end to end | | 6. Sound | Effects and mix | Listened to on speakers and headphones | | 7. Render | Final files in every format | Pre-flight passed | | 8. Hand-off | Files delivered, hosting decided by whoever owns the destination | | Style frames are the cheapest place to change your mind. Do not start animating until they are approved. ## The brief Answer these before writing a line of script, and record the answers at the top of the project's own `CLAUDE.md` or brief file, dated. | Question | Default | | --- | --- | | Purpose and audience | One sentence each | | Length | Under 60s for social, under 2 min for a site explainer | | Formats | 16:9, 9:16 and 1:1 from one build (below) | | Voice | Voiceover, or text-only. Text-only must work muted. | | Music | Licensed track, or silence (silence is on-brand) | | Tool | Code (Remotion) for anything with type in it (below) | | Where it lives | A project folder outside any product or site repo | | Reviewer | One named person who approves each stage | ## Tool choice **Build anything with type in it in code** (Remotion: React, rendered frame-by-frame). AI video generators cannot render large type reliably, and in our videos the type is the content. Code also gives exact brand values, one build for every format, and a diffable history. AI generation is fine for organic footage that type never touches (a texture, a camera move on an object). Never use it for the logo, for type, or for UI. Log every generated clip with its prompt, model and job id (see "Provenance"). **Repeatable formats are templates in this repo**, under `templates/video/`. The template holds the design; each piece's inputs (photos, names) and its renders live in a folder outside the repo that the template's scripts take as an argument. Why: the design is reviewed like any brand change, and personal data never enters git. The first is `templates/video/new-hire/`, the new-hire announcement loop. ## Formats and safe zones Build once and render every format from the same timeline. Scenes lay out from the composition's width and height; never build three separate edits. | Format | Size | For | Content box (keep type inside) | | --- | --- | --- | --- | | 16:9 | 1920x1080 | Site, YouTube, decks | 120px from every edge (per `motion.md`) | | 9:16 | 1080x1920 | Reels, Shorts, TikTok, Stories | 8% from the sides, clear of the top 12% and bottom 20% | | 1:1 | 1080x1080 | LinkedIn feed | 9% from the sides, 10% top and bottom | All at 30 fps, H.264, AAC stereo. The 9:16 margins keep type out of platform UI (captions, buttons, profile row). Imagery may run into those zones; type may not. Put the content box in one layout helper that every scene reads, so a margin change is one edit. Derive a base unit from the short side (`min(w, h) / 100`) for small type, rules and gaps, so they scale across formats. ## Timing **A reading floor, then calm.** Nothing leaves the screen before it can be read: at least 0.3s per word and never less than 0.8s per card. That is the floor, not the target. Gritmind sits at the slow end: a stat holds at least 2.5s (`motion.md`), and a card should hold long enough to read twice. **Hook early.** The first words are on screen by 2s. No logo intro (a social loop's first frame is its end card; see "Social loops"). If the video opens on the signature noise-to-signal move, the headline lands with the resolve, not after it. **End on the mark.** Close on the logo and `gritmind.com`, held still for 2 to 3 seconds (social loops excepted, below). To bring the stacked logo in, use the formal animation (`assets/graphics/gritmind-logo-animation.js`, 0.6s); its `render(t)` gives exact frames, so drive it from the composition's frame number, then hold. **When there is music, cut to its grid.** Pick the BPM and build the timeline in beats and bars, not frames: ```ts const beat = (n: number) => Math.round((n * 60 * FPS) / BPM) + OFFSET_FRAMES; const bar = (n: number) => beat(n * 4); ``` Never hardcode frame counts. At most tempos a beat is not a whole number of frames, so hardcoded frames drift. Keep the scene table in beats in one place, and land the important moments on downbeats and the track's lifts. When the real track arrives, measure its actual BPM and the offset of its first downbeat, set `BPM` and `OFFSET_FRAMES`, and move scene boundaries to the track's sections rather than forcing the track to fit the edit. ## Words on screen - One idea per card. Aim for 6 words or fewer; 9 is the ceiling. - Headlines fill 60 to 80% of the content box width. Size type by measuring it with the real font (Remotion's `fitText`), not by eye, and fit a set of cards to one shared size so the type does not jump between them. - **Gate rendering on the font loading.** Measuring against a fallback font caches the wrong sizes. Load Alliance No.2 and JetBrains Mono, hold the render until both are in, then measure. - Text-only videos must work muted: feeds autoplay silently. Anything with speech gets captions (spec in `motion.md`). - Numbers are mono, prose is sans, one accented word per card - the same rules as every other medium. - Mask reveals clip descenders unless the mask extends below the baseline. Extend it by about a third of the font size, and stop clipping once the line has settled. ## Motion vocabulary **A small set of moves, used consistently.** Many different transition types read as amateur. Pick from this list before inventing anything: | Move | Use | | --- | --- | | Noise to signal | The signature. Once per piece, at the open or the main point. | | Fade and 14px rise | Default entrance for text and elements | | Mask wipe | Replacing one line with the next in place | | Accent rule draw | Underlining the one accented word, left to right | | Count-up | Stats, in mono, landing on the same rounding as the site | | Hard cut | At most once, to mark the turn from problem to answer | | Signal lines, held | Background of a social loop only (below) | Easing and durations come from `tokens/tokens.json` and `motion.md`. The spring curve belongs to the logo only, so no overshooting word slams. ## Social loops Short pieces that autoplay and loop muted in a feed: under 10s, one card. The rules above hold except where this section says otherwise. Why: a loop is watched two or three times in a row, so it needs energy on the first pass, and its first frame is also its end card. - **The first frame is the last frame.** Open and close on the stacked logo and `gritmind.com`, and close with the formal logo animation, unchanged. The logo may hold 0.2 to 0.3s on each side of the loop point instead of 2 to 3s, because the loop shows it again at once. - **A faster text build.** Lines rise through masks in 300ms each, staggered by 70ms, on the `out` curve, with no overshoot. This replaces the 600ms title card entrance only here. - **Hold the person, not the logo.** Once everything has landed, hold the finished card for about 3s before the exit. Type and photo stay still through the hold; background motion may continue. - **Signal lines as a background.** The homepage hero lines may run behind the card as its held hover state: the three lines keep scrolling, the middle one sweeps to the accent once and then stays resolved to the left of a resting point, with its dot riding the line; the other two fall back. No crosshair and no SIGNAL label. It counts as the piece's one noise-to-signal moment. Where lines pass behind type, give the type a ground-coloured outline so they stop short of the letters. The reference build is `templates/video/new-hire/`. ## Figures and claims Every number and claim on screen comes from the canonical figures list (see `CHECKLIST.md`; until it exists, the shipped website copy) and is signed off at the script stage. Keep a table in the project brief: figure, wording on screen, source. If a figure has no documented basis, it does not ship. If it is dropped, record that and why. Never invent a quote, a figure, or a client name. ## Sound Gritmind sound is sparse. Music sits under -18 LUFS and drops another 6dB under narration (`motion.md`); effects mark structural moments (a cut, a resolve, a stat landing), never every element. Silence is a valid choice. When effects are used, run them like this: - **A cue sheet in JSON**: id, description or generation prompt, duration, volume, and cue points in beats. Code reads it; nobody places sounds by hand on a timeline. - **Normalise every effect** to a peak of -1 dBFS before mixing, so the volumes in the cue sheet compare. Generated and library sounds arrive at wildly different levels. - **Duck the music** briefly under effects that need to cut through, rather than raising the effect. - **Check the mix** with an audio-only render (`--codec=wav`). The final peak stays below -1 dBFS, the usual streaming ceiling, with no clipping. ## Provenance and licensing Keep a `LICENSES.md` in the project listing every asset that was not drawn in code: music, effects, footage, photos, fonts. For each: file, source, date, licence or plan, and for generated assets the prompt and job id. - Music must be licensed for commercial use. A free plan on a music generator usually is not. ## Review - Render style frames and review stills from a script that renders a named list of frames for every format in one pass (`node scripts/stills.mjs hook:102 end:1655`), so every review covers all three formats. - Log each review round in the project brief: date, reviewer, what changed. The reviewer's own wording when it decided something. - When a scene is retimed, update the frame numbers in the notes or delete them. Stale frame numbers waste the next review. ## Project hygiene - Keep the video project in its own folder, outside the website and product repos. It reads brand files; it never writes to another repo. - **Vendor, do not import.** When reusing a site component or animation, copy it into the video project with a header naming the source repo and commit. A later site change must never alter an approved video. - Pull tokens, fonts and logos from a pinned brand release, not a working copy. - If a component builds class names dynamically (Tailwind), the build will not generate them; list them explicitly. - API keys for generation services live in your shell profile, never in the project and never pasted into chat. ## Render and delivery - Render each format to `out/-.mp4`; `out/` is never committed. - Confirm duration, resolution, frame rate and audio with `npx remotion ffprobe`. - Hosting is the destination owner's call. Uploading to the site's player or a social account is a separate, deliberate step. ## Pre-flight addendum (video) Run with the general pre-flight in `CHECKLIST.md`. - [ ] Rendered in every format in the brief; type inside each content box - [ ] First words on screen by 2s; ends on logo and URL, held 2 to 3 seconds (social loops: first frame = last frame, 3s hold on the card) - [ ] Every card meets the reading floor (0.3s per word, 0.8s minimum) - [ ] Watched muted: still makes sense - [ ] Captions on any speech - [ ] Every figure traced to its source in the brief - [ ] Mix peaks below -1 dBFS, no clipping - [ ] `LICENSES.md` complete; music licence confirmed - [ ] No flashing above 3 Hz; reduced-motion still provided if used as a loop ## What we did not borrow The Bison explainer is fast, loud and cheeky by design. These parts of it are deliberately not Gritmind: - Spring-overshoot word slams and slam hits on every word - Effects on every element (cartoon zips, crunches, pops) - A 124 BPM driving electronic bed under the whole piece - Card holds near the reading floor throughout - Heavy (800) headlines; ours are weight 500