Files
mintel.me/apps/video/CLAUDE.md
T
mmintelandClaude Opus 5.5 5cbcb2eac4 feat: content strategy, image posts and a posting plan for the films
Adds twelve image posts made the same way as the films: six posters
(one picture of each film with its idea in two lines) and six cards
that answer a question clients ask before the first call. The answers
come from the questions and principles on the website.

The posting plan is data (six weeks, film, card and poster per week),
and the export writes the library in that order, by language, week and
day, with the text to post. All video posts now open with the hook of
their film. The reasoning is in plans/content-strategy.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 10:00:28 +02:00

103 lines
7.7 KiB
Markdown

# apps/video
Social media videos (LinkedIn first, 16:9 for YouTube and Google Ads) in the mintel.me look, made with Remotion.
Standalone package: it is **not** in `pnpm-workspace.yaml`, so it never ends up in the web build, the Dockerfile
or `pnpm -r`. `apps/web` must never import from here, and this package imports nothing from `apps/web`.
## Commands (run from this folder)
- Install: `pnpm install --ignore-workspace`
- Studio (the playground, http://localhost:3000): `pnpm studio`
- One frame as PNG: `pnpm still WebsiteDone-de-feed out/check.png --frame=40`
- One video: `pnpm render WebsiteDone-de-feed out/website.mp4`
- The whole library: `pnpm library` (= `node scripts/export.ts`; `--only <VideoId>`, `--formats feed,wide`,
`--page` to rewrite only post texts and the overview). Writes `out/library/index.html` (watch, copy the post
text, download) and `out/library/<language>/week-<n>/<slot>-<day>-<id>/` with the files and `post.txt`, in plan order.
- `pnpm typecheck`, `pnpm test`
Compositions are named `<VideoId>-<language>-<format>`: languages `en`, `de`; formats `feed` (4:5, LinkedIn),
`wide` (16:9), `square`, `story` (9:16). `out/` is gitignored and holds only two things: `out/library`
(what gets posted) and `out/tmp` (your check frames, sheets and logs; delete it when you are done).
## Where things are
- `src/content/videos.ts`: every word. Headlines per slide, the post text per video, both languages, and the
German for labels inside drawings (`LABELS_DE`). Drawing code writes labels in English; they are translated
when rendered. German addresses the viewer as "Sie".
- `src/compositions/<Video>.tsx`: the slides of one video (ids, durations, illustrations). No text.
- `src/slides`: `SlideDeck` (panel, headline, curtain, loop, portrait and 16:9 layout), `ServiceVideo`
(frame + language + deck), `ctaSlide` (closing slide with the button).
- `src/illustrations`: `parts.tsx` (tile, icon, cursor, data chip, window, page, badges, day box), `scenes.tsx`
(scenes several videos share), `motion.ts` (easing helpers).
- `src/brand`: tokens, fonts, `BrandFrame` (logo, labels, digit texture), `Panel` (the dark panel with the
website's light effects), `BrandButton`.
- `src/lib`: pure, tested logic (`bits.ts`, `aura.ts`).
## How to make a new video
1. Add the texts to `src/content/videos.ts` (new `VideoId`, both languages, post text).
2. Add `src/compositions/<Name>.tsx` with its slides and register it in `src/Root.tsx`.
3. Look before reporting: render the MP4, pull one frame per slide and read them, in `feed` and `wide`, in both
languages (German lines are longer). Do not hand over a video you have not seen.
4. `pnpm library --only <Name>` and tell the owner where the files are.
## Films (the current format, owner approved 2026-10-04)
Every video is a film in `src/films`: one continuous shot on a dark stage, not a deck of slides.
- Shared: `FilmStage` (backdrop, one centred statement at a time, signature, address) and `shot.ts`
(one timeline `T`, the camera move `cameraAt`, the six caption slots hook/reveal/problem/turn/calm/cta).
- The pattern: close on something abstract that looks like something else ("Looks like ping-pong."), the
camera pulls back and shows what it really is ("It's your office."), it stops, resolves, rests, and
returns to the opening picture so the film loops. Frame 0 is the preview image.
- Minimal and calm (owner feedback: earlier versions were hectic). Only squares, dots, lines and bars; no
icons or labels in the drawing. One statement of two short lines, held for about three seconds.
A little sarcasm in the hook is welcome. German has to read like a native wrote it.
- One font size per film: the largest at which the longest line fits, so keep lines short.
- The logo is the white signature (`public/logo-mark.svg`): bottom left, and very large and faint behind.
- The slide deck code (`src/slides/SlideDeck`, `src/illustrations`, `BrandFrame`, `Panel`) is no longer used
by any video and can be removed once the owner confirms.
## Image posts and the posting plan
- Image posts are made the same way as films: `src/content/images.ts` holds every word and, for a poster, which
film and frame it shows; `src/images/ImagePost.tsx` draws them. A poster is a film rendered at one frame with
two lines ("Not ping-pong. Your office."); a card is a client's question with the answer in large type.
Cards say only what the website says. Compositions: `<ImageId>-<language>-<feed|square>`.
- `src/content/plan.ts` is the posting plan (which film or image in which week); the reasoning is in
`apps/web/plans/content-strategy.md`. The spec checks that every film and image is planned exactly once
and that every video post opens with the hook of its film.
- `pnpm library` renders films and images and writes the overview page in plan order;
`--images`, `--videos`, `--only <id>`, `--page`.
## Rules
- Before any work: bring the worktree up to date with `main` (owner feedback, twice). Take wording, styles and
effects from the website as it is **now**: texts in `apps/web/src/content/de.ts` and `en.ts`, styles in
`apps/web/app/globals.css`, drawings in `apps/web/src/components/illustrations`. Do not state prices, terms
or durations that are not in the texts.
- Picture first, few words (owner feedback): 6 to 8 slides of about 2 s, each one large animated illustration
plus a headline of two to four words. No paragraphs, no captions.
- It has to look stunning (owner feedback, repeated: "not enough yet"). The videos carry every effect of the
website: the dark `Panel` with `BitAura` (light along the edge, digits drifting off), `BitGlow` (light over
the dot grid) and `bit-aurora` (indigo light drifting behind the drawing); slides change with the `BitCurtain`
(ragged front of digits, `src/lib/curtain.ts`); the button has the `bit-cta` light running round its edge.
When the website gets a new effect, bring it here as a pure function of the frame in `src/lib`.
- Drawings follow `PathScenes.tsx`: fine light lines, tinted glass surfaces (`DRAW.tint`, `DRAW.glass`) instead
of solid blocks, amber packets with a halo (`DRAW.mark`), emerald for done, soft glows on what is active.
- UI in a video must be the website's real UI, rebuilt faithfully (owner feedback): read the component in
`apps/web/src/components` first. The button is `BrandButton` (twin of `Button.tsx`); do not draw your own.
- Almost no frame (owner feedback: the drawing matters far more than what surrounds it). No border, no name,
no topic label, no progress bar. Only one small line at the bottom: the logo, small and dimmed, and
`www.mintel.me` (with `www.` so that it reads as an address). The stage is scaled as large as the frame allows.
- Light is drawn with plain gradients that fade to transparent. No `filter: blur`, `mix-blend-mode` or dashed
strokes for glows: they came out with hard edges in the rendered video (owner feedback).
- Every video loops: the first slide is complete on frame 0 (it is the preview image) and fades back in at the
end. Anything that moves outside the slides (`Panel`) must repeat exactly over the length of the video.
- Frame-driven only: all motion comes from `useCurrentFrame()` / `interpolate()`. No `setTimeout`,
`setInterval`, CSS animations, `Math.random()` or framer-motion: they do not render correctly frame by frame.
Pure logic goes in `src/lib` with a `*.spec.ts`.
- 30 fps, about 15 seconds. The video must work without sound and make sense in the first two seconds.
- Copy rules as on the website (see root `CLAUDE.md`): no AI as the owner's tool, no internal method vocabulary,
modest and factual, no promises the owner did not confirm. Never write the full email address.
- The hero design of the website (binary-digit headline) is approved: do not recreate it here with changes.