009

Landing Page Template

£15 View live demo or the whole Vault, £79.20

A vertical-agnostic one-page site whose identity is structural: bands alternate hard between two tones, and the fixed nav and reading rail invert themselves against whichever band is behind them, swapped by a ScrollTrigger per band.

ScrollTrigger Lenis beginner
5 more details
scrollspytext-animationscroll-revealstagger 3 colour palettes
Colour

Updated

About this template

A production-ready one-page site built to be dropped into any business, which is the hard part: a template that suits everything usually ends up with no point of view. This one takes its identity from structure rather than subject.

Read the full template overview

Bands alternate hard between a light ground and a dark inverse, and the fixed chrome, the top nav and a reading rail, carries the opposite tone to whichever band is passing beneath it. A ScrollTrigger per band does the switch on the line each piece of chrome actually sits on, and the colour crossfades over a quarter of a second, so the inversion never lands mid-band or on the wrong tone.

The section set is the universal landing-page skeleton (intro, proof, offer, work, testimonial, pricing, contact), the copy is written as a small independent studio, and three complete colour-and-type presets show how the same alternating structure can feel editorial, contemporary or direct without changing the composition.

Landing Page Template - website template preview

What's included

11 items
  • Complete deployable one-page site: nav, reading rail, intro, proof, offer, work, testimonial, pricing, contact, footer
  • Signature inverting chrome: nav and rail flip between dark and light against alternating tone bands, driven by a ScrollTrigger per band and measured at 12.63:1 or better in every preset
  • Tone system where each band re-points shared rule and secondary-text tokens, so every component works on either ground unchanged
  • Three shipped colour-and-type identities: sage and magenta with Familjen Grotesk, warm parchment and umber with Cormorant Garamond, and cool blue with Manrope, each measured across both alternating tones
  • Reading rail whose entries are generated from the bands themselves, so deleting a section removes its entry instead of shifting the rest out of step
  • Marker springs to the band that owns the middle of the screen
  • Bundled project photography baked to a sage duotone, around 115KB total
  • Universal landing-page section set, so the template fits a studio, a shop, a service, or a product with a copy swap
  • Complete semantic palette blocks include both grounds, per-tone rules and secondary text, accent fills, matching RGB triples and the display face
  • Lenis smooth scrolling wired in and fully optional
  • Accessible: the rail is an inert indicator rather than duplicate navigation, reduced motion gets a complete static page, and the page reads fully without JavaScript

Perfect for

5 use cases
  • Small studios, agencies, and independent teams
  • Service businesses that need one page that converts
  • Product and launch pages where the section set matters more than the vertical
  • A reusable starting point for client one-pagers
  • Learning how to drive fixed chrome from the section beneath it without it ever landing on the wrong tone

How it works

3 sections

The inverting chrome

One script initialises each section with a single setup and teardown path and one motion branch, skipping any section it cannot find. Bands carry a tone class that sets their ground and re-points the shared rule and dim tokens, and the fixed chrome reads that same class to decide its own colour: a ScrollTrigger per band toggles is-on-light or is-on-dark as the band crosses the line that piece of chrome sits on, the nav on its own centre line and the rail on the middle of the viewport. Both states are the page's own grounds, at least 12.63:1 either way across the shipped presets, and CSS crossfades between them in 0.25s so the swap reads as an inversion rather than a jump. The starting classes are written into the HTML, so the chrome is legible before a line of script runs.

The reading rail

The script adds the reading indicator: it builds one rail entry per band from that band's data-section label, creates a ScrollTrigger per band spanning the middle of the viewport, and springs the marker to whichever band is active.

Reveals and fallbacks

Reveal targets and the intro lines start hidden in CSS and animate from a start state that matches it exactly, so nothing is ever painted in its finished state and snapped back. A prefers-reduced-motion branch applies the same layout with no tweens, and the has-js class that hides content is only set once GSAP is confirmed present, so a CDN failure degrades to a fully visible page.

Plugins ScrollTrigger
Difficulty Beginner
Smooth scroll Lenis integration
Colour palettes 3 ready-made palettes, each measured for AA contrast. Switch with one attribute, or copy the values you want into :root. Try them in the preview above.
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

What vertical is this template for?

Deliberately none. Its identity is structural rather than thematic: bands alternate hard between two tones and the chrome inverts against them. The section set (intro, proof, offer, work, testimonial, pricing, contact) is the universal landing-page run, so a studio, a shop, a service or a product all fit with a copy swap.

How does the nav flip colour as you scroll?

A ScrollTrigger per band. Each piece of chrome watches the line it actually sits on, the nav its own centre line and the rail the middle of the viewport, and takes the opposite tone to the band that owns that line: ink over the pale ground, paper over the charcoal. Because the trigger is the band itself, retoning or deleting a band takes the nav with it, and there is no second list of scroll offsets to keep in step.

