037

Link Hub Template

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

An editorial link-in-bio page for a fashion model and lifestyle creator: a Didone contents index whose covers follow the cursor and cross-fade as you move down the list, with a shipping four-palette persona switcher.

ScrollTrigger Lenis intermediate
8 more details
mouse-followmagnetichover-effectspotlightscroll-revealparallaxstagger 4 colour palettes
Colour

Updated

About this template

A complete, deployable one-page link hub for a fashion model and lifestyle creator: a fixed nav, a full-bleed portrait hero, an editorial link index, a Latest campaign block, a social row and a footer. The demo dresses it as Noor Vidal, a Milan-based model, but every word, link and photo is yours. It is styled like the contents page of a magazine, not a stack of rounded buttons: a high-contrast Bodoni Moda display over a clean Hanken Grotesk, on a glossy warm-black ground with a single champagne accent.

Read the full template overview

The index is the signature. On a laptop, a single cover photo follows your cursor down the list and cross-fades to whichever row you are over, that row's label slides toward the pointer, the other rows dim, and an underline sweeps in. On a phone, in reduced motion, or with JavaScript off, each row instead shows its cover as a small static thumbnail, so the whole index stays complete and tappable with none of the motion.

Making it yours is a photo swap and, if you like, a palette swap. Drop your campaign shots into the image slots (a bundled manifest bakes the grade so the set reads as one shoot), and rewrite the copy in your voice. The page ships four full palettes: Runway (the glossy near-black default), Neon (magenta nightlife), Editorial (a light cream print look) and Studio (calm greige). Pick one by setting data-palette on the html tag, or copy its values into the stylesheet's root.

With JavaScript off the page is a clean, readable document with every link reachable, and it deploys as static files with no build step.

Link Hub Template - website template preview

What's included

11 items
  • Complete deployable link page: fixed nav, portrait hero with bio and stats, a six-row link index, a Latest campaign block, a social row and a footer
  • Signature hover index: on a fine pointer one cover photo follows the cursor and cross-fades to the hovered row, with a velocity-driven tilt and a settle lag that reads as a held photograph
  • Magnetic labels and a spotlight: the hovered row's Bodoni label nudges toward the cursor, the other rows dim to 0.4, and an accent underline sweeps in
  • A real touch fallback: on coarse pointers, reduced motion or no-JS, every row shows its cover as a static inline thumbnail instead of the floating preview, fully tappable and good-looking
  • Four measured palettes, each with its own display face (Didone, geometric grotesk, print serif, humanist sans), switched by one data-palette attribute: a persona picker for the buyer, not demo scaffolding
  • Every colour token measured as used in all four palettes; the tightest pair on the site is 4.6:1 and it is recorded in the stylesheet header
  • Hero portrait parallax on scroll, kept within an overscaled frame so no edge is ever uncovered
  • Designed CSS placeholders behind every image slot: a per-palette graded gradient tile so the page looks finished before the real photos are dropped in, with a bundled manifest for baking them
  • Keyboard parity: rows are real links that tab and open natively, and focus mirrors the hover spotlight and preview
  • Flash-free: the JS gate is set synchronously in the head, every reveal target is pre-hidden under it, and a blocked CDN degrades to the plain document
  • Reduced motion renders a complete static page via both a CSS media query and the script's own motion branch

Perfect for

5 use cases
  • Link-in-bio pages for models, influencers and lifestyle creators
  • A single landing page linking a portfolio, shop edit, bookings and socials
  • Photographers, stylists and makeup artists pointing to a book and a rate card
  • Anyone replacing a rented link-list service with an editorial page they own
  • Talent and agency profile pages that need to look like a campaign, not a form

How it works

5 sections

Structure

One script initialises everything with a single setup and teardown path, and one motion branch keyed on pointer type and reduced motion. Every querySelector is guarded, so the nav, hero, index, Latest block, social row and footer can each be deleted without breaking the rest. Lenis is wired in optionally and shares its clock with ScrollTrigger, so the reveals and parallax stay in step with smooth scroll.

The hover index

On a fine pointer a single fixed cover follows the cursor, cross-fading its stacked images to whichever row you are over. The same pointer move drives a velocity tilt on the preview and a magnetic nudge on the active row's label, while a data attribute dims the other rows and sweeps in an underline. None of it needs a plugin beyond ScrollTrigger.

The touch fallback

The floating preview only wakes in the fine-pointer, non-reduced branch, which is also where the inline thumbnails are hidden. On a phone, a coarse pointer, reduced motion or with no JavaScript, those thumbnails are what shows: each row carries its cover as a small static image, so the index is a complete, tappable list without any cursor work. Rows are real anchors, so they open on tap the same way they do on click.

