Scroll Video

A video that plays frame by frame as you scroll through a pinned stage, with lines of copy that take turns over it.

  1. One body, milled from brass.
  2. A grip that finds your hand.
  3. Seven parts. Every one replaceable.
import { ScrollVideo } from '@brand-studio/ui';

export default function ScrollVideoDemo() {
  return (
    <div style={{ width: '100%' }}>
      <ScrollVideo label="The Halden R turning, then coming apart into its parts" src="/videos/halden-turn.mp4" poster="/videos/halden-turn.jpg" length={320} steps={[
        { at: 0, text: 'One body, milled from brass.' },
        { at: .35, text: 'A grip that finds your hand.' },
        { at: .72, text: 'Seven parts. Every one replaceable.' },
      ]} />
    </div>
  );
}

Installation

pnpm add @brand-studio/ui

Usage

import { ScrollVideo } from '@brand-studio/ui';
<ScrollVideo label="The Halden R turning, then coming apart" src="/turn.mp4" poster="/turn.jpg" length={320} steps={[
  { at: 0, text: 'One body, milled from brass.' },
  { at: .72, text: 'Seven parts. Every one replaceable.' },
]} />

length is the scroll distance in viewport heights. Each step shows from its at point, between 0 and 1, until the next one. Encode the video with a keyframe on every frame so it seeks without stalling:

ffmpeg -i turn.mov -c:v libx264 -crf 27 -g 1 -movflags +faststart -an turn.mp4

Accessibility

  • The section is labelled, and so is the video; describe what it shows in label.
  • Before scripts run, and under reduced motion, it is an ordinary muted video with controls and the steps as a list.
  • The steps are real text over the video; keep them short and check their contrast against every frame.

API Reference

PropTypeDefault
srcstring–
poster?string–
labelstring–
steps?ScrollVideoStep[]–
length?number300
className?string''

Still, Deskhand and Hollis are fictional brands. The coffee photographs are original generated artwork. @brand-studio/ui is MIT licensed.