If I delete a section, does the reading rail break?

No. The rail generates its entries from the bands that actually exist, so removing a section removes its entry rather than leaving a dead link or shifting the rest out of step. That is the reason it is generated rather than hand-listed.

How much work is it to make it look like my brand?

One token block: two grounds and one accent. Because every component is written to work on either tone, changing those three values reskins the whole page without hunting for hardcoded colours in individual sections.

Is the reading rail a second navigation menu?

No, and deliberately so. It is an inert progress indicator that springs its marker to whichever band owns the middle of the screen. Making it a duplicate nav would give screen-reader users two competing menus for the same page.

Paid template

Purchase to unlock the code.

Buying Landing Page 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.

£15 Standard license, unlimited projects

Browse free effects

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

Documentation

What's Included

Code snippet omitted: it ships with the download.

No build step. Open index.html and it runs.

Optional: minify before you go live

assets/script.js is the readable source and is what index.html loads. It is around 9KB, which is fine to ship as-is. If you would rather serve it minified, produce it yourself once your edits are done:

Code snippet omitted: it ships with the download.

Then point the last <script> tag in index.html at assets/script.min.js. Keep script.js as the file you edit and re-run the command after each change.

Quick Start

  1. Open index.html and replace the placeholder company with yours: name, headline, claims, offer, work, quote, prices, contact details.
  2. Update the <title> and <meta name="description">, and remove <meta name="robots" content="noindex, nofollow"> when you go live.
  3. Choose one of the three colour-and-type presets at the top of style.css, or change a preset's two grounds and accent to your own.
  4. Deploy the folder anywhere that serves static files.

The Inverting Chrome (the signature)

The nav and rail carry the opposite ground to the band behind them: --ink over the light ground and --paper over the dark ground, at least 12.63:1 in every preset. initChromeTone in script.js owns the switch. Each piece of chrome watches its own line, because each sits on different pixels, the nav on its own centre line and the rail on the middle of the viewport, and a ScrollTrigger per band toggles is-on-light / is-on-dark as that line crosses into the next band. CSS transitions the colour over 0.25s, so the swap still reads as an inversion rather than a jump; prefers-reduced-motion drops the transition and the colours snap.

Three rules to keep if you edit it:

  • The starting classes live in the HTML (class="nav chrome is-on-light"), matched to the first band. Without them the chrome would be unstyled until the script runs, and unreadable entirely if the CDN fails.
  • Keep the bands alternating and decisively light or dark. The swap only has two states; two mid-tones make both of them muddy.
  • Keep solid fills out of the chrome. The nav is text only and every call to action lives in a band, which is what lets it float over the page with no background of its own.

If a band ever needs artwork under the rail gutter or beneath the nav, keep that area quiet in tone: the chrome is one flat colour per band and cannot answer a busy photograph pixel by pixel.

This was mix-blend-mode: difference until 2026-09-09. The blend composited correctly on screen, but automated contrast checking cannot composite a blend mode: it measured white against the pale ground and reported 1.25:1 for painted pixels that were 4.6:1 to 14:1. Since the template publishes its Lighthouse accessibility score, the blend was replaced with the scripted swap, which states the same intent in colours a machine can read. What the swap costs is one thing the blend gave for free: while a band edge is physically crossing the nav text, about 24px of scroll, part of a glyph sits on the ground it is about to leave. The blend handled that per pixel. If you would rather have the blend back, put color: #fff; mix-blend-mode: difference; on .chrome, drop the two is-on-* rules, and expect the automated contrast report to fail.

Palettes

Three complete presets ship. Set data-palette on <html>, or copy one preset's values into :root and delete the alternate blocks. The demo picker is preview chrome injected by GSAP Vault and is not included in the buyer download.

Preset data-palette Paper / ink / accent Display face
Sage & magenta (default) omit the attribute #DEE8E1 / #16181D / #D6296B Familjen Grotesk 500
Warm neutral warm #F0E3CF / #211713 / #B84A31 Cormorant Garamond 600
Cool blue cool #DDEBF4 / #10263D / #147A8B Manrope 700

For example: <html lang="en" data-palette="warm">. Each preset restates all surface, rule, secondary-text, accent and on-accent values, plus matching RGB triples. There is still no third surface tone: the page is two grounds and a hard edge between them.

Token Default value What it is
--paper #DEE8E1 pale sage ground
--ink #16181D charcoal ground
--accent #D6296B magenta — fills and marks only, never type
--accent-deep #B01253 solid buttons carrying white text
--dim-on-paper / --dim-on-ink #55605A / #9AA39E secondary copy per tone
--rule-on-paper / --rule-on-ink #B7C7BD / #2F333B hairline band separators