The palette switch

Four palettes ship as data-palette blocks in the stylesheet, each restating every colour token and its RGB triple. Because every translucent rule, scrim and placeholder gradient resolves from those triples, switching palette repaints the whole page, placeholders included, with no stale colour left behind. A buyer sets one attribute on the html tag, or copies a block into the root and deletes the rest.

Reduced motion and no JavaScript

The JS gate is added synchronously in the head so reveal start states apply before first paint, and the script removes it if the GSAP CDN fails, degrading to the plain document. Reduced motion restores every pre-hidden reveal through both a CSS media query and the script's own motion branch, and renders the static thumbnail index. With JavaScript off the page is a clean, readable document with every link reachable.

Plugins ScrollTrigger
Difficulty Intermediate
Smooth scroll Lenis integration
Colour palettes 4 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 are the four palettes for?

They are a persona picker for you, not demo scaffolding. Runway, Neon, Editorial and Studio are each a complete token block switched by one data-palette attribute, and every colour is measured as used in all four, with the tightest pair at 4.6:1 recorded in the stylesheet header. Pick one and ship it.

What happens on a phone, where there is no cursor to follow?

Every row shows its cover as a static inline thumbnail instead of the floating preview, fully tappable and composed to look right rather than looking like a disabled desktop feature. The same fallback covers reduced motion and no-JS.

Do I need professional photography?

To look its best, yes: it is an editorial page for models and creators and the covers carry it. But designed CSS placeholders sit behind every image slot, a per-palette graded gradient tile, so the page looks finished before real photos are dropped in, with a manifest for baking them when you have them.

How many links can it hold?

Six rows ship as a contents index. It is a curated shortlist by design, not a long list: portfolio, shop edit, bookings, socials. If you need twenty links this is the wrong shape and the sticker-toss link-in-bio template suits better.

Link in Bio Template

Will it flash or break if the CDN is blocked?

No. The JS gate is set synchronously in the head and every reveal target is pre-hidden under it, so a blocked CDN degrades to the plain document rather than leaving content invisible or flashing it in late.

Paid template

Purchase to unlock the code.

Buying Link Hub 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

Quick Start

  1. Copy the folder. Everything the page needs is in index.html and assets/ (style.css, script.js, fonts/). The CDN <script> tags for GSAP, ScrollTrigger and Lenis are already in index.html.

  2. Add your photos. The page references eight images in assets/img/:

    File Size Where
    hero.webp 1600 x 2000 the portrait hero
    hero-1200.webp, hero-800.webp 1200 x 1500, 800 x 1000 smaller copies of the hero for phones and laptops
    link-01.webp … link-06.webp 800 x 1000 each the six link covers
    feature.webp 1200 x 800 the Latest campaign cover

    Until they exist, a designed gradient placeholder (graded from the current palette) fills every slot, so the page looks finished from the first open. See Images below for the bundled bake pipeline, or just drop files with those exact names into assets/img/.

  3. Rewrite the copy. Replace the brand name (Noor Vidal), handle, bio, stats, the six link labels/meta, the Latest block and the footer with yours. Point each href="#" at your real destination.

  4. Pick a palette (optional). See Palettes below.


Sections and options

Every section is independent: the script guards each lookup, so you can delete any block from index.html and the rest keeps working.

  • Nav (.nav) — wordmark and one CTA. It turns solid on scroll via a data-stuck attribute the script toggles.
  • Hero (.hero) — name, handle, one-line bio and a <dl> of stats beside the portrait. The portrait drifts on scroll (parallax); the image is overscaled inside its frame so an edge is never uncovered. Edit or remove .hero__meta items freely.
  • Link index (.hub) — six rows, each a real <a>. Add or remove rows by copying a .link-row block; keep the data-index sequential and add a matching data-preview-img cover in .link-preview and a .ph__tile--cN class if you want a distinct placeholder tint. The 01–06 numbers and the meta line under each label are yours to change.
  • Latest (.latest) — the newest drop or campaign: a wide cover with a small scrimmed tag, a title, a blurb and a button.
  • Social row (.social) — plain text links; add or remove freely.
  • Footer (.foot) — copyright, a "Built with" line, and a back-to-top link.

Palettes

The template ships four full palettes, each paired with its own display face so the four read as four identities rather than one design in four colours. They are a feature, not scaffolding: each is a complete token block in assets/style.css — the default :root (Runway) plus three :root[data-palette="…"] blocks at the foot of the file.

