# Interactive Map

> A studio portfolio drawn as one engraved sea chart: scroll flies a camera from a world view down to each project island, where the case study opens in place. Suits creative studios, architects, agencies, destination brands and any collective with four to six places to show.

Canonical: https://gsapvault.com/templates/interactive-map-template
Live demo: https://gsapvault.com/demos/interactive-map-template/index.html

| Property | Value |
|----------|-------|
| Type | template |
| Tier | paid |
| Price | £20 |
| Difficulty | advanced |
| Plugins | ScrollTrigger |
| Techniques | pinning, scrub, guided-camera, parallax, drag-to-pan, svg-line-draw, procedural-svg, interactive-svg, checkpoint-navigation, keyboard-navigation, interruptible-transitions, form-animation |
| Uses Lenis | Yes |

## Lighthouse, as measured

Google Lighthouse on the demo, 28 September 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

Fathom & Field is a complete one-page site for a small design studio whose portfolio is a single hand-engraved sea chart of an invented archipelago. Every project is an island. Scrolling flies a camera along a survey line from a world view down to each place; dragging pans the chart, and a tap on any island flies there. It is built for a studio, an architect, an agency, a collective or a destination brand with four to six places to show, and the worked fiction (a seven-person studio, five clients, a legend of services and a journal in the margins) is easy to replace.

The chart behaves like an instrument. A compass rose turns with the camera heading, a scale bar re-measures as you descend, a position and bearing readout runs live, and latitude and longitude ticks slide along the frame. The map redraws itself as you go: graticules thin and thicken, coastlines gain contours, soundings and hachures, and place names arrive at closer levels. Land, sea, cloud shadow and labels move at different rates, and contour rings lean away from the camera like stacked cut paper.

Each island opens into its case study as the camera arrives: the chart dims to a margin and a navy plate unfolds beside it with the project's text and line art. The same mechanism carries the surveyor's about page, the services as a legend of chart symbols, a journal set as marginalia, and a contact form that lights a signal fire on the map. Everything is static HTML, CSS and one script, with no build step. Re-seed or redraw the archipelago with the bundled generator, repaint the palette in the token block and rewrite the copy.

## Features

- Scroll-driven camera: one pinned stage flies from a world view to each place along a curved survey line, easing between waypoints and dipping out on long crossings
- Semantic zoom: graticule tiers, contours, hachures, soundings, rocks, feature names and harbour symbols fade in as the map is descended, with labels held at a constant size
- Free pan with a mouse and a tap-to-fly on any island; the chart returns to the route when you scroll, and a Back on route button appears while you are off it
- Live instruments: a compass rose that turns with the heading, a scale bar that re-measures, position, bearing, scale and level readouts, and sliding latitude and longitude edge ticks
- Case studies open in place as the camera arrives: the chart dims to a margin and a plate unfolds beside it, or rises from the bottom on a phone
- Depth by parallax: a swell layer beneath, cloud shadow above, and contour rings that lean like stacked cut paper as the camera passes
- A chart index of every place as a rail, an overlay dialog and a footer list, plus previous and next buttons, all keyboard operable with focus moved to the arrived place
- Seeded procedural coastlines written by a bundled generator: change the seed or the island list, run one command and the archipelago is redrawn
- Services as a legend of chart symbols, a journal as marginalia, and a contact form that lights a signal fire on the map
- Designed reduced-motion path: one place per screen with jump cuts, every plate readable and every control working
- Readable without JavaScript or with the CDN blocked: the chart is a picture and every case study follows as a stacked section
- Two typefaces (Ibarra Real Nova and B612 Mono) and a palette of paper, navy and one vermilion ink, all resolved from tokens

## Use Cases

- Creative and design studios that want the portfolio itself to be the experience
- Architecture and landscape practices presenting projects as sites on a plan
- Agencies and collectives with four to six flagship pieces to show in depth
- Tourism boards, islands, estates, campuses and festivals that are literally places
- Travel writers, photographers and expedition brands mapping a body of work
- Museums, trusts and heritage sites with a collection spread across locations

## Questions about this template

### Is this only for design studios?

No. The page is a chart with places on it, so it suits anyone whose work or offer is spread across sites: an architecture practice, a destination or island brand, a festival, a heritage trust, a photographer with regional series. The fiction is a studio with five clients, but every place is an article with a title, text and a figure, so it becomes projects, buildings or destinations by editing copy.

