040

Long-Form Story Template

£10

A one-page long read laid out for reading: a single 68-character measure on a pale celery ground, a sticky chapter spine with a scrubbed plum progress thread, inline-SVG figures that break the column, and four principle cards that stack into a deck as the section pins.

ScrollTrigger Lenis intermediate
6 more details
scroll-stackpinningscrollspysvg-drawscroll-revealreading-progress
Long-Form Story Template - website template preview

This template reads better at your own screen size than in the frame below:

About this template

A production-ready one-page site for a single long read, built around a reading experience rather than a business type. It ships as a fictional publication, Fieldnote, carrying a first-person account of rebuilding a small manufacturing workshop over four years, so what you open is a finished article and not a skeleton with placeholder headings.

Read the full template overview

The page is one ground and one measure throughout: pale celery paper, near-black ink, a plum accent that is dark enough to carry body copy, and a single raised card surface. Prose sits at a real reading size in a column of about sixty-eight characters, and the only things allowed out of that column are two figures drawn entirely in inline SVG, a plotted quarterly timeline and an annotated section through the workshop.

Two pieces of behaviour carry it. A sticky chapter spine runs down the left margin above 1100px, its tick expanding and its chapter name unfurling as you pass, with a plum thread that fills the rule as you descend; below 1100px the spine becomes a slim fixed progress bar at the top of the viewport. Then the principles section pins and its four cards stack over one another, each incoming card sliding up, overshooting a few pixels and settling while the cards beneath scale down, dim and lean in sequence, so a visible deck builds under your thumb.

Making it yours is a copy job and a four-value repaint. Replace the article text, the chapter titles and the two figures' data; change the four colour tokens and their RGB triples in the token block and the whole page reskins with no stray literals left behind. Every section is found by a data attribute and guarded, so a buyer can delete the figures, the principles, the evidence table or the endnote and the rest still runs.

What's included

10 items
  • A complete long read as shipped copy: opening with a hairline meta rule, four chapters of real prose with a drop cap, a stacking principles section, two pull quotes with a five-row ledger, endnote, about block and footer
  • Signature scroll stack: the principles section pins and four cards build into a deck, the locking card overshooting and relaxing while the cards beneath compress in a stagger and a live counter reports the position
  • Sticky chapter spine above 1100px with real anchor links, an expanding tick, an unfurling chapter name, and a plum reading thread that fills as you read, with no extra plugin
  • Slim fixed reading-progress bar below 1100px, whose real height is what the pinned section starts below, so the deck is never hidden underneath it
  • Two designed inline-SVG figures that break the reading column: a plotted quarterly timeline with a called-out event, and an annotated cross-section with dimensions, a hatched ground and a scale bar
  • One measure everywhere, set as a token: prose at a real reading size in about sixty-eight characters a line, with a three-column grid that lets a figure break out without a negative margin
  • Four-token palette with RGB triples and every measured contrast ratio written into the stylesheet header, so a reskin is four values and a reader never lands on unreadable type
  • Hairline-ruled data table with a real caption and row headers, scrollable on a phone rather than crushed
  • Lenis smooth scrolling wired in, kept in lockstep with the pinned stack, anchors routed through it, and entirely optional
  • Accessible throughout: the stack degrades to a plain readable list with no JavaScript, under reduced motion and on viewports too short to hold a deck; following a spine link moves keyboard focus into the chapter; every figure has a title and description

Perfect for

6 use cases
  • Company or founder stories that need to read as an essay rather than an about page
  • Case studies and project write-ups where the argument matters more than the screenshots
  • Research summaries, white papers and technical write-ups with charts and diagrams in the flow of the text
  • Annual reviews and impact reports that want figures inside the prose instead of a slide deck
  • Independent publications and newsletters publishing one long piece at a time
  • Product stories and manufacturing or process pieces where a timeline and a schematic do the explaining

How it works

5 sections

Structure

One script initialises every section with a single setup and teardown path and one motion branch, keyed on motion preference, width and viewport height so exactly one branch runs on every device including a phone. Each section is found by a data attribute and guarded, so deleting the figures, the stack, the table or the endnote leaves everything else working. The whole page is a complete static document before any script runs: the article, the figures and the four cards are all markup.

The reading chrome

