059

Parallax Scroll Template

£20 or the whole Vault, £79.20

A nature-led one-page site for a national trail, outdoor brand or landscape project: four full-bleed photographs pinned into a scroll-scrubbed journey, a live type specimen you type into, and a lens that samples the palette off a hillside.

ScrollTrigger Lenis advanced
10 more details
pinningscrubparallaxmask-revealcount-upsvg-line-drawcanvaspointer-effectstext-animationscroll-reveal

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

Updated

About this template

Wending is a complete one-page site for a long-distance trail, told the way a brand foundations site tells a type system: one word at fifteen viewport-widths, bracketed labels, a cool mist ground alternating with a near-black field, and photography that runs edge to edge rather than sitting in frames. It is not built for one business. The fiction is a coast-to-summit national trail, and the same page reskins to an outdoor brand, a national park, a landscape photographer, a conservation trust or an expedition with the copy and the twelve photographs changed.

Read the full template overview

Three interactions carry it, each on a different input. Scrolling walks four full-bleed chapters through one pinned frame: the next photograph settles over the last as it drifts away, the chapter name rises through its mask, the altitude and the mile count up, a route line at the foot draws to the next stop, and at the summit the frame whites out to the page ground. Typing sets your own words in the trail's typeface at display scale, with the variable font's width and weight axes on tabs, the size fitting the line and the photograph behind darkening as it fills. Pointing a lens at a photograph of a headland samples the pixel under it live into a swatch with its hex, with five named points on the hillside to jump to.

Everything is static HTML, CSS and one script: no build step, no framework, one typeface. Repaint the five values in the token block to reskin it, drop your own photographs into assets/img, and rewrite the copy. Every section is independent, so any of them can be deleted without touching the JavaScript, and without JavaScript at all the four chapters stand as four full-height panels.

Parallax Scroll Template - website template preview

What's included

10 items
  • Pinned four-chapter journey: full-bleed photographs scrubbed through one frame with masked chapter names, a live altitude and mile counter, a drawing route line and a whiteout to the page ground at the summit
  • Live type specimen: a contenteditable line at display scale with the variable font's width and weight axes on tabs, size that fits the line as you type, and a shuffle of lines from the brand
  • Colour lens: a pointer-driven lens samples the photograph beneath it into a swatch with its hex and a name, drifts home with an elastic settle, and jumps to five named points from chips or the photograph itself
  • Scroll parallax across an offset six-frame photography grid, one frame bled off the edge
  • Type is the composition: one variable family (Mona Sans) at a 16:1 ratio between display and fine sizes, bracketed labels and a two-word nav whose Index opens the site map as a full-screen overlay menu
  • Twelve baked WebP photographs, graded as one set, 1.5MB in total, with a manifest to regenerate them from your own
  • Cool mist ground and near-black field with every translucent value mixed from RGB triples, so a reskin is a five-value edit
  • Designed reduced-motion page: the journey lays out as four stacked full-height chapters, the lens and chips still sample, the tabs still set the axes
  • Readable with JavaScript disabled or the CDN blocked, every chapter, table row and caption included
  • Lenis smooth scroll wired on the shared GSAP clock, opt-out per page or per URL

Perfect for

6 use cases
  • National trails, long-distance paths and outdoor route guides told chapter by chapter
  • Outdoor and landscape brands whose product is a place rather than an object
  • National parks, nature reserves and conservation trusts with strong photography
  • Landscape and travel photographers presenting a single body of work as a journey
  • Brand foundations and design-system microsites that need a type specimen and a palette page with real interaction
  • Expedition, retreat and slow-travel projects that sell time in a landscape

How it works

5 sections

Structure

One script, one setup and teardown path, one init function per section, each returning early when its markup is absent, so any section can be deleted. A synchronous head script adds .has-js before first paint so the reveal gates apply without a flash, and the main script removes it again if the CDN is blocked. The nav is in the flow at the top of the page rather than fixed, so it never sits over a chapter photograph; its Index link opens the site map as a full-screen overlay, with focus moved in and back out, Escape to close, and the footer carrying the same list for visitors without JavaScript. In-page links are scrolled by the script rather than the browser, because a native hash jump to a pinned section lands at the pinned element's current position, not the section's start; the chapter rows carry data-jump-chapter so each lands on its own chapter.

The journey

The four chapters are complete panels in the markup: a full-bleed photograph, a name, an altitude, a mile and a paragraph each. With motion allowed the script adds a stage class that stacks them into one 100vh frame, pins the section, and drives one scrubbed timeline with a unit per transition. Each unit moves the leaving photograph up and out at a larger scale, fades the arriving one over it while its scale settles, masks the old name out through the top and the new one in from below, tweens a counter object for the altitude and mile, and extends the route line's x2 to the next stop. A final 0.7 of a unit scales the last photograph while a mist-coloured layer fades to full, so the unpin lands on a page the same colour as the frame. The pin is budgeted at 0.85 viewports per transition.

