# Advertising Agency Template

> A one-page site for a full-service ad agency, opening on a hero whose background is a pinned, scroll-scrubbed reel of location photography, before a capabilities marquee that skews in proportion to how fast the visitor is scrolling right now, tracked live with the GSAP Observer plugin. Six real campaign case studies with results stats, a CSS-only discipline filter, and an honest process rail sit either side of it.

Canonical: https://gsapvault.com/templates/advertising-agency-template
Live demo: https://gsapvault.com/demos/advertising-agency-template/index.html

| Property | Value |
|----------|-------|
| Type | template |
| Tier | paid |
| Price | £10 |
| Difficulty | intermediate |
| Plugins | ScrollTrigger, SplitText, Observer, CustomEase |
| Techniques | image-sequence, canvas, pinning, scrub, mask-reveal, text-animation, scroll-reveal, stagger, skew, velocity-tracking, magnetic, count-up, filter, progressive-enhancement, keyboard-navigation |
| Uses Lenis | Yes |

## Overview

A production-ready one-page site for a full-service advertising agency. It ships as a finished site for a fictional six-person shop, VOLUME, with six real campaign case studies, results stats, plain discipline tags and a written process, so what you open reads as a working agency rather than a grid of placeholder headings.

The hero's background IS the reel: sixty real photographs from a night shoot, pinned and scrubbed frame by frame as you scroll, your scroll position as the actual playhead, while the headline and stat strip hold in place on top of it. Straight after it, the capabilities marquee does not just scroll: it reads live scroll velocity with the GSAP Observer plugin and skews the whole track in proportion to how fast you are moving right now, clamped to a sane maximum and snapped back to level with a CustomEase the instant you stop. Flick the page hard and the type leans into the flick; let it settle and the type settles with it.

Around that sit six campaign cards, each fronted by a graded photograph and a real result stat, a CSS-only discipline filter that keeps working with JavaScript switched off, a mouse-following tilt on the cards for fine pointers, a calmer constant-speed client-logo marquee running the other direction for contrast, and an enquiry form that asks what an agency actually needs to know before the first call.

Every photograph is a bundled, optimised, art-directed derivative: source stills and the hero's frame sequence are graded into VOLUME's own duotone before shipping, never redistributed untouched. Every section is found by a data attribute and separately guarded, so delete the marquee, the work grid, the process or the enquiry block and the rest keeps running.

## Features

- A hero whose background is a pinned, scroll-scrubbed reel of sixty graded photographs, scroll position as the actual playhead, the headline and stat strip holding in place on top of it
- A capabilities marquee that skews proportionally to live scroll velocity via the GSAP Observer plugin, clamped to a sane maximum and snapped back to level with a quickTo driven by a CustomEase the instant scrolling settles
- A second, calmer marquee of client wordmarks at constant speed running the opposite direction, for contrast against the loud capabilities strip
- Six campaign case studies, each with a discipline tag and a count-up results stat, in a CSS-only filter built on :has() and radio inputs that keeps filtering with JavaScript disabled
- A mouse-following tilt on every case study card for fine pointers, with a static press state as the touch fallback and a focus-visible equivalent for keyboard users
- A stacked, multi-line SplitText hero headline that reveals on load inside overflow masks, with a positioning statement and a four-figure stat strip underneath
- A five-step process rail, scroll-revealed rather than pinned, explaining how the agency actually works
- An enquiry form matched to what an agency needs to qualify a lead: organisation, budget band, project type and a message
- Bundled, optimised WebP photography for the reel and every case study card, each one an art-directed derivative graded into VOLUME's duotone, never a redistributed original
- Every measured contrast ratio written into the stylesheet header, including why the accent is barred from small body text and where it is allowed as large display type
- Accessible throughout: a complete static document with no JavaScript, a full page under reduced motion with the hero unpinned on a single frame and both marquees frozen, and a blocked CDN that degrades to the plain document

## Use Cases

- Advertising and campaign agencies that need a site for their own business
- Small full-service shops selling brand strategy, film, social, OOH and experiential work
- Freelance creative directors or strategists presenting a portfolio of campaign results
- Any agency that wants to lead with results stats rather than a mood-board wall
- Consultancies that want a confident, brash tone rather than a neutral corporate one
- A starting point for any results-driven service business, since every section is independent

## 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 script initialises every section inside a single gsap.context, with one gsap.matchMedia whose condition sets cover coarse pointers as well as desktop, so exactly one branch runs on every device. Each block is found by a data attribute and returns early if it is absent, so deleting any section leaves the others working. The page is a complete static document before any script runs.

### The reel

The hero and the reel are the same section. Sixty photographs preload as Image objects, and a pinned ScrollTrigger maps its scrub progress to a frame index, drawing the nearest loaded frame to a canvas on every update: your scroll position is the actual playhead, not a simulated one. The headline and CTAs are revealed separately on load, then simply hold in place, pinned, while the footage plays behind them. The canvas stays transparent until every frame has decoded, so the plain <img> fallback underneath is what a slow connection or JS-off visitor sees, behind ordinary, unpinned text.