A single ScrollTrigger spanning the article drives both the spine thread and the mobile progress bar. The thread is a plain SVG path that fills from empty to full as you read, with no drawing plugin involved. A second set of triggers, one per chapter with contiguous bands, marks the current chapter: exactly one is ever current, so jumping straight to an anchor still lands inside a band.

The card stack

The stage pins below the fixed progress bar, adapting to the bar's real height rather than assuming it, and a scrubbed timeline slides each card up into place. The locking card overshoots four pixels and relaxes; the cards already locked drop one depth level each, scaling, dimming and leaning with a small stagger so the deck compresses in sequence rather than snapping as a block. Every distance is recalculated when the page resizes, everything moves in the same units, and the first card stays in normal flow so the deck takes its height from real content rather than a guess.

Reduced motion and short screens

The plain vertical list of four cards is the default, in both the markup and the CSS; the pinned deck is a class the script adds. So a reduced-motion visitor, and anyone on a viewport too short to show a card with the deck behind it, gets the readable list instead of a frozen pin, and the depth offsets and number of visible cards are reduced below 700px so the deck can never overflow a phone. Reading progress and the chapter spy still run in the reduced-motion branch, because they report position rather than animate.

Without JavaScript

The gating class goes on in the head before first paint, so reveal start states apply to the first frame and nothing is painted visible and then hidden; the script removes that class if GSAP is missing, so a blocked CDN degrades to the plain document rather than hiding content forever. With scripting off the chapter spine is still a working list of anchor links with its thread drawn full, the progress bar is hidden rather than left empty, the cards are a plain list, and both figures render exactly as drawn.

Plugins ScrollTrigger
Difficulty Intermediate
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this template's demo, 9 September 2026. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Questions about this template

Is the shipped copy real writing or lorem ipsum?

Real prose: four chapters, a drop cap, two pull quotes, a five-row ledger, an endnote and an about block. That matters more here than elsewhere, because you cannot judge whether a long-read layout works against placeholder text. You are replacing words, not inventing structure.

What happens on a short laptop screen where a pinned deck will not fit?

It degrades to a plain readable list, on viewports too short to hold a deck, under reduced motion, and with JavaScript off. That short-viewport case is a genuine failure mode for pinned card stacks and it is handled rather than assumed away.

Can I put charts and diagrams in the text?

Yes, and two ship as designed inline SVG that break the reading column: a plotted quarterly timeline with a called-out event, and an annotated cross-section with dimensions, hatched ground and a scale bar. The three-column grid lets a figure break out without a negative-margin hack.

Is the reading measure actually set for reading?

Yes, one measure everywhere as a token: about sixty-eight characters a line at a real reading size. The four-token palette has every measured contrast ratio written into the stylesheet header, so a repalette cannot quietly leave a reader on unreadable type.

What is the sticky chapter spine, and does it appear on mobile?

Above 1100px you get a spine with real anchor links, an expanding tick, an unfurling chapter name and a plum reading thread. Below that it becomes a slim fixed progress bar, and its real height is what the pinned section starts below, so the deck is never hidden underneath it.

Paid template

Purchase to unlock the code.

Buying Long-Form Story Template opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects.

£10 Standard license, unlimited projects

Browse free effects

Documentation

Quick Start

  1. Copy the whole folder into your project. It is static, no build step, no bundler.
  2. Open index.html and replace the copy: the publication name (Fieldnote), the piece (The Slow Build), the byline and meta rule, the four chapters, the four principle cards, the two pull quotes, the table, the endnote and the about blocks.
  3. Update the two figures. Both are plain inline <svg> in index.html with commented groups, see The figures below.
  4. Update the chapter spine to match your chapters, see The chapter spine.
  5. Deploy the folder as-is. GSAP and Lenis load from a CDN; nothing else is required.

The scripts at the end of <body>:

Code snippet omitted: it ships with the download.

This one line in <head> is load-bearing, keep it:

Code snippet omitted: it ships with the download.

It runs before the first paint, so the reveal start states apply to the very first frame and nothing is painted visible and then hidden. assets/script.js removes the class if GSAP failed to load, so a blocked CDN degrades to the plain document instead of hiding content forever.

Sections & options

Every section is found by a data-* hook and guarded independently, so you can delete any one of them and the rest still runs.

