auteur

Design and build cinematic, award-level web pages.

  • web-design
  • cinematic
  • scroll-animation
  • design-system
  • anti-slop
  • frontend

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/optional-skills/creative/auteur'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md

Hermes adaptation note: upstream auteur generated assets through several local image CLIs. In Hermes, read every generation instruction as a call to the built-in image_generate tool with the same prompt (then move the returned file into the project's assets/gen/ path), use the terminal tool for ffmpeg/node/npx, and browser_exec or Playwright-via-terminal for screenshot loops. The per-CLI routing/strength tables below are upstream reference material — the taste guidance transfers, the CLI names do not.

scroll-flight — photoreal scroll-scrubbed video ("fly through the world")

auteur's video-scrub tier. The hero is a pre-rendered camera flight whose currentTime is driven by scroll — the viewer pilots a photoreal world. Complementary to the real-time WebGL recipes in scroll-cinema.md, not a replacement.

Engine: templates/scroll-flight-engine.js — a zero-dependency, framework- agnostic, drop-in scrubber. Vendored from scroll-world (github.com/cth9191/scroll-world, MIT © cyw); it solves ~18 shipped-in-anger edge cases you do NOT want to re-derive. Read its header for the full config API.

When to reach for this (vs WebGL scroll-cinema)

Use scroll-flight (video) when…Use WebGL scroll-cinema when…
the world must look photoreal — a real place, product, interior, landscapethe look is generative/abstract — fluid, particles, shaders, type
the motion is a camera flight through a fixed scenethe motion is procedural and reacts to cursor/audio/data live
you can generate/shoot video clips of ityou can express it as math in one WebGL context

They compose: a WebGL hero can hand off into a scrubbed-video mid-section.

⚠️ AI clips barely move the camera — the scroll-dolly does the travelling

The single most important thing to know here. image→video models (all the common ones) animate a still ambiently — light shimmers, water drifts, particles float — but they do NOT fly the camera through the scene. Verified on disk: a clip's first and last frame are near-identical. So a scene built only from a raw AI clip reads as a slightly-moving photo, not a journey. This is the #1 reason a scroll-flight looks like a slideshow.

The fix lives in the engine, not the prompt: scroll-flight-engine.js applies a scroll-driven camera dolly — as you scroll through a scene, it pushes the whole scene IN (scale) and drifts it down, inside the scale overscan so edges never reveal. That is what manufactures forward/descent travel; the clip's currentTime scrub only adds the ambient life on top. Consequences:

  • Don't over-invest in per-clip motion. A near-static clip + the dolly looks the same as an aggressively-prompted clip + the dolly. Prompt for mood and ambient life (drifting particles, light, creatures), not "fast camera dash" you won't get.
  • Stills and clips are interchangeable. A scene with only a still gets the same dolly, so it reads identically to a video scene. Mix freely — ship the clips you reliably get, fill the rest with stills, the dolly unifies them. (ABYSS showcase: 2 video scenes + 3 stills, indistinguishable.)
  • Pick worlds whose medium drifts — underwater, clouds, space, dust, smoke. Ambient drift hides the lack of camera-baked motion; a dry static landscape exposes it.
  • Real camera travel baked into the footage needs a true flythrough model (Higgsfield/Runway/Veo) or the 2.5D depth-parallax route (still → depth map → WebGL camera through the layers). The dolly is the pragmatic default that needs neither.

The pipeline (auteur's toolchain)

  1. Scene stills — one anchor still first, get art-direction approval, then batch the rest style-locked to the anchor (pass the approved still as the style reference). A style miss caught on the anchor costs 1 gen, not N. Source: image_generate — see assets.md.
  2. Dive clips — animate each still into a short camera push-in (any image→video model). One clip per scene.
  3. Seams — two ways, pick by what your video model can do:
    • Crossfade seams (default, start-image-only models). Leave connectors empty/null; the engine crossfades directly between adjacent dives. Ship-safe, always works, reads clean. This is auteur's baseline.
    • Seamless flight (only with an end-image model — Higgsfield seedance / kling). Generate connector clips whose start = prev dive's last frame, end = next dive's first frame (extract the actual rendered frames, never the stills). Verify every seam with the SSIM gate below before eyeballing.
  4. Encode for scrubbing (§ below) — the single most important step.
  5. Posters — extract each encoded clip's first frame (§ below).
  6. Wire the engine config; run the motion + slopscan gates.

auteur has no Higgsfield account by default; a start-image-only image→video model is the baseline. So the honest default is crossfade-seam photoreal scrub — still Apple-tier. Fully-seamless chaining is an upgrade you unlock only with an end-image-capable video model.

Encode for scrubbing — the -g 8 recipe (critical)

Scrubbing sets currentTime every frame; a decoder's seek cost scales with how many frames it must decode from the nearest keyframe. A tiny GOP (keyframe every 8 frames) is what makes frame-accurate seeking cheap. Native res, crf 20, no audio, faststart, light sharpen:

enc() { ffmpeg -v error -y -i "$1" -an -vf "unsharp=5:5:0.8:5:5:0.0" \
  -c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p \
  -g 8 -keyint_min 8 -sc_threshold 0 -movflags +faststart "$2"; }
  • Never upscale — encode what ffprobe reports (some models return 720p).
  • Mobile sibling (-m.mp4): 720p, -g 4 (twice the keyframes = ~half the seek-decode work), crf 23. Wire as clipMobile/connectorsMobile. Still choppy on a low-end phone → -g 2, or -g 1 (all-intra = instant seeks, bigger files).
  • The engine loads each clip as a Blob (always seekable) and scrubs — it does NOT rely on HTTP byte-range. Do not "optimize" that away, or you get frozen-at- frame-0 on hosts that don't serve ranges.

Posters — from the ENCODED clip's first frame

The still is 3:2, the clip is a 16:9 re-render — if the still is the loading poster, the video paints with a visible crop/render pop on the first scene a visitor sees. Hand off the actual frame:

ffmpeg -v error -y -ss 0 -i "$ASSETS/vid/$n.mp4" -frames:v 1 -q:v 2 poster.png
cwebp -quiet -q 84 poster.png -o "$ASSETS/$n-poster.webp"   # → sections[k].poster

Keep the source still too: it's the reduced-motion artwork and the no-clip fallback.

Seam QA — SSIM gate (before any eyeballing)

Seamlessness is the product; don't ship it on a squint. A true actual-frame handoff scores SSIM ≥0.95 even after encoding.

seam_ssim() { # clipA clipB  — last frame of A vs first of B
  ffmpeg -v error -y -sseof -0.05 -i "$1" -frames:v 1 _a.png
  ffmpeg -v error -y -ss 0      -i "$2" -frames:v 1 _b.png
  ffmpeg -v info -i _a.png -i _b.png -lavfi ssim -f null - 2>&1 | grep -o 'All:[0-9.]*' | cut -d: -f2
}
# ≥0.90 pass · 0.75–0.90 warn (crossfade usually hides it) · <0.75 FAIL:
# an endpoint was a still, not the neighbour's frame — regenerate, don't rationalize.

Re-run after every re-roll: replacing one clip can silently break BOTH its seams.

Chain architecture — A vs B

  • A — one continuous forward take. Legs chained from actual last frames, no pull-back, no end-image. Use for any grounded walkthrough. No rewind risk.
  • B — dive + connector interleave. More cinematic, but if a connector's camera velocity reverses (dive pushes in, connector pulls back out) it reads as a rewind even with a perfect frame-match seam. Inherent to B — keep connector motion continuing forward, or use A.

Mobile & iOS — the hard gotchas (the engine handles these; don't undo them)

  • Frozen / stuck at frame 0 → host isn't serving byte ranges → blob URLs (engine does).
  • Blank/black scene on iOS → a muted video never played won't paint a seeked frame. Engine keeps the poster up until a real frame paints and primes each clip (muted play→pause) on first touch. Don't hide the poster on loadedmetadata; don't strip playsinline/muted.
  • Frozen on iOS Low Power Mode → LPM rejects even muted play() and currentTime scrubbing dies — no video technique survives it. Engine detects the rejected prime and flips the whole page to stills-with-crossfades. Keep that .catch() fallback if you adapt it.
  • Phone stutters on a fast flick → seeks pile up. Engine coalesces seeks (never issues a new currentTime while seeking); ship the -m.mp4 tier as the other half.
  • iPad gets blurry 720p → tier by screen short side (≤600 CSS px = phone), never by pointer type or UA (iPadOS lies on both).
  • Page jumps while scrolling → the mobile URL bar fires resize; the engine ignores height-only resizes (relayout on width change / orientationchange).
  • Copy behind the notch/URL bar → engine uses env(safe-area-inset-bottom) + dvh; keep <meta viewport … viewport-fit=cover>.

Accessibility / SEO (auteur floor — enforced)

  • prefers-reduced-motion, data-saver → stills mode (no video load/decode), cross-dissolving as you scroll. Never blank.
  • The engine builds its DOM in JS, so put a plain-markup copy block marked data-sw-seo in the container — crawlers, link previews, and no-JS visitors read it; the engine hides it on mount. Readable with JS off.

Config pacing knobs

  • sections[k].scroll — per-scene scroll distance (more = slower dwell).
  • sections[k].linger (0..1) — remaps scroll→time so the camera settles mid-scene where the copy peaks and moves quicker at the seams. Keep ≤0.6.
  • diveScroll / connScroll, crossfade (seam dissolve width), scrollMobileFactor.

Upgrade path — canvas frame-sequence (Apple's actual technique)

For butter on low-end devices or when the blob payload (~8 MB × clips) is too heavy: pre-extract N frames per clip (webp/avif), draw to <canvas> (WebCodecs to decode ahead). Frame paint becomes deterministic — no decoder seek latency. The seam doctrine, chain math, and pacing knobs all carry over; only the "paint frame at time t" primitive swaps. More build tooling, more requests — reach for it only when video-scrub genuinely stutters on the target hardware.


Technique & engine adapted from scroll-world by cyw (github.com/cth9191/scroll-world), MIT. auteur pairs it with image_generate asset production and its own slopscan / motionqa gates.

Referenced from SKILL.md
SKILL.mdView in source ↗
Source excerpt starting at line 37.
- **Playwright (for the QA gates)** — in the project directory: `npm install playwright` then `npx playwright install chromium`. Required by `scripts/shoot.mjs`, `motionqa.mjs`, `systemscan.mjs`, `refscout.mjs`, `chromadiff.mjs`, `moodboard.mjs` (the scripts import `playwright` at runtime; `slopscan.mjs` and `source.mjs` are dependency-light).- **ffmpeg** — optional; only for the video/score paths in `references/assets.md` and `references/scroll-flight.md`.- **Hermes tools** — use `image_generate` for image generation/editing, `terminal` for node/ffmpeg/npm, `write_file`/`read_file` for project files, `vision_analyze` to actually look at screenshots, and `browser_exec` for live-page inspection when a script isn't the right fit.
SKILL.mdView in source ↗
Source excerpt starting at line 153.
- `references/scroll-cinema.md` — working code recipes: scroll-scrubbed video, canvas sequences, GSAP+Lenis foundation, CSS scroll-driven animations, text reveals, the two-keyframe WebGL displacement transition, view transitions, ambient audio, and the cinematic transition library (wipe, curtain, letterbox, shutter, depth parallax). Load during assembly.- `references/scroll-flight.md` — the **video-scrub tier**: a photoreal "fly through the world" hero driven by scroll, using the drop-in `templates/scroll-flight-engine.js`. The canonical recipe for scroll-scrubbed *video* (encode-for-scrubbing `-g 8`, encoded-frame posters, SSIM seam gate, chain architecture A/B, iOS/mobile decode hardening, crossfade-vs-seamless seams). Load when the hero should be photoreal footage/AI-video rather than real-time WebGL.- `references/ambient-backgrounds.md` — **quiet** texture for secondary sections and simpler builds (not a hero): a curated 6 editorial/analog effects (paper grain, ledger/blueprint rules, topographic contour, ink tide, sparse dust, one heat-haze shader) + a zero-motion static-mesh default. The governing rule (weaker than the quietest foreground element; one ambient per page), the CSS/SVG-first stack, and the `feTurbulence`-static perf rule. Load when a section needs to not be flat but must NOT compete with copy.