# Multi-Page Developer Portfolio

> An eleven-page portfolio website template for frontend developers, design engineers, product designers and freelance consultants. Every project has its own case study in its own colour, whole sections turn selected, and every page change runs as a text selection that lands on the next title in the destination's colour.

Canonical: https://gsapvault.com/templates/multi-page-developer-portfolio-template
Live demo: https://gsapvault.com/demos/multi-page-developer-portfolio-template/index.html

| Property | Value |
|----------|-------|
| Type | template |
| Tier | paid |
| Price | Not sold singly; comes with the Templates Pass or the Vault |
| Difficulty | advanced |
| Plugins | ScrollTrigger |
| Techniques | page-transition, soft-navigation, directional-transition, clip-path, scroll-reveal, stagger, hover-effect, keyboard-navigation, focus-management, progressive-enhancement |
| Uses Lenis | No |

## Lighthouse, as measured

Google Lighthouse on the demo (11 pages, lowest score shown), 9 October 2026. A measurement of the demo as shipped, not a promise for your page.

| Category | Score |
|----------|-------|
| Accessibility | 100 |
| Best practices | 100 |

No performance score is published: it depends on the deployment (server compression, caching, CDN, connection and device) rather than on the code, so measure it where it will live.

## Overview

A portfolio for someone who designs and builds: home, a work index, five case studies, about and stack, a writing index, an essay and contact, eleven pages in all. Ama Owusu, a fictional design engineer in Rotterdam, is the worked example, with five projects written up in full, product screens and photographs of the work in use, essays and short notes. The same pages suit a frontend developer, full-stack developer, product designer or independent consultant once the name, work and copy are yours.

The whole site is built on one material: selection. A paper-grey ground, near-black ink and a small family of saturated colours that mean selected: a true blue for the site and one colour per project. Small things are selected (a project name, the current page, a row under the pointer) and so are whole sections, set into the page as rounded panels: each case study's head, figures and footer turn the page's colour with the text reversed out, every page opens on a hero panel in its own colour with the navigation pill set into it, and the Contact page is one panel from top to bottom, in the colour of the last project you read. On the home page the Selected work panel turns the colour of the project under the pointer, and the page transition draws its selection in the destination's colour, so moving between projects visibly changes colour.

The home page sets the statement on a ruled title line beside a stack of product screens. Hover, focus or drag-select a project name in the introduction and the selection hops to it, in that project's colour, as its screen comes to the front. On the work list a highlight bar follows the pointer and the keyboard across the projects with a large preview beside them.

Page changes are the signature, in under a second with the next page prefetched. The clicked link is selected like text and the selection grows into a page-sized panel in the destination's colour, the next title appears on it, and the panel settles onto the new page's hero as the title deselects with one blink of a caret. Back and Forward grow the panel from the screen edge. Everything is static HTML, CSS and JavaScript with bundled images and no build step.

## Features

- Eleven standalone HTML pages: home, work, five case studies, about and stack, writing index, essay and contact
- Text-selection page transition on every internal link: the selection grows into a page-sized panel in the destination's colour, holds the next title, then settles onto the new page, in about a second
- Selected sections: bands with reversed-out text for selected work, case study heads and figures, talks, principles and the footer, and a fully selected Contact page
- A colour family of nine tokens: a true blue for the site, one colour per project and three page colours, each measured for white text and as text on the ground
- Home hero with a stack of product screens that reorders as you hover, focus or drag-select project names
- Project list with a highlight bar that follows hover and keyboard focus, a large live preview, and the highlight carried into the transition
- Five case studies from one kit of sections (wide screen, photograph, split, pair, figures band, quote, decisions, code, changelog) with previous and next project links
- Photographs of the work in use and the process alongside designed product screens, with credits
- Back and Forward reverse the direction and restore scroll; the arriving heading is focused and announced
- Writing index with essays and notes, filterable by topic through ?topic= links, and an essay with a live ::selection demo
- Contact page with copy-to-clipboard email and an unwired enquiry form
- Real links and complete pages without JavaScript; instant page swaps under reduced motion

## Use Cases

- Frontend and full-stack developer portfolios with a few deep case studies
- Design engineer and product designer portfolios that mix work, writing and an about page
- Freelance consultants and independent developers taking enquiries
- Personal sites that publish essays and short notes alongside client work

## Questions about this template

### Who is this portfolio template for besides design engineers?