Palette data-palette Look Display face
Runway (default, no attribute) glossy warm-black, champagne accent Bodoni Moda 600, a high-contrast Didone
Neon neon dark ground, electric magenta Space Grotesk 700, a geometric grotesk
Editorial editorial light cream ground, ink type, muted terracotta Newsreader 600, a warm print serif
Studio studio calm greige, warm sand accent Figtree 600, a humanist sans

The face and the colours are independent tokens (--font-display and --font-display-weight sit in each block next to the colours), so keep the palette and swap the face, or the other way round. All four faces are self-hosted in assets/fonts/ and declared by the @font-face rules at the top of assets/style.css; a browser only downloads the one the page uses, but once you have settled you can delete the other families' rules and files. If you keep a palette other than Runway, point the Bodoni Moda preload in the <head> at your face's file. The body face (Hanken Grotesk) is the same in every palette.

To use one, set the attribute on the <html> tag in index.html:

Code snippet omitted: it ships with the download.

To make one the permanent default, copy its token values into the :root block at the top of style.css, then delete the alternate blocks. That leaves the stylesheet stating one palette rather than four.

Each block restates every colour token and its --*-rgb triple. Every translucent rule, scrim and placeholder gradient on the page resolves from those triples, so a swap repaints the whole page — placeholders included — with no stale colour left behind. Reskinning to a brand-new palette is a matter of editing those five colours (and their triples) in one block.

All four palettes were contrast-checked as used, at size; the measured pairs and the tightest one on the site are recorded in the style.css header comment.


Images

Images are meant to ship as bundled, optimised WebP derivatives with the template's grade baked into the pixels, so the set reads as one campaign and the files are art-directed rather than raw stock.

  • assets/img-manifest.json lists each output (out name, width, height, quality, grade). Point each src at your source file or URL.
  • Bake them with bun scripts/build-template-assets.ts --only link-hub-template, which crops, resizes and grades each source into assets/img/ at the exact names index.html references.
  • To swap a photo, either replace the file in assets/img/ directly, or edit its src in the manifest and re-run the bake. Set brightness per image so mixed sources match in perceived exposure.

If you would rather not use the pipeline, dropping correctly named files into assets/img/ works too; the <img> width/height are set for layout stability. The hero is served at three widths (hero-800, hero-1200, hero) through srcset, and preloaded in the <head> with the same list, so a phone fetches the small one first. When you replace the hero, replace all three, or cut the srcset and the preload's imagesrcset down to the files you have.


Accessibility

  • Reduced motion. With prefers-reduced-motion: reduce, all reveals and the parallax are disabled through both a CSS media query and the matchMedia branch, and the index renders as the static thumbnail list. Nothing is left hidden.
  • No JavaScript. The page is a clean, readable document: nav, hero, all six links, the Latest block, the social row and the footer are present and reachable. The floating preview never appears, because nothing wakes it. The link rows are plain <a> elements, so they tab and open natively.
  • Touch. The cursor preview is fine-pointer only; coarse pointers get the static thumbnail index, fully tappable.
  • Keyboard. Every row is a real link. Focus mirrors the hover spotlight — the focused row lights its underline and arrow and, when the enhanced index is active, brings up its cover — so a keyboard user gets the same cue a mouse does.

Dependencies

  • GSAP 3.15.0 core + ScrollTrigger (CDN tags included)
  • Lenis 1.3.17 smooth scroll (optional; the page works without it)
  • Fonts: Bodoni Moda (display) and Hanken Grotesk (body), plus the alternate palettes' Space Grotesk, Newsreader and Figtree

No build step. No framework. Static HTML, CSS and one JavaScript file.

Fonts

Every face is self-hosted in assets/fonts/, so the page makes no render-blocking third-party request. The files are the Latin subsets Google Fonts serves (Bodoni Moda also ships its symbols and math subsets, which hold the arrow glyphs; Bodoni Moda and Hanken Grotesk are variable fonts, so one file covers every weight), declared by the @font-face rules at the top of assets/style.css with the same unicode-range Google uses. Bodoni Moda and Hanken Grotesk are preloaded in the <head> because both set the hero. Licence: SIL Open Font License 1.1, full text and copyright lines in assets/fonts/OFL.txt (Bodoni Moda: Copyright 2020 The Bodoni Moda Project Authors; Hanken Grotesk: Copyright 2021 The Hanken Grotesk Project Authors; Space Grotesk: Copyright 2020 The Space Grotesk Project Authors; Newsreader: Copyright 2020 The Newsreader Project Authors; Figtree: Copyright 2022 The Figtree Project Authors).

To use Google Fonts instead, delete the @font-face rules and the two font preloads and add the Google Fonts <link> to the <head>.

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