Section Hooks the script reads Notes
Reading progress bar [data-bar], [data-bar-fill] Fixed, below 1100px only. Its measured height is what the pinned stack starts below, so restyling it needs no code change.
Chapter spine [data-spine], [data-thread], [data-spine-link] 1100px and up. Real <a href="#chapter-n"> links.
Article [data-article] Wraps everything; the reading progress spans it, top to bottom.
Opening [data-opening], [data-open] [data-open] elements rise together on load.
Chapters [data-chapter], [data-chapter-title] One [data-chapter] per chapter, in document order, that order is what the spine's links are paired against. [data-chapter-title] carries tabindex="-1" and takes focus when its spine link is followed.
Figures n/a [data-reveal] only. The plate carries data-lenis-prevent so the wheel scrolls it sideways.
Principles [data-stack], [data-stack-stage], [data-stack-deck], [data-pcard], [data-stack-step] The signature. See below.
Evidence [data-evidence], [data-reveal] Two pull quotes and the ledger. The table wrap carries data-lenis-prevent.
Close [data-close], [data-reveal] Endnote, about blocks, footer.
Any element [data-reveal] Fades and rises once as it enters the viewport. Add it to anything; it is pre-hidden in CSS under .has-js and restored under reduced motion.

Layout classes worth knowing, all applied to a direct child of a .column section:

Class Effect
(none) Sits in the reading column. This is the default.
.wide Starts at the reading column's left edge and runs out to the right margin. Used by the title, the meta rule, the table and the about block.
.full Spans the whole shell. Used by the masthead rule, the figures and the footer.

The chapter spine

Add or remove a chapter in three places, and nothing else:

  1. a <section class="chapter column" id="chapter-N" data-chapter> in #chapters;
  2. an <li> in .spine-list whose <a href="#chapter-N" data-spine-link> matches that id;
  3. the chapter count in the opening's meta rule.

The script pairs them by document order, so the Nth spine link tracks the Nth [data-chapter]. Each chapter is current from the moment its top passes 45% of the viewport until the next chapter's does, which is why exactly one is ever current and why jumping straight to an anchor still lands inside a band.

The thread is a plain <path> carrying pathLength="1". That normalises its dash units, so the script only sets stroke-dashoffset between 1 (empty) and 0 (full) and never has to measure the path, no drawing plugin is involved. If you change the spine's height in CSS, change the viewBox height and the y2/V values to match and the thread still works.

To move the spine, edit left and --spine-w in the @media (min-width: 1100px) block. --spine-w is also the left padding on .page, which is what keeps the full-width figures from running underneath the spine, keep the two in step.

The principle stack

The plain vertical list is the default, in both the markup and the CSS. The script adds .is-stacked to [data-stack] to switch it into the pinned deck, so a no-JS visitor, a reduced-motion visitor and anyone on a viewport shorter than about 420px all get the readable list rather than a frozen pin.

In stacked mode the stage pins below the progress bar and a scrubbed timeline runs one segment per card. Each incoming card slides up from below the stage, overshoots four pixels and settles; every card already locked drops one depth level, scaling down, dimming and leaning, each 0.07 behind the last so the deck compresses in sequence.

Tuning lives in one object near the top of initStack in assets/script.js:

Code snippet omitted: it ships with the download.

Key What it does
scale How much smaller each level down is. Past about 0.06 the deck reads as a fan, not a stack.
lift Pixels each level peeks above the card in front.
lean Degrees of rotation per level.
fade Opacity lost per level.
visible How many levels stay legible; anything deeper fades to zero. This is a contrast setting, not a taste one, at fade: 0.18 a third level would sit at 46% opacity, which is below the readable floor for the card's body copy.

Add or remove cards by adding or removing <article class="pcard" data-pcard> blocks. Nothing is paired by index; the script counts what it finds, sizes the travel from that count, and the counter ([data-stack-step]) follows.

Two things to leave alone unless you know why they are there: the first card keeps position: relative in stacked mode so the deck's height is a measured card height rather than a guessed one, and every card moves on pixel y rather than a mix of y and yPercent, because a card is an incoming card once and a deck card three times and mixing the two units leaves a parsed pixel offset behind that never clears.

The figures