It suits anyone who shows a handful of projects and writes about how they work: frontend developers, full-stack developers, product and UX designers, design engineers and freelance consultants. Replace Ama Owusu's name, projects, screenshots and essays with yours; the case study structure works for code-heavy and design-heavy projects alike.

### How do I add more case studies or essays?

Duplicate one of the five work pages, change the title, label, meta and sections, and point a row on the work page and the previous and next links at it. Each case study is built from the same kit of sections, so you can drop or reorder them freely. The transition picks up any new page's title from its h1.

### Can I use my own screenshots and photographs?

Yes. Each project row has its own 16:10 screenshot, which also feeds the large preview and the home page stack, so replacing one file updates all three. Case study photographs sit in ordinary figures with captions. The README lists every bundled image and how to regenerate optimised WebP versions from the manifest.

### Does the contact form send email?

No. The enquiry form is an unwired static front end: it collects a name, email, company, type of work, rough budget and a message, checks the required fields and shows a confirmation that nothing was sent. Connect it to Formspree, Netlify Forms, Basin or your own endpoint before launch. The copy-email button works as shipped.

### Can I change the colours?

Yes. The colour family is nine tokens at the top of the stylesheet: --c-core for the site, one per project and three page colours (--c-night, --c-ochre, --c-plum), each with an RGB triple. A case study picks its colour with data-hue on the page wrapper and on links that point to it. Keep every colour dark enough for 4.5:1 with white text and on the page ground; the stylesheet records the measured pairs.

### Can I keep some links as normal page loads?

Yes. Add data-native-navigation to any link, or to a container such as the footer, and those links load the next page normally without the selection transition. Links to other folders, external sites, downloads and same-page anchors already behave normally, so a blog hosted elsewhere or a PDF CV needs no changes.

## Vibe-Code Ready Setup

This template includes `START-HERE-AI.md`, a product-specific copy-paste setup prompt for Cursor, Claude Code, ChatGPT, GitHub Copilot, Windsurf, and other coding assistants. It tells the assistant to inspect the existing stack, integrate the supplied files, preserve the design, scope selectors, retain accessibility and responsive behaviour, add framework-appropriate GSAP cleanup, and report what it tested.