### The velocity marquee

An Observer instance watches wheel, touch and pointer scrolling and reports velocity on every change. That velocity is clamped and mapped to a skewX value applied to the marquee track with a quickTo, so the type visibly leans harder the faster you flick the page. A short idle timer watches for the scrolling to stop; once it does, a second quickTo built on a CustomEase eases the skew back to level. The horizontal scroll itself is a separate, constant-speed loop, so the marquee never stops moving, only leans.

### The discipline filter

Filtering is a CSS :has() selector reading the checked radio input and hiding case studies whose data-tags do not match, so it keeps working with this file deleted entirely. JavaScript only adds a stagger fade on the cards left visible after a change, which is why nothing about the filtering itself depends on script.js running.

### The tilt cards

On a fine pointer, each case study card tracks the cursor and quickTo's rotateX and rotateY toward it, releasing back to flat on pointerleave. A coarse pointer gets a static pressed state on pointerdown instead of a continuous tilt, and keyboard focus gets its own lifted state through :focus-visible, so nothing about the card's information depends on being able to hover it.

### Without JavaScript

The gating class goes on in the head before first paint, so reveal start states apply to the first frame and nothing is painted visible and then hidden; the script removes that class when GSAP is missing, so a blocked CDN degrades to the plain document. With scripting off the hero's canvas never receives a frame, so its plain photograph shows behind the headline in normal flow, nothing pinned; both marquees render as a single static row of the same terms, the filter still filters, and every stat shows its final value.

## Integration Preview

How this effect integrates into a page. The full documentation (examples, events, programmatic API, customization guide) ships with the download.

### Quick Start

1. Copy the whole `advertising-agency-template` folder to your site.
2. Open `index.html` in a browser — it works immediately, no build step.
3. Replace `VOLUME` with your own name throughout `index.html` (the
   wordmark, `<title>`, the footer legal line and the `mailto:`/`tel:`
   links).
4. Rewrite the copy: the hero headline and lede, the six case studies, the
   process steps and the contact details are all real prose written for a
   fictional agency, not lorem ipsum. Swap in your own.
5. Repoint `assets/style.css`'s `--accent` (see **Brand colour**, below) if
   vermilion is not your colour.
6. Wire up the contact form's `action` attribute to your form handler
   (Formspree, Basin, Netlify Forms, or your own endpoint).

Everything is plain HTML, CSS and JavaScript. There is no bundler, no
package manager and no build step — deploy the folder as static files
anywhere.

### Dependencies

```html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/SplitText.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/Observer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/CustomEase.min.js"></script>
<script src="https://unpkg.com/lenis@1.3.17/dist/lenis.min.js"></script>
<script src="assets/script.js"></script>
```

Lenis is optional. Smooth scroll is opt-out (`data-smooth="off"` on
`<html>`, or `?smooth=off` in the URL) and is also off automatically under
`prefers-reduced-motion`. Delete the Lenis `<script>` tag and its block in
`script.js` to drop it entirely; nothing else depends on it.

These CDN tags carry no `integrity` attributes on purpose — a template is
deployed to a buyer's own domain, and a stale SRI hash would break their
site the next time GSAP ships a patch release.

### Accessibility

- **No JavaScript**: the whole page is a complete, readable static
  document. The hero's canvas never receives a frame, so its plain `<img>`
  fallback shows behind the headline in normal flow, nothing pinned; both
  marquees render as a single static row of the same words (no duplicated
  copy, no motion), the discipline filter still filters (it is CSS, not
  JavaScript), and every stat shows its final value.
- **Reduced motion**: the hero never pins or loads its frame sequence at
  all — the fallback photograph and the headline show immediately, both
  marquees freeze on one frame, the hero headline is fully visible with no
  mask animation, counters show their final values immediately, and
  nothing needed for the page to make sense is hidden behind a state only
  `prefers-reduced-motion: no-preference` reaches.
- **Keyboard**: every interactive element is a real `<button>`, `<a>` with
  an `href`, or form control. The work-card tilt has a keyboard-reachable
  equivalent (`:focus-visible` lift) independent of the pointer-driven
  version, and the discipline filter is native radio inputs, fully
  operable by keyboard alone.
- **Blocked CDN**: `script.js` removes the `has-js` class if `gsap` or
  `ScrollTrigger` fail to load, which un-hides everything the CSS had
  pre-hidden for the animated version. The page degrades to the same
  static document described above.

### Browser support

Built on `:has()`, which is required for the discipline filter and has
been supported in every major evergreen browser (Chrome, Edge, Firefox,
Safari) since 2023. In a browser without it, the filter chips are visible
but inert and every case study shows — a safe, readable fallback, not a
broken one.

## 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 £10 one-time and covers unlimited personal and commercial projects with no attribution required. The only restrictions: no redistribution of the code itself and no competing effect libraries.

- [Buy Advertising Agency Template](https://gsapvault.com/templates/advertising-agency-template)
- [Effects & Templates Vault (£39 one-time, best value): every current and future effect and template](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
