Quick Start
1. Add to your HTML <head>:
Code snippet omitted: it ships with the download.
2. Add sections to your <body>:
Code snippet omitted: it ships with the download.
3. Add before closing </body>:
Code snippet omitted: it ships with the download.
Using It With Your Own Design
Each [data-story-flow] owns one [data-story-stage], one [data-story-line] and one [data-story-frame]. Put two [data-story-picture] figures inside the frame, each with an image. One picture also works, with no changeover. Keep the outer section height-free: ScrollTrigger supplies pin spacing.
The script adds .is-story-live only when the motion setup succeeds. That class makes the stage one viewport tall, puts the sentence on a single line, and stacks the photographs. Keep those structural rules, the clipping on the stage/frame, and the line's width: max-content. The script measures the line after fonts load and again when the viewport changes. The text stays intact and can include emphasis; it is not split or replaced.
The header labels, three colour themes, body copy and photography are demo content. Replace them freely. The sentence should be wider than the viewport for meaningful travel. Its resting left/right clearance is 6% of the stage width; keep the .story-type-window padding in step with the script's inset() if changing that clearance.
Base styles form a normal photo essay, with wrapped headlines and both pictures visible. Preserve that base layout: it is used without JavaScript, after teardown, and under reduced motion. Avoid putting links or controls inside the moving line or overlapping pictures; place controls in the static section copy instead.
Options
| Attribute | Values | Default | Description |
|---|---|---|---|
data-story-flow |
Present | — | Owns one pinned scene. |
data-story-stage |
Present | — | The viewport-sized element to pin. |
data-story-line |
Present | — | The intact single-line heading that travels horizontally. |
data-story-frame |
Present | — | Clipped image frame. |
data-story-picture |
Present | — | Photo layer; the second wipes upward over the first. |
data-story-direction |
left, right |
left |
Direction the sentence travels during forward scrolling. |
data-story-distance |
100–600 |
220 |
Minimum pin distance as a percentage of viewport height. Longer sentences can extend it automatically. |
data-story-lean |
0–6 |
2 |
Maximum additional velocity skew in degrees; 0 disables it. |
data-smooth |
off |
Enabled if Lenis is loaded | Set on <html> to disable optional smoothing. ?smooth=off also works. |
Easing and Scroll Timing
storyGlide is a CustomEase curve (0.25,0.18,0.32,1) that starts the sentence moving immediately, then accelerates and eases into its landing. storyUnfold (0.16,1,0.3,1) opens the photo crop and settles the velocity response. Without CustomEase, the script uses built-in GSAP eases.
The sentence starts moving as soon as the pin engages, with a small reading beat only at the end. The photo frame grows from its initial inset to fill the viewport across the pin. The second image wipes in across the middle of the timeline, while both images slowly shift and scale inside their crops. Text sits above the imagery; a viewport-aligned shade rises as the photograph reaches it. The numeric scrub (0.55) softens changes in scroll position without playing an independent timed slideshow. Reverse scrolling reverses the same sequence.
Accessibility
Reduced motion uses the static photo essay: no pinning, horizontal text clipping or smooth scrolling. Both photographs and the full wrapped sentence are available. Changing the preference live reverts or recreates the animation.
Without JavaScript or GSAP, the original page remains readable. Headings keep their semantic markup and images have descriptive alt text. Keyboard scrolling works with the document; the effect adds no arrow-key controls or slide navigation. As photographs expand behind the text, a graduated shade protects the heading and supporting copy. The lower-right image area stays clear.
Photography
The demo includes six locally optimised WebP photographs: architecture, ceramics, a loom, shoreline and forest. Sources are recorded in assets/img-manifest.json using the project's curated stock library. Replace the files and alt text with your own images when adapting the story. Explicit image dimensions reserve the layout without waiting for downloads.
Dependencies
- GSAP 3.15.0 and ScrollTrigger; compatible with GSAP 3.12+.
- CustomEase for the supplied curves, with built-in easing fallbacks.
- Lenis 1.3.17, optional.
- Mona Sans from Google Fonts in the demo; a system sans-serif fallback is provided.
Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.