### How do I add another place or remove one?

Copy or delete one article in index.html. Each carries its position on the chart in data-x and data-y, and the marker, rail entry, route leg and tour stop are all built from it. Then add or remove its links in the rail, the index overlay and the footer list. To give a new place an island, add it to the generator's island list and run it. Four to six places suits the pacing.

### How much work is it to make this my own?

More than a typical template, and worth knowing before you buy. Swapping the copy, colours and figures is quick. Reshaping the map takes longer: the generator redraws the islands from a list, but island names, feature labels and the position of each place are set by eye against the preview. Plan an afternoon to move it to your own places, and stay with four to six places, which is what the camera route and pacing are built for.

### Can I redraw the archipelago for my own places?

Yes. assets/chart-generator.mjs takes a list of islands with a centre, size and peak, plus a seed, and rewrites the chart between two comments in index.html. Changing the seed gives new coastlines in the same layout. Island names and feature labels are plain text in the markup, so you place them by eye with the preview in front of you.

### Is the contact form live?

No. The Beacon Skerry form is a static front end: it checks the fields, lights the signal fire and shows a confirmation, but sends nothing. It collects a name, an email address, a project type and a message. Point its action at Formspree, Netlify Forms or your CRM, or post it from the submit handler in script.js before the beacon is lit.

### What replaces the project artwork, and are photographs included?

No photographs are bundled. Each case study carries an inline SVG line drawing built from the client's own material (tin lids, a timetable, a tide chart, a floor plan). Swap a figure for your own image, keeping its width and height so nothing shifts, or redraw the SVG. The chart is drawn, not photographed, so photography is optional.

### What does it do on a phone, and can I turn off the smooth scroll?

On a phone the map keeps a strip across the top and each case study rises as a sheet from the bottom, with the camera aimed at that strip. Vertical swipes drive the tour and a tap on an island flies there. Add data-smooth="off" to the html element, or ?smooth=off to the address, and the tour scrolls natively.

### How do I recolour it or change the typefaces?

The palette is a handful of tokens at the top of style.css: paper, sea, land, navy, the plate ground, chalk and one vermilion, each with its RGB triple. Water tints and relief steps are separate tokens. The two typefaces are set in one line each. The measured contrast figures for every pairing are written beside the tokens, so you can see which alphas must stay.

## 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

### Structure

One pinned stage holds the chart, the instruments and the case studies. The chart is a single inline SVG; each place is an article with its position on the chart in data attributes, and the script builds the markers, the rail, the route and the tour from those articles, so deleting one removes its marker, rail entry and stop with it. A synchronous head script adds the gating class before first paint and the main script takes it away again if GSAP does not load. Without JavaScript the chart is a picture and the articles stack below it.

### The camera

A small camera state is owned by GSAP: how far along the tour it is, how far the current plate has unfolded, and the opening zoom-out. One scrubbed timeline carries the state through each place in turn, easing between waypoints, then a single function draws it: position on a curve between places, zoom in log space with a dip on long crossings, heading with a little bank, and a shift of the view when a plate is open. Because everything reads the same state, the chart, the rail, the readouts and the route can never disagree.

### Semantic zoom and parallax

Each detail layer has a fade-in and fade-out zoom, so graticule tiers, contours, soundings and names arrive as you descend. Strokes are non-scaling, labels are held at a constant size and cancel the map's rotation, and the swell, cloud and relief layers move at their own rates for depth.

### Flying, panning and interruption

Taps, links, the rail and the pager all fly by moving the scroll position, through Lenis when it is running, so the tour is the only source of truth. Any wheel, touch or arrow key interrupts a flight. A mouse drag adds a free pan with a little inertia; scrolling or Back on route eases it home. Touch keeps the page scroll and only taps to fly.

### The chart generator

assets/chart-generator.mjs builds a seeded height field from a list of islands, traces contour lines through it and writes shoals, depth lines, coasts, relief, hachures, soundings, rocks, graticule and neatline into the markup between two comment markers. Run it after editing the island list and the chart is redrawn; the same seed always gives the same coast.

### Without motion or scripting

With reduced motion the tour becomes one place per screen with instant cuts and the same controls, and a tall plate scrolls inside itself. Without JavaScript the chart shows at world level with labels, and every case study, legend row and note is real content in the document.

## 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