Both are hand-authored inline <svg> in index.html, with a <title> and <desc> referenced by aria-labelledby, and both are styled entirely from assets/style.css (the .fig-* and .sch-* classes) so they repaint with the palette.

  • Figure one, the plot. Sixteen quarterly points. The plot area is x 96 → 828 and y 44 (100 units) to 272 (0), so a value maps to y = 272 − value × 2.28 and the ith quarter to x = 96 + i × 48.8. Change the numbers in the points list, the matching <circle>s, and the d of .fig-area (same points, closed along the baseline).
  • Figure two, the section. A cross-section drawing: shell, mezzanine and stair, a column, stock on stillages, the oven on its plinth, a drain, a dashed flood line with a dimension, and a scale bar. Groups are commented. .sch-solid is built structure, .sch-line is drawn object, .sch-dim is dimensions, and the ground hatch is a real <pattern>.

Below 700px the plate scrolls sideways rather than shrinking the labels away, and says so in the caption.

Palette

Four colours. Everything else on the page is one of them at another alpha, so a reskin is four values plus their RGB triples, keep each triple in step with its hex or translucent rules and dimmed type will stay mixed from the old colour.

Code snippet omitted: it ships with the download.

There is one ground. The page does not alternate tones band by band, and the fixed chrome is not inverted; the only other surface anywhere is --card, used by the four principle cards.

Measured contrast, as used

Pair Ratio Where
--ink on --celery 13.8:1 all prose, all headings
--plum on --celery 9.0:1 drop cap, pull quotes, links, card meta
--ink on --card 15.6:1 principle card copy
--ink @ .78 on --celery 7.3:1 standfirst, figure captions, about copy
--ink @ .70 on --celery 5.6:1 labels, meta, table headers
--ink @ .68 on --celery 5.3:1 spine chapter names
--ink @ .82 on --card 9.0:1 deck, one card down
--ink @ .64 on --card 4.9:1 deck, two cards down
--card on --plum 10.2:1 selection highlight

The contrast floor for dimmed ink on this ground is .70. At .64 it measures 4.7:1 and below that body copy fails AA, which is also why the deck stops dimming after two levels and fades the third out entirely.

Unlike a lot of accents, plum is dark enough to carry body copy at 9.0:1, so it is used as a real type colour: the drop cap, both pull quotes, the footer links and the card meta lines. If you swap it for something lighter, measure it before letting it carry small text.

Non-text marks: the spine's inactive ticks are --ink @ .55, which is 3.6:1 and clears the 3:1 bar for marks. The rule the progress thread runs in is background rather than information, the plum thread inside it is what reports the reading position, at 9.0:1.

Accessibility

  • Reduced motion: handled twice, in a @media (prefers-reduced-motion: reduce) block and in a gsap.matchMedia branch. Nothing pins, the four cards stay a plain readable list, and every reveal target is held visible. The reading progress and the chapter spy still run, because they report position rather than animate.
  • No JavaScript: every word on the page is readable. The spine is still a working list of anchor links (with its thread drawn full), the progress bar is hidden rather than left sitting empty, the cards are a plain list, and both figures render exactly as drawn.
  • Short viewports: if the viewport cannot hold a card with the deck behind it, the stack simply does not build. Nothing is ever cut off by the pin.
  • Keyboard: the spine items are real links with a visible :focus-visible ring, and following one moves focus to the chapter heading as well as the viewport, so you land in the prose rather than staying parked in the margin. The unfurling chapter name is clipped, never hidden, the chapter number stays visible, and hover or focus opens any name.
  • Figures each have a <title> and a plain-language <desc>, referenced by aria-labelledby, so the shape of the data is available without seeing the drawing.
  • The table uses a real <caption>, <thead>, and scope on both column and row headers.
  • The stack's decorative position counter is aria-hidden; all four cards are in the document and readable regardless of the deck's state.

Dependencies

  • GSAP 3.15.0 core and ScrollTrigger. Nothing else, the progress thread is plain stroke-dashoffset, not a drawing plugin.
  • Lenis 1.3.17 smooth scroll, optional. Remove the lenis block in assets/script.js and the CDN tag to drop it. While it is present it is wired to ScrollTrigger.update, without which the pinned stack jitters a frame behind, and anchors: true routes the spine's links through it.
  • Google Fonts: Frank Ruhl Libre (display), Lora (body), Sofia Sans Condensed (labels and chapter meta).

assets/script.min.js is the minified build of assets/script.js. Edit the readable file and re-minify, or just point the <script> tag at script.js.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.

Your cart

Your cart is empty

The Vault £99

Everything in the catalogue, plus everything we release next.