The type specimen

The line is a contenteditable paragraph. On input the script counts characters, fits the size (full size to 26 characters, then shrinking on a square root down to a third of the base) and darkens the photograph behind in proportion, all through one tweened state object. The width and weight tabs tween two custom properties, --wdth and --wght, which font-variation-settings reads, so the variable font moves smoothly between Narrow and Wide or Light and Bold rather than snapping. Paste is forced to plain text, Enter is swallowed so the line stays a line, and the tabs support arrow keys.

The colour lens

The photograph is drawn once to a hidden canvas at natural size. The lens position is a fraction of the field held in a small object that a short overwriting tween eases toward the pointer on fine devices, and every update maps that fraction back through the object-fit cover crop to a pixel, averages a 13-pixel block around it, and paints the result into the swatch through a tweened RGB object. Leaving the field lets the lens drift back to the last named point on an elastic ease; a tap or click moves it; the chips and the buttons on the photograph jump to fixed points. If the canvas is tainted by a cross-origin image the chips fall back to their stored hex values.

Without JavaScript or motion

Without the script the page is a plain document with the four chapters stacked as four full-height panels, the specimen showing its sample sentence, and the swatch painted with the first named colour. Under prefers-reduced-motion the CSS restores every gated element and keeps the stacked chapter layout, the script's own motion branch skips the pin, the parallax and the hero timeline, and the specimen tabs and the colour chips still work with their changes applied instantly.

Plugins ScrollTrigger
Difficulty Advanced
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, from the latest scan. 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

It's a walking trail in the demo. What else does this design suit?

Anything sold on a landscape and photography rather than a product: an outdoor clothing brand, a national park, a conservation trust, a retreat, an expedition, a landscape photographer's portfolio. The fiction is four chapters of a trail, but the chapters are just four photographs with a name, a number and a paragraph each, so they become four collections, four seasons, four regions or four projects by editing the text. Nothing in the layout says 'trail' except the words.

Can I use my own photographs, and what happens to the twelve included?

Yes. The twelve are graded WebP derivatives of Pexels photographs, bundled for the demo, and you can ship them or replace them. Drop your own files into assets/img with the same names, or edit assets/img-manifest.json with your sources and run the bake script to get matched, optimised WebP with one grade across the set. Full-bleed chapter images want to be about 1920 pixels wide; the grid frames 900 to 1200.

How do I change the four chapters, or have three or five?

Each chapter is one article block in index.html with its photograph, name, altitude, mile and paragraph. Copy or delete a block. The pin length, the counter, the route stops and the whiteout all read the number of chapters and their data-alt and data-mile values, so there is nothing to retune. Three chapters is the fewest that still reads as a journey; six is the most before the section becomes the longest stretch of the page.

Does the typing section work on a phone?

Yes. It is an ordinary editable line, so the keyboard opens when it is tapped, the size fits the text as it is typed, and the width and weight tabs are buttons large enough for a thumb. The five named colours in the colour section work by tap, and a tap anywhere on the photograph moves the lens and samples there. Only the follow-the-cursor behaviour is reserved for a mouse.

Can I change the typeface, given the whole page is built on one?

You can, but pick a variable font with a width axis if you want the Narrow and Wide tabs to do anything; without one they still work as weight tabs and you can delete the width row. Mona Sans is loaded from Google Fonts with both axes in one request. The page runs on the ratio between the largest and smallest sizes rather than on any face in particular, so a different grotesk or a serif keeps the composition.

Is there any form, booking or shop to wire up?

No. There is no form on the page at all, so nothing submits to nothing. The footer links to 'Plan a walk', 'Bothies' and 'Tide tables' are placeholders pointing back to the top; point them at your own pages, a booking tool or a PDF. If you add a contact form it will need a handler such as Formspree or Netlify Forms, because this is static front-end only.

How do I recolour it?

Five values in the token block at the top of style.css: the mist ground, the dark field, the ink, the chalk and the one green, each with its RGB triple beside it. Every rule, scrim, dimmed label and focus ring is mixed from those, so nothing is left in the old colour. The contrast figures for each pair as used are written in the same comment, so if you lighten the ground you know which alpha to raise.

Paid template

Purchase to unlock the code.

Buying Parallax Scroll 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. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£20 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £79.20, one payment.

Documentation

Quick Start