The accent is banned as a text colour, on both grounds. Magenta measures 3.81:1 on paper and 3.71:1 on ink — under the 4.5:1 AA floor for normal-size type on both tones, which is why the ban is absolute rather than per-tone. Use it as a fill with white on it, or as a non-text mark (rules, bullets, the contact underline, the focus ring, the picked-plan border). If you recolour it, re-measure: any replacement must clear 4.5:1 against white before it can carry white text on a fill.

Measured pairs, including both alternating tones and the focus/mark accent:

Preset Ink / paper Dim / paper Dim / ink Accent / paper Accent / ink White / accent White / deep accent
Sage & magenta 14.15:1 5.22:1 6.86:1 3.81:1 3.71:1 4.79:1 6.87:1
Warm neutral 13.87:1 5.41:1 7.69:1 4.09:1 3.39:1 5.17:1 7.68:1
Cool blue 12.63:1 5.04:1 7.00:1 4.12:1 3.06:1 5.02:1 7.90:1

Two deliberate exceptions, both documented in the stylesheet where they live: the band separator rules are 1.4:1 hairlines that carry no information on their own, and the reading rail's inactive entries run at opacity .35 because the rail is aria-hidden decoration duplicated by the top nav. The contact address turns accent on hover, where it is 30.4px — large text, judged against the 3:1 bar.

If you swap the grounds, keep them far apart in value. The chrome only ever paints one ground on top of the other, so it only reads if each ground is decisively light or decisively dark; two mid-tones make it muddy on both. The nav links are 12.48px (12px on phones), which is small: the pair carrying them is at least 12.63:1 either way, so do not trade that headroom away for a softer grey.

Tones

Each band carries .tone--paper or .tone--ink. A tone sets its ground and text colour, and re-points two shared tokens:

Code snippet omitted: it ships with the download.

Every component below uses var(--rule) and var(--dim) rather than a fixed colour, so buttons, rules, captions, and secondary text all work on either ground with no per-tone overrides. Reorder or retone bands freely; just keep them alternating, since the inversion is the whole point. The chrome reads the same .tone--ink class to decide its own colour, so a retoned band takes the nav with it and there is no second list to keep in step.

The Reading Rail

An orientation indicator, not navigation, so it is inert and aria-hidden; the top nav does the navigating.

Entries are generated from the bands themselves, using each section's data-section label:

Code snippet omitted: it ships with the download.

Delete a band and its rail entry disappears with it. That matters: an earlier hand-written list silently shifted every entry below a deleted section out of step, so the rail confidently pointed at the wrong thing.

The rail hides below 1080px, where there is no gutter for it and it would mean nothing.

Photography

The three work images are bundled, optimised WebP derivatives, not hotlinks, baked to a sage duotone so mixed sources read as one set. Around 115KB total.

Replace the files in assets/img/ directly, or edit assets/img-manifest.json and regenerate:

Code snippet omitted: it ships with the download.

Per-image brightness compensates for source exposure; matching perceived brightness matters more than matching numbers. If you change the palette, retint the photography to match.

Credits

Original photographs from Unsplash, free to use under the Unsplash licence. The shipped files are altered, graded derivatives.

Smooth Scrolling

Lenis is wired in and optional. Remove the CDN tag and the lenis block at the top of script.js to drop it.

Accessibility

  • The rail is an inert indicator rather than a second set of links, so assistive tech is not given duplicate navigation.
  • Focus is visible on both tones; inside the chrome the ring uses currentColor so it inverts along with everything else.
  • The chrome's two states are --ink on --paper and --paper on --ink; every preset clears 12.6:1 in both directions. They are real colours rather than a blend mode precisely so an audit can measure them.
  • The accent is used for large text, rules, and fills only. Every preset clears 3:1 for focus indicators on both tones and 4.5:1 beneath white fill labels; solid buttons use the deeper --accent-deep for extra headroom.
  • prefers-reduced-motion gets the same layout with no tweens, and nothing hidden.
  • Without JavaScript the page reads completely; only the rail, which is a decorative indicator, is absent.

Customisation Notes

  • Colour: see Palettes above — --paper, --ink, --accent and --accent-deep are the core identity, and the accent is banned as normal-size text on both grounds. The per-tone rule and dim tokens exist so you rarely need to touch anything else.
  • Type: each preset sets --font-display and --font-display-weight; --font-body (Hanken Grotesk) and --font-mono (Spline Sans Mono) stay shared. Update the Google Fonts link when you swap them.
  • Sections are independent: the script skips any section it cannot find, so delete what you do not need.

Dependencies

  • GSAP 3.15.0 (core)
  • ScrollTrigger
  • Lenis 1.3.17 (optional)

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