**1. Upload the folder.** `index.html`, `assets/style.css`, `assets/script.js` (or `assets/script.min.js`) are the whole site. `assets/chart-generator.mjs` is optional and only used on your machine. Any static host will do.

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

_Code snippet omitted: it ships with the download._

The one-line script must stay synchronous and in `<head>`. It is what stops every gated element painting visible for a frame and then flashing to zero. `data-cfasync="false"` stops Cloudflare Rocket Loader deferring it.

**3. Keep the scripts before `</body>`:**

_Code snippet omitted: it ships with the download._

Lenis is optional; delete its tag and the tour scrolls natively. The minimum supported GSAP is 3.12; the demo is built against 3.15.0.

**4. Rewrite the copy, then re-point the chart.** Everything else is optional.

---

### Using It With Your Own Design

The site is one chart with places on it. To make it yours:

1. **Rewrite the places.** Each place is an `article.plate[data-place]`. Edit its text, figure, facts and links. Keep `data-x`, `data-y` and `data-span` (see below).
2. **Add or remove places.** Copy or delete a plate. The marker on the chart, the rail entry, the route leg and the tour stop are all built from the plates by the script. Also add or remove its row in the chart index overlay (`[data-index-list]`), the rail (`[data-rail]`) and the footer list, which are plain links to `#plate-id` with `data-fly="plate-id"`. Four to six places reads best.
3. **Redraw the archipelago.** Edit the `ISLANDS` list at the top of `assets/chart-generator.mjs` so each island sits where its place does, then run `node assets/chart-generator.mjs`. It rewrites everything between `<!--CHART:START-->` and `<!--CHART:END-->` in `index.html`. Change `SEED` for different coastlines in the same layout.
4. **Move the labels.** Island names and feature names are `.pt` groups inside `.labels` with a `data-x`, `data-y` and a `data-lod` zoom range. Place them by eye with the preview open. `node assets/chart-generator.mjs --report` prints each island's bounds, peak and extreme points to help.
5. **Repaint.** The palette is a token block at the top of `style.css`.

#### Place attributes

| Attribute | Meaning |
|---|---|
| `data-x`, `data-y` | The camera target on the chart, in chart units (the chart is 3200 by 2000; 50 units is one nautical mile). The marker and route leg end here. |
| `data-span` | How many chart units should fit the margin strip beside the plate. Smaller spans zoom in closer. |
| `data-heading` | Camera turn in degrees on arrival (a few degrees either way). The compass and bearing follow it. |
| `data-name` | The short name used by the rail, the pager and the screen reader announcement. |
| `data-kind` | `about`, `project`, `legend`, `notes` or `contact`. A hook for your own styling. |
| `data-p` | On any element inside a plate that should unfold in order as the plate opens. |

---

### Sections and their hooks

| Part | Hook | What you can change |
|---|---|---|
| Stage | `[data-atlas]` | Carries the chart's frame of reference: `data-world` (width and height), `data-lat0` and `data-lon0` (degrees and minutes at the top-left corner), `data-units-per-nm` and `data-lon-scale`. These only feed the readouts and edge ticks. |
| Chart | `[data-map]`, `[data-world]` | One SVG. Everything between the CHART comments is generated. Route, boxes and labels are hand-authored after it. |
| Layers | `[data-layer="swell"]`, `[data-layer="cloud"]` | The parallax layers under and over the chart. Their `data-depth` documents intent; the rates are in `render()`. |
| Hero | `[data-hero]` | The world view cartouche. `data-hero-in` elements fade in on load. |
| Bar | `.bar`, `[data-rail]`, `[data-prev]`, `[data-next]`, `[data-index-open]` | Brand, chart index rail, pager and the index overlay. |
| Instruments | `.instr` | Scale bar, readouts and compass. Decorative and hidden from assistive technology. |
| Plates | `.plate` | The case studies, about page, legend, journal and contact. |
| Legend | `.legend` | Services as chart symbols. The symbols are `<symbol>` definitions in the SVG `<defs>`. |
| Marginalia | `.note`, `.note-side` | A note and its marginal comment. Stacks on a phone. |
| Signal | `[data-signal]` | The contact form. See below. |
| Index overlay | `[data-index]` | A dialog with focus kept inside and Escape to close. It carries `data-lenis-prevent` because it stops Lenis while open. |

#### The contact form is a static front end

