Quick Start
- Copy the whole folder to your web server (or any static host). There is no build step.
- Open
index.htmland replace the copy: masthead, issue number and dateline in the folio bar, the cover story, the index entries, contributors, stockists and prices. - Point the subscribe buttons (
.subscribe-actionsin the subscribe section) at your checkout, Stripe payment link, or mailing list. - Replace the cover photograph: drop your own image over
assets/img/cover.webp(1000 x 1250), or editassets/img-manifest.jsonand re-run the bake (see Images below). - Deploy. The page works with JavaScript disabled, so nothing else is required.
The GSAP scripts load from a CDN in index.html; swap assets/script.js for assets/script.min.js in production if you prefer the smaller file.
The two signature moments
The typesetting headline
The element carrying data-typeset (the cover <h1>) is split into glyphs and set letter by letter on load. Everything carrying data-after-set (standfirst, byline, column text, the photograph, the ear box) follows in DOM order.
- Change the headline: edit the text; the split adapts. Keep it under about 30 characters if you want it to finish quickly - the stagger is 0.038s per glyph.
- Slow it down / speed it up: in
assets/script.js, thestagger: 0.038andduration: 0.16values in the typesetting block. - Remove it: delete
data-typesetfrom the headline. The page falls back to showing everything immediately (thedata-after-setelements are then shown without the sequence).
The pull-quote reflow
Any .pull-quote inside a container carrying data-flow grows from 62% to full size on a scrubbed ScrollTrigger as it passes the top third of the viewport, and the CSS columns around it re-wrap live. The stylesheet size is the finished size - the script only starts them smaller - so no-JS and reduced-motion readers see the finished page.
- Add a quote: drop
<blockquote class="pull-quote">...</blockquote>anywhere inside adata-flowcontainer. Nothing else to wire. - Tune the growth:
setSize * 0.62(start size) and thestart/endpositions of the ScrollTrigger in the pull-quote block ofscript.js. - Why nothing jumps: each
data-flowcontainer is measured at finished-quote size on init and locked to that height withmin-height, so the sections below never move while a quote grows. A debounced resize handler re-measures.
Sections
Every section is independent: the script guards all its selectors, so you can delete any of these wholesale and the rest keeps working.
| Section | id | Notes |
|---|---|---|
| Folio bar + masthead + nav | (header) | Issue number, dateline, price; nav links are plain anchors |
| Cover story | #cover |
Headline (data-typeset), standfirst, two-column body (data-flow), photo, "ear" box |
| Features index | #index |
Column entries: folio, headline, standfirst, byline; two pull quotes in the flow |
| Contributors | #contributors |
Grid with vertical rules; editors' note beneath |
| Stockists | #stockists |
Recessed panel, mono list |
| Subscribe | #subscribe |
The red plate; price panel with two buttons |
| Colophon | (footer) | Ink plate: about, colophon, contact, back-to-top |
Palette
Three colours, declared once in :root at the top of assets/style.css, each with an RGB triple so every translucent value derives from a token:
Code snippet omitted: it ships with the download.
Change a hex, change its triple, and the issue reprints. --paper-deep is the recessed panel tone (the ear, the stockists band). The header comment above :root records the measured contrast table and its constraints - read it before adjusting: the red is pinned by small red type on the deep panel (5.03:1), and red type is banned on the ink plate (3.52:1, rules and ornaments only there).
Type
- Playfair Display - the metal: masthead, headlines, pull quotes, prices. Nothing else.
- Spectral - all running text, justified and hyphenated in the column flows.
- Inconsolata - the folio chrome: datelines, page references, bylines, captions, buttons.
All three load from Google Fonts in the <head>. If you swap faces, keep the roles: one display serif, one text serif, one mono for chrome.
Images
The single photograph ships as a baked, optimised WebP derivative - a near-monochrome, cool-toned print grade applied to the pixels, not a hotlink and not a raw original.
- Swap it: replace
assets/img/cover.webpwith your own 1000 x 1250 image (any 4:5 crop works; the<img>has explicitwidth/height). - Regenerate or re-grade:
assets/img-manifest.jsonholds the source URL, output size and grade. From the GSAP Vault repo:bun scripts/build-template-assets.ts indie-magazine-template.
The original is a royalty-free photograph from Unsplash, used here as an altered, art-directed derivative:
- The cover (croissants under falling flour, by Mae Mu) - https://unsplash.com/photos/two-brown-croissants-m9pzwmxm2rk
Accessibility
- Reduced motion: honoured twice - a CSS
prefers-reduced-motionblock and agsap.matchMediabranch. The reduced page is simply the printed page: headline set, quotes at display size, nothing moving, Lenis never created. A mid-visit preference change restores the static page. - No JavaScript: the complete page renders from plain markup; all animation start states are gated behind a JS-added
has-jsclass. - Keyboard: every interactive element is a real
<a>with a visible:focus-visiblestate mirroring its hover state; a skip link jumps to the front page. - Screen readers: decorative rules and the moon ornament are
aria-hidden; the cover photo has descriptive alt text; the ear box is a labelled<aside>.
Browser Support
Modern browsers (ES5 syntax, CSS columns, document.fonts). Not compatible with IE11.
Dependencies
- GSAP 3.14+ (core)
- ScrollTrigger plugin (reveals and the pull-quote scrub)
- SplitText plugin (the typesetting headline; free since GSAP 3.12)
- Lenis (optional - smooth scrolling; the page works without it)
All loaded from CDN in index.html. If any script fails to load, the page degrades to the finished static issue.
Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.