[How AI-assisted setup works](https://gsapvault.com/vibe-coding)

## How It Works

### Eleven pages, one title line

Each page is its own HTML file with the same header and page head: a small label above and the page title on a ruled line at a fixed height. Five case studies share one kit of sections, mixed differently per project, with previous and next links between them. Without JavaScript the links are ordinary links and every page is complete.

### Selection as structure, in colour

Six colours mean selected: a core blue for the site and one per project, each holding white text. A page names its colour with one attribute, and inside a selected block every colour token flips, so lists, links, the highlight bar, figures and form fields reverse out without extra rules. Case studies open on a head in the project's colour.

### The selection transition

Internal links fetch the next page and swap its content in place, with the exit starting on the click while the page loads underneath. The link is highlighted like selected text, and the selection grows into a rounded panel the size of the page, in the destination's colour, with the next title held on it until the page is ready. The title deselects with a caret blink as the panel settles onto the new page's own hero panel, under a header that stays put.

### Work you can handle

On the home page the project names in the introduction can be hovered, focused or drag-selected; the selection hops to the name and that project's screen comes to the front of the stack beside the title. On the work list a highlight bar follows pointer and keyboard focus with a large preview, and a lit row carries its highlight straight into the transition. Touch screens show each project's screen inline.

### Calm when it needs to be

Reduced motion swaps pages instantly and shows every section without animation. Keyboard navigation lands focus on each new page's heading and announces it. A second click during a transition is honoured without the old page flashing back. With the animation library blocked, the site falls back to plain page loads.

## Documentation

How this template works and how it goes into a page. The reference you use once you own the files (worked examples, events, the programmatic API, the class list) ships with the download.

### Quick Start

Upload the folder to any static host and open `index.html`. Keep the eleven HTML files beside `assets/` so relative links keep working. There is no build step, framework or package to install.

Serve the files over HTTP or HTTPS to see the page transitions. While editing, run any local static server in the folder (for example `python3 -m http.server`) and open `http://localhost:8000/index.html`. Opening a file straight from disk works too, but links then load pages normally without the transition.

GSAP and ScrollTrigger load from a CDN and the fonts (Host Grotesk and Google Sans Code) from Google Fonts. Images, styles and scripts are bundled locally.

### Using It With Your Own Design

1. **Identity.** Replace "Ama Owusu", "Design engineer" and "Booking from January" in the header of each page, and the line and links in each footer. They are repeated in all eleven files so every page stands alone.
2. **Titles.** Each page's `h1` sits on the shared title line. Keep titles short (one or two lines); the home statement can hold a permanently selected phrase in `<span class="sel">`.
3. **Projects.** Edit the rows in `index.html` and `work.html`, the project names in the home introduction, and the five `work-*.html` case studies. Replace the screenshots and photographs in `assets/img/` (see Images).
4. **Writing.** Replace the essay in `writing-selection.html` and the notes on `writing.html`. Give each note an `id` and its topics in `data-topics`.
5. **Colour and type.** Edit the colour tokens at the top of `assets/style.css` (see Palette). Change the Google Fonts link in each page if you change typefaces.
6. **Contact.** Change the email address and connect the enquiry form before launch (see Contact Form).

Everything visual lives in `assets/style.css`; everything interactive lives in `assets/script.js`, organised as one function per feature that returns early when its markup is absent. `assets/page-router.js` is the small shared page router underneath the transition (link handling, fetching, history, scroll and focus); you should not need to edit it. Delete a section from the HTML and the rest keeps working.

### Pages and Configuration

| File | Content |
| --- | --- |
| `index.html` | Statement on the title line beside a stack of product screens, introduction with selectable project names, facts row, selected work band, writing, Now with a photograph |
| `work.html` | All five projects with a highlight bar and large preview, talks and workshops band |
| `work-ledgerline.html`, `work-tidepool.html`, `work-kiln.html`, `work-sedge.html`, `work-halyard.html` | Case studies from one kit: head and meta, wide screen, then a mix of text, photograph, split (text beside a photo), pair, figures band, quote, decisions, code and changelog, ending in previous and next project links |
| `about.html` | Portrait and biography, a working photograph, stack, experience, a band of working habits |
| `writing.html` | Topic filter, a selected essay band and dated notes; `?topic=css` filters on arrival |
| `writing-selection.html` | Essay with a live `::selection` demo, code, footnotes and links onward |
| `contact.html` | A fully selected page: email with a copy button, enquiry form, availability, time zone and elsewhere |

Hooks you will meet in the markup:

- `data-page` wraps each page's content and footer; the header stays outside it and persists across page changes. `data-nav="work"` on that wrapper names the navigation item to mark as current (case studies mark Work, the essay marks Writing). The `is-selected` class on that wrapper makes a whole page one panel, as on Contact.
- `is-selected` on any block (the `band` sections, the footer, every page's `page-top` hero) flips every colour token inside it: the page's colour as the ground, white text, white selection. Components need no extra rules to sit inside one.
- `data-hue="kiln"` on a page wrapper gives that page its colour; on a link (nav links, work rows, home project names, previous and next) it tells the transition, and the nav hover fill, which colour to draw in. Values match the `--c-*` tokens.
- `data-hero-words` holds the home introduction; each `a[data-project="tidepool"]` matches an `img[data-shot="tidepool"]` in `data-hero-stack`. Add or remove pairs together.
- `.page-head` holds the small label (`.eyebrow`) and the `h1.title`. Keep this structure on every page: the transition reads the next page's title from it and lands on its first baseline.
- `data-work-list` with `data-work-row` links: the project list. Each row's `.work-thumb` image (16:10) is shown inline on touch screens and also feeds the preview panel (`data-work-preview`) on desktop. Wrap the words the transition should select in `data-select-text`.
- `data-topic` links and `data-topics="css motion"` items: the writing filter. It works in place, counts each topic on its chip and writes what matched into `data-filter-status`.
- `data-copy` / `data-copy-source`: the copy-email button and the text it copies. `data-contact-form`: the enquiry form.
- `data-intro` marks a page's opening block; `data-reveal` and `data-reveal-group` give a gentle rise on scroll.

### Page Transitions

Every same-origin link to a sibling `.html` page runs the same transition, and the next page is fetched while it plays. With the page prefetched (links prefetch on hover and focus) the whole change takes about one second:

1. **Leave (about 0.5s).** The clicked link's words are highlighted from left to right, like pressing Shift+End. The highlight then grows into a rounded panel the size of the window, inset like every other panel, while the old page fades out under it and the header floats on top. A lit project row skips the first step: its highlight bar is already the selection. The panel is drawn in the destination's colour: a link's `data-hue`, the project named in a `work-<project>.html` address, the last project visited (for Contact), or the core blue.
2. **Hold.** The next page's title appears on the panel, in white, on the title line. The only wait is the genuine fetch and image decode.
3. **Enter (about 0.6s).** The title deselects with one caret blink while the panel settles onto the new page's hero panel (on Contact, the whole page), stopping short of a case study's first screen; the held title hands over to the real heading underneath. The header floats over the panel throughout, and its selection slides to the new page.

Back and Forward grow the panel from the bottom or top edge instead of from a link. Scroll positions are restored, and the arriving heading receives focus and is announced. In the navigation pill the current page is a white selection that slides to the new link, and hovering or focusing a link fills it in the colour of the page it leads to; click, and that fill is what grows into the next page's panel.

Notes for editing:

- Pages are fetched, not reloaded, so scripts inside a fetched page do not run. Add new behaviour to `assets/script.js` as another init function called from `initPage`. Every page loads `assets/page-router.js` before `assets/script.js`; keep that order on a new page.
- The transition is the `leave`, `hold` and `enter` functions passed to `PageRouter.create` at the end of `assets/script.js`. The header comment of `assets/page-router.js` lists everything they receive.
- Any sibling HTML file with a `data-page` wrapper joins the transition automatically. Add `data-native-navigation` to a link or container to opt out; downloads, new-tab clicks, external links and same-page anchors already behave normally.
- Timings live in `leave`, `showTitle` and `enter`. On a slow connection the title is held on the panel until the page and its main image are ready; nothing is added on top of the network time.
- The latest click wins: a second link chosen before the new page is in place goes straight there from the covered screen.

### Contact Form

The enquiry form is a static front end. It collects name, email, company, type of work, a rough budget and a message, checks the required fields and then says plainly that nothing was sent. Point the form's `action` at Formspree, Netlify Forms, Basin or your own endpoint and remove the `submit` handler in `initContact`, or post the fields from that handler.

### Palette

| Token | Value | Use |
| --- | --- | --- |
| `--ground` | `#F1F1EE` | Page ground and the transition cover |
| `--surface` | `#FBFBF9` | Image frames, form fields, demo panel |
| `--ink` | `#15151A` | Text; dimmed at 0.70 and 0.60 for secondary text and labels |
| `--c-core` | `#0A5FD1` | The site's selection colour and the home page's: highlights, links, focus, selected sections |
| `--c-ledgerline` | `#137547` | Ledgerline's case study, row highlight and transition colour |
| `--c-tidepool` | `#0A6878` | Tidepool |
| `--c-kiln` | `#A93F1D` | Kiln & Co. |
| `--c-sedge` | `#B5234C` | Sedge |
| `--c-halyard` | `#5B45E0` | Halyard |
| `--c-night` / `--c-ochre` / `--c-plum` | `#1D1D24` / `#735C00` / `#7B2D6E` | Page colours: the heads of Work, About and Writing (Home is core blue) |
| `--hue` / `--select` | per page | The current page's colour (from `data-hue`) and the selection drawn with it; inside `is-selected` blocks the selection becomes white |
| `--on-select` | `#FFFFFF` | Text inside a selection |
| `--inset` / `--r-panel` | `clamp()` | The gap round a panel and its corner radius; the transition reads both |
| `--r-media` / `--r-control` | `clamp()` / `6px` | Corners on screens and photographs, and on buttons, fields and bars |

Every page opens on a hero panel, `<div class="page-top is-selected">` around its head, in the page's `data-hue`; the header sits on it with the navigation as a pill whose current page is a white selection. Nav links carry their page's `data-hue` too, so the transition knows the destination's colour before the page arrives: give a new page and its nav link the same one. A section turns selected with `class="band is-selected"`; add `data-hue="kiln"` (or any family name) to paint it in that colour instead of the page's. On the home page the Selected work panel takes the colour of the project under the pointer or focus.

Measured contrast pairs are recorded at the top of `assets/style.css`: white on each colour is 5.7:1 or better, and each colour as text on the ground is 5.1:1 or better. A replacement or extra project colour must keep 4.5:1 both ways; add its token, its RGB triple and a `[data-hue="name"]` line beside the others.

### Accessibility and Fallbacks

- Real links everywhere, a skip link, visible focus in the selection colour, labelled form controls and one `h1` per page.
- The project highlight bar and the home project names follow keyboard focus as well as the pointer; the preview panel and the screen stack are decorative and hidden from assistive technology.
- Text inside selected blocks is white, or white at 0.92 and 0.86 (4.7:1 at the lowest, on Ledgerline green); the navigation is full white.
- The transition layer is `aria-hidden`. Scrolling is held while it runs, and the arriving heading is focused and announced through a polite live region.
- Reduced motion swaps pages instantly and shows every section without animation.
- No JavaScript, an unavailable GSAP CDN or opening from `file://`: links load pages normally and all content is visible.

### Dependencies

The demo is pinned to **GSAP 3.15.0** with ScrollTrigger. Compatibility floor: **GSAP 3.12+**, with core and plugin on matching versions. No Lenis, no other plugins, no backend.

### Images and Credits

The download contains WebP derivatives in `assets/img/`, generated by `assets/img-manifest.json` (`bun scripts/build-template-assets.ts <folder>` in the Vault repository, or any image tool at the listed sizes). Product screens are 1600 by 1000 for the stack, list previews and case study heads; photographs are lazy-loaded below the fold.

The product screens (`ledgerline-*.webp`, `tidepool*.webp`, `kiln*.webp`, `sedge*.webp`, `halyard*.webp`) are designed mock-ups of fictional products, made for this template from HTML and CSS; their JPEG masters are in `assets/img-src/`. Replace them with screenshots of your own work.

Photographs are licensed through [Pexels](https://www.pexels.com/license/), which permits use in website templates. They show unrelated people and places, not Ama Owusu, her clients or their users; captions describe the scene, not a real project.

| File | Source | Subject |
| --- | --- | --- |
| `portrait.webp` | [Pexels 10159280](https://www.pexels.com/photo/10159280/) | Smiling woman in a white T-shirt against a pale wall |
| `photo-ledgerline-whiteboard.webp` | [Pexels 1181343](https://www.pexels.com/photo/1181343/) | Man at a whiteboard of wireframe sketches |
| `photo-ledgerline-paper.webp` | [Pexels 11780441](https://www.pexels.com/photo/11780441/) | Hand on a phone over grid-paper wireframes |
| `photo-tidepool-deck.webp` | [Pexels 39199081](https://www.pexels.com/photo/39199081/) | Woman checking a phone on deck, yachts behind |
| `photo-tidepool-helm.webp` | [Pexels 5416429](https://www.pexels.com/photo/5416429/) | Sailor at the wheel of a yacht |
| `photo-kiln-studio.webp` | [Pexels 9304491](https://www.pexels.com/photo/9304491/) | Teacher throwing a bowl while a student watches |
| `photo-kiln-hands.webp` | [Pexels 31848846](https://www.pexels.com/photo/31848846/) | Hands shaping a vase on a wheel |
| `photo-sedge-mudflat.webp` | [Pexels 17688199](https://www.pexels.com/photo/17688199/) | Figure walking across a mudflat towards reeds |
| `photo-sedge-wading.webp` | [Pexels 14244617](https://www.pexels.com/photo/14244617/) | Person wading among plants in still water |
| `photo-halyard-desk.webp` | [Pexels 574073](https://www.pexels.com/photo/574073/) | Laptop with code beside a notebook |
| `photo-talk.webp` | [Pexels 18935245](https://www.pexels.com/photo/18935245/) | Speaker facing an audience at tables |
| `photo-about-call.webp` | [Pexels 7014931](https://www.pexels.com/photo/7014931/) | Over-the-shoulder view of a video call and drawing tablet |
| `photo-sketch.webp` | [Pexels 4959784](https://www.pexels.com/photo/4959784/) | Hands sketching beside a laptop |

Replace the portrait with your own photograph before launch.

## What You Get

- `index.html`: working demo page
- `assets/script.js`: commented, readable source
- `assets/style.css`: effect styles
- `README.md`: full documentation with examples and framework integration notes
- `START-HERE-AI.md`: product-specific copy-paste prompt for AI-assisted setup
- `LICENSE.txt`: standard license terms
- Lifetime updates: re-download anytime from your library

## Get the Code

This is a premium template, not sold individually: it comes with the Templates Pass or the Vault. The standard licence covers unlimited personal and commercial projects with no attribution required for our code. Bundled third-party assets retain their own licences and attribution requirements. The only restrictions: no redistribution of the code itself and no competing effect libraries.

- [Templates Pass (£50 one-time): every current and future premium template](https://gsapvault.com/pricing)
- [The Vault (£99 one-time, best value): every collection in the Vault library, plus future items added to those collections](https://gsapvault.com/effects)

---

From [GSAP Vault](https://gsapvault.com): production-ready GSAP animation effects. Full catalog for agents: https://gsapvault.com/llms-full.txt