`[data-signal]` checks its fields, lights the beacon on the chart and shows a confirmation, but nothing is sent. It collects a name, an email address, a project type and a message. To make it live, point the form's `action` at a form handler such as Formspree or Netlify Forms, or post it from the submit handler in `initSignal` in `script.js` and light the beacon on success.

#### Tuning the tour

Four numbers near `buildTour` in `assets/script.js` set the pacing, all in viewport heights of scroll: `FLY` (the crossing between places), `OPEN` (the plate unfolding), `READ_MIN` (the least time to read before a plate closes) and `CLOSE`. The tour is about three viewports of scroll per place on a desktop. The script lengthens the reading time of any plate that has to pan a long way, so a tall plate on a phone scrolls at about the pace of the page.

---

### The chart generator

`assets/chart-generator.mjs` is a dependency-free Node script. It builds a height field from the island list, traces contour lines through it and writes:

- shoal tints and depth contours in the water
- the coastline, land fill and four relief rings per island, with hachures
- soundings and rocks awash
- a three-tier graticule and the graduated neatline

Each island entry has a centre (`x`, `y`), a `peak` height in metres, a `rough` value for how ragged its coast is, and `parts`: overlapping ellipses that give the island its shape. Optional `bumps` raise interior hills and `pit` cuts a bay or lagoon. `ring` on a part makes an atoll with a tide gap. `SKERRIES` is a list of loose islets. The result is seeded, so it never changes unless you change the input.

---

### Palette

Colour is a handful of tokens at the top of `style.css`, each with its RGB triple, so every translucent value is mixed from the same source:

| Token | Role |
|---|---|
| `--paper` | The glacier-blue ground and the chart margin |
| `--sea`, `--shoal-1` to `--shoal-4` | Deep water and four shoaling tints |
| `--land`, `--rel-1` to `--rel-4` | Land and four relief steps toward the summit |
| `--navy` | All line work and text on the pale ground |
| `--deep`, `--chalk` | The plate ground and its text |
| `--pop` | Vermilion, reserved for the current position, the active place and calls to action |
| `--pop-ink` | The same colour darkened for small text on pale grounds |

The measured contrast figures for each pairing are written beside the tokens. Vermilion is 4.85:1 against the plate ground and 3.0:1 against paper, so on paper it is only ever a mark or a filled button, never small text.

### Typeface

Ibarra Real Nova carries every name, title and paragraph; B612 Mono carries every readout, tick and label. They are set in `--font-name` and `--font-mono`. Any pair works if the serif is comfortable at reading size and the mono has tabular figures.

### Imagery

No photographs are bundled. The chart is drawn, and each case study carries an inline SVG line drawing (`.plate-fig`) made from the client's own material. Replace a figure with your own artwork by swapping the `<svg>` for an `<img>` with `width` and `height` set, so nothing shifts as it loads. Keep the `figcaption`.

---

### Accessibility and fallbacks

- **Keyboard.** Every place is reachable from the rail, the Index dialog, the previous and next buttons or the footer list. Arriving by keyboard moves focus to the place's heading and announces it politely. Escape closes the index. All controls have a visible focus ring.
- **Screen readers.** The chart is decorative and hidden. The chart index, the pager and the plates carry the same content, and each arrival is announced.
- **Touch.** Vertical swipes drive the tour and a tap on an island flies there. Free pan is mouse only, so nothing fights the page scroll.
- **Interruption.** Any wheel, touch or arrow key stops a flight in progress.
- **Reduced motion.** The tour becomes one place per screen with instant cuts. Every plate is fully visible, a tall plate scrolls inside itself, and all controls work.
- **No JavaScript, or the CDN blocked.** The chart shows at world level with its labels and every case study follows as a stacked section.

### Browser support

Current Chrome, Safari, Firefox and Edge. The chart uses SVG transforms and `clip-path`; no WebGL.

### Dependencies

GSAP 3.12 or later with ScrollTrigger (demo built against 3.15.0). Lenis 1.3 is optional and used only for smooth scroll and for flights.

### Teardown

Everything runs inside one `gsap.context()` exposed as `window.gsapContext`. Call `window.gsapContext.revert()` to remove the tour, the markers, the listeners and Lenis if this script started it. A host's own Lenis is left running.

## 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. The standard license costs £20 one-time and 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.

- [Buy Interactive Map](https://gsapvault.com/templates/interactive-map-template)
- [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