1. Upload the folder. index.html, assets/style.css, assets/script.js (or assets/script.min.js) and assets/img/ are the whole site. Any static host will do.

2. Check the <head>. Three things must stay, in this order:

Code snippet omitted: it ships with the download.

That one-line script must stay synchronous and stay in <head>. It is what stops every reveal target painting visible for a frame and then flashing to zero. data-cfasync="false" stops Cloudflare Rocket Loader deferring it, which would bring the flash back on the live site only.

3. Keep the scripts before </body>:

Code snippet omitted: it ships with the download.

4. Rewrite the copy and swap the photographs. Everything else is optional.


Sections and their options

Each section is initialised by its own function and every one returns early when its markup is missing, so you can delete any section from index.html without touching the JavaScript.

Section Hook What you can change
Nav .site-nav Two links, in the flow at the top of the page. "Index" opens the overlay below; without JavaScript its href goes to the footer's copy of the same list.
Index overlay data-index-menu The site map as a full-screen menu: the list in [data-index-list] (edit the links; keep them as plain #id hrefs), a short paragraph and the four chapter thumbnails in [data-index-side]. Escape, the Close button or any link closes it.
Hero data-hero The giant word is .word-line; keep it to one word or two short ones, because it is set at fifteen viewport-widths. The sub line, the lede and the data row are plain text.
The journey data-journey One article[data-chapter] per chapter, each with data-alt (metres) and data-mile. Add or delete chapters freely: the pin length, the live counter, the route stops and the whiteout all read the count and the numbers. Three is the fewest that reads as a journey; six the most before the section becomes the longest stretch of the page.
Chapter index .index Plain list rows. The thumbnail in each row is revealed on hover; on touch it is always shown. Each row links to #journey with data-jump-chapter="n", which lands the pinned journey on chapter n rather than at its start.
Voice data-voice The sample sentence is the text of [data-voice-text] and its data-placeholder. The shuffle lines live in the <script type="application/json" data-voice-lines> block. The tabs are data-voice-width (75–125) and data-voice-weight (300–700).
Colour data-colour The photograph is [data-colour-img]. The five points are button[data-colour-point] on the photograph and button[data-colour-chip] in the panel, each carrying data-x, data-y (percent of the photograph) and data-hex (the fallback colour). See below for re-pointing them at your own photograph.
Photography data-photo-grid Six .photo-1 to .photo-6 frames; their grid placement in style.css is the composition. data-speed on each sets its scroll drift: 1 moves with the page, 1.2 faster, 0.85 slower.
Index (footer) .index-footer The same site map in the page flow, for the no-JavaScript visitor and for anyone who reaches the end.

In-page links are handled by the script, not by the browser. A native #journey jump to a pinned section lands wherever the pinned element currently sits, which after one scroll-through is the whited-out end of the pin. initAnchors scrolls every a[href^="#"] to the target's real position instead (its pin spacer when it has one), through Lenis when it is running, and honours data-jump-chapter. Keep new in-page links as plain #id hrefs and they get this for free.

Three numbers worth knowing before you tune the motion, all in assets/script.js:

  • Pin length (initJourney, perStep): 0.85 viewports per chapter transition, plus 0.7 of that for the whiteout. Below about 0.6 a single hard flick clears two chapters in one gesture; above 1 the section starts to drag.
  • Fit threshold (initVoice, fit): the line stays at full size to 26 characters, then shrinks on a square root down to a third of the base. Raise the 26 if your sample sentences are longer.
  • Lens lag (initColour, the pointermove tween): 0.55 seconds. This is the trailing that makes the colour feel sampled rather than read off the cursor. Shorter feels like a cursor; much longer feels broken.

Palette

The reskin is one edit to one block. Open assets/style.css and change the five solids in :root together with their matching RGB triples:

Code snippet omitted: it ships with the download.

Everything else in the stylesheet, every rule, scrim, dimmed label and focus ring, is one of those triples at another alpha, so nothing is left mixed from the old colour after a repaint. There are no hardcoded rgba() literals to hunt down.

Contrast was measured as used, composited, at the size it is used, and the figures are in the :root header comment. Two constraints hold the palette in place:

  • Body copy is ink at 72% on mist, at 6.35:1; the fine labels are ink at 64%, at 4.8:1. Dropping the label alpha under 0.62 takes them below the 4.5:1 floor.
  • The green is never text, a rule or a focus ring on the dark field. It measures 2.68:1 there. The dark sections override the focus colour to chalk for that reason; keep that override if you change the accent.

Type over a photograph always sits inside the foot of the scrim, which is black at 62% where copy lands, so even a blown-out cloud behind a caption composites to at least 10:1.


Typeface

One family, Mona Sans, loaded from Google Fonts with both its axes: weight 300–700 and width 75–125. The width axis is what makes the Narrow and Wide tabs in the Voice section do anything. If you swap the family, pick another variable font with a wdth axis, or delete the width tab row and keep the weight tabs.

The page runs on the ratio between its largest and smallest type (about 16:1 on a desktop) rather than on any face in particular, so the composition survives a change of family. Keep the ratio if you change the sizes.


Photographs

The twelve images in assets/img/ are optimised WebP derivatives with one grade baked into the pixels (saturation pulled to 0.82, brightness matched per image), so the set reads as one walk. They total about 1.5MB. You may ship them as they are or replace them.

To swap a photograph, either drop your own file into assets/img/ under the same name, or edit assets/img-manifest.json (a source path or URL, an output name, a width and height, and the grade) and regenerate the set with:

Code snippet omitted: it ships with the download.

Full-bleed chapter images want to be about 1920 pixels wide; the grid frames 900 to 1200; the colour photograph 1500.

The colour lens reads pixels off the photograph, so when you replace colour-heath.webp the five named points need re-pointing: set each button's data-x and data-y to the percentage position of the colour you want, and its data-hex to that colour so the no-JavaScript page and the fallback match. The names are yours to change too; the name shown under the lens while it moves comes from nameColour() in script.js, a short table of hue bands you can rewrite in the vocabulary of your own landscape.

The photograph must be served from the same origin as the page (which it is when you upload the folder). A cross-origin image taints the canvas, and in that case the lens still moves and the five chips still work from their stored hex values, but the swatch no longer follows the pointer.

Credits. The originals are Pexels photographs, licensed under the Pexels licence, which permits modification and redistribution without attribution. The credits are given anyway:

File Photograph
ch-shore.webp https://www.pexels.com/photo/drone-shot-of-waves-breaking-on-a-shore-5851472/
ch-forest.webp https://www.pexels.com/photo/green-pine-trees-on-mountain-area-10762369/
ch-moor.webp https://www.pexels.com/photo/tranquil-foggy-path-through-misty-heathland-36344918/
ch-summit.webp https://www.pexels.com/photo/a-view-of-snow-covered-mountains-from-above-28199288/
colour-heath.webp https://www.pexels.com/photo/purple-heather-growing-on-the-coast-18720264/
voice-cloud.webp https://www.pexels.com/photo/scenic-view-of-a-mountain-amid-clouds-26953466/
ph-pines.webp https://www.pexels.com/photo/foggy-forest-in-autumn-15222306/
ph-surf.webp https://www.pexels.com/photo/wave-on-seashore-in-birds-eye-view-19704701/
ph-falls.webp https://www.pexels.com/photo/waterfalls-under-blue-sky-2417729/
ph-river.webp https://www.pexels.com/photo/a-curvy-river-surrounded-by-green-grass-and-trees-13221707/
ph-lake.webp https://www.pexels.com/photo/herbert-lake-reflection-at-sunset-in-banff-32194155/
ph-cliffs.webp https://www.pexels.com/photo/waves-crashing-on-a-rocky-shore-7112541/

Accessibility and fallbacks

  • Without JavaScript, or with the CDN blocked, the page is a plain document: the four chapters stand as four full-height panels with their photograph, name, figures and text; the Voice section shows its sample sentence; the swatch is painted with the first named colour. The head script's class is removed when GSAP fails to load, so nothing stays hidden.
  • Reduced motion is a designed page, not the animated one switched off. The journey keeps the stacked layout and never pins, the hero and the reveals appear in place, the parallax is off. The Voice tabs still set the axes and the colour chips still sample, both applied instantly.
  • Keyboard. The Voice line is a real editable element. The width and weight tabs are buttons in role="tablist" groups with arrow-key movement. The five colour points and the five chips are buttons. Focus rings are fern on the mist sections and chalk on the dark ones.
  • Touch. The lens does not follow a finger; a tap on the photograph moves it there and samples, and the five chips are thumb-sized. The chapter thumbnails in the index are shown without hover.
  • Smooth scroll is Lenis on the shared GSAP clock, and it is opt-out: data-smooth="off" on <html>, or ?smooth=off in the URL. It is also off automatically under reduced motion. Never add anticipatePin to the journey's ScrollTrigger; on a pinned section it costs visible yank.

Browser support

Evergreen browsers. The variable font axes, font-variation-settings, clip-path, aspect-ratio and canvas getImageData are all widely supported; where a canvas is unavailable the colour section falls back to its stored values.

Built against GSAP 3.15.0 and Lenis 1.3.17. Works on GSAP 3.12+.

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