# Branding Studio Template

> An editorial one-page site for a brand and identity studio: a contents index of typographic plates you throw sideways with a finger, display headings cut in a variable serif that arrive light and set themselves once as they come into view, and a featured project laid out as a proper article with a drop cap, marginalia and numbered notes. Four measured palettes ship.

Canonical: https://gsapvault.com/templates/branding-studio-template
Live demo: https://gsapvault.com/demos/branding-studio-template/index.html

| Property | Value |
|----------|-------|
| Type | template |
| Tier | paid |
| Price | £10 |
| Difficulty | advanced |
| Plugins | ScrollTrigger, Draggable, InertiaPlugin, CustomEase |
| Techniques | draggable, momentum, touch-drag, variable-font, clip-path, mask-reveal, typesetting, scroll-reveal, stagger, keyboard-navigation, progressive-enhancement |
| Uses Lenis | Yes |

## Overview

A production-ready one-page site for a brand and identity studio: naming, identity systems, typography, packaging, editorial design and the guidelines that hold it all together. It ships as a finished site for a fictional eight-person studio, PLINTH, with real disciplines, honest timelines and actual deliverables already written, so what you open reads as a working practice rather than a grid of placeholder headings.

It is set rather than laid out. A pale sage ground, a serif that does both the display and the reading through its optical size axis, folios and hairline rules, marginalia in the outer column, small caps for furniture, and a measured reading column of about sixty-six characters. The oxblood accent is treated as a second ink rather than a button colour: it clears the AA floor on every light surface here, so it sets folios, the drop cap, small-caps labels, links and the pull quote, which is what an editorial page actually needs.

Two things carry it. The contents index is a horizontal run of numbered typographic plates that you throw sideways with momentum, the way you flick through a magazine's contents page, with a progress rail, keyboard access and a native scrolling strip underneath as the fallback. And the type sets itself: every display heading arrives a little light and settles to its resting weight once as it comes into view, then stays put. Nothing on the page follows the scroll, which is deliberate on a layout whose whole argument is that it has been properly set.

Four palettes ship, not one. Sage is the default; Press, Slate and Night are alternate token blocks you switch on with a single attribute on the html element, or copy into place and delete the rest. All four were measured on the same pairs, and Night inverts the page entirely, which is the case that proves why the type colour sitting on an accent fill is its own token.

There is no bundled photography and none is wanted: every plate and mark is set type on a colour field, which is what a branding studio's work actually is. Each plate carries a documented image swap point if you would rather use a photograph. Every section is found by a data attribute and separately guarded, so delete the contents index, the feature, the practice list, the quotes or the enquiry block and the rest keeps running.

## Features

- A contents index of numbered typographic plates that you drag and throw with real momentum, bounded and with a progress rail, which falls back to a native scrolling strip with no JavaScript and under reduced motion
- Display headings cut in a variable serif that arrive light and settle to their resting weight once as they come into view, reading as type being set rather than as motion that follows the reader down the page
- A featured project set as a genuine article: drop cap, a measured column of about sixty-six characters, marginalia in the outer column, a pull quote that breaks the measure, and numbered notes with back-links
- Four measured palettes shipping as token blocks, switched by one attribute, with the type colour that sits on an accent fill kept as its own token because a light accent needs dark type on it and a dark one needs light
- An accent treated as a second ink rather than a button colour, measured past the AA floor on every light surface so it can set folios, labels, links and the drop cap, and explicitly barred from the dark band where it fails
- A practice list of six disciplines set as editorial rows with timings and deliverables, not as a grid of cards
- Text reveals built from clip-path and masked line transforms rather than a text-splitting plugin, so the markup stays plain and readable with no JavaScript
- Touch handled properly on the index: coordinates read from the raw event, movement rather than press committing the gesture, and a direction test so a vertical swipe that starts on the strip still scrolls the page
- One named custom ease used consistently across every reveal, wipe and settle, with a graceful fallback if the plugin does not load
- Every measured contrast ratio written into the stylesheet header, including the two pairs that are banned and why one of them fails silently on a reskin
- Accessible throughout: a complete static document with no JavaScript, a full page under reduced motion with the type axes at rest, a blocked CDN that degrades to the plain document, and keyboard access to every plate that brings the focused one into view

## Use Cases

- Brand and identity studios presenting naming, identity, packaging and guidelines work
- Design studios and consultancies whose output is typographic rather than photographic
- Editorial and print designers who need a site that looks set rather than templated
- Type foundries and lettering practices showing specimens and commissions
- Any studio that sells taste and wants a page that demonstrates it rather than claiming it
- Small practices that need a work index, a case study and an enquiry form on one page

## 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 footer sits outside the enquiry section, so removing that section does not take the colophon with it.

### The contents index

The default is a native horizontally scrolling strip with scroll snapping, which is swipeable, keyboard reachable and works with no JavaScript at all. Only when motion is allowed and both Draggable and the inertia plugin have loaded does the script upgrade it to a thrown, bounded track. Coordinates come from the raw pointer event rather than a cached pointer, nothing commits on a press, and the gesture has to prove itself more horizontal than vertical before it takes over, so a finger that lands on a plate and swipes up still scrolls the page.

### Type that sets itself

Each display heading is found by a data attribute and given one ScrollTrigger that fires a single time as it enters. Its resting cut, optical size and width included, is read back out of the stylesheet at start-up, so restyling a heading in CSS cannot leave the script disagreeing with it. Only the weight moves: changing width would change how much room the words take and reflow the line under the reader. The axes are written by tweening a plain object and setting font-variation-settings from an update callback, naming all three axes, because writing that property wholesale overrides the font weight and optical sizing that CSS set.

### Type reveals without a plugin

Headline lines are wrapped in overflow-hidden masks and moved on both yPercent and y together, because a CSS percentage start state is parsed into pixels and would otherwise leave a stale offset behind. Section titles wipe in on clip-path. Nothing depends on a text-splitting plugin, so the markup you read is the markup that ships and a reader with no JavaScript gets ordinary headings.

### Without JavaScript

The gating class goes on in the head before first paint, so reveal start states apply to the very 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 contents index is a scrolling strip, the headline sits at its resting weight and width, the article is a plain article, and every note and back-link still works.

## 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 folder** and open `index.html` in a browser. That is the whole
site; there is no server to run.

**2. Change the head.** In order down the file:

```html
<title>PLINTH &mdash; Brand &amp; Identity Design Studio</title>
<meta name="description" content="...">
```

**Check that there is no `<meta name="robots">` tag, and leave it that way.**
This template ships deliberately without one, so the site you deploy is
indexable from the first crawl. If you paste one in from somewhere else, make
sure it does not say `noindex`; a `noindex` left in by accident is the single
most common reason a new site never appears in search results, and nothing on
the page will look wrong while it happens.

**3. Replace the copy.** It is all plain markup in `index.html`, in the order it
appears on the page, and each section is fenced by a comment banner:

1. Masthead: wordmark, nav, the three hand-broken headline lines, the standfirst,
   the facts list, the type specimen.
2. Contents: seven plates.
3. Feature: the Marrow write-up, its marginalia and its three notes.
4. Practice: six disciplines.
5. Voices: three quotes.
6. Enquiries: the form and the contact list.

Then the colophon, which sits after `</main>`.

**4. Give the form somewhere to go.** The `<form>` ships with an empty `action`.
See [The enquiry form](#the-enquiry-form) below; this is the one thing on the
page that is not finished, and it has to be done before you take enquiries.

**5. Repaint the seven colour tokens** at the top of `assets/style.css` if the
oxblood-on-sage palette is not yours. See [Palette](#palette), and read the two
banned pairs before you pick an accent.

**6. Ship `assets/script.min.js` instead of `assets/script.js`** if you want the
smaller file. Change the last `<script>` tag in `index.html`:

```html
<script src="assets/script.min.js"></script>
```

Both files do exactly the same thing. `assets/script.js` is the commented one;
keep it around, because the comments are where the reasoning lives.

**The fastest route to making it yours** is the masthead and the contents index,
in that order. The three headline lines and the seven plates are what a visitor
sees before they scroll, and they are the two blocks with the most of PLINTH
left in them. Everything after the fold is prose you can rewrite at leisure.

---

### Accessibility

**No JavaScript** gets the complete document. There is nothing on this page that
only exists once a script runs: the contents index is a native scrolling strip,
the headline sits at its resting weight and width, the article is an article, the
notes and their back-links are ordinary anchors, and the form posts to whatever
you gave it. The gating class that pre-hides reveal targets is added in `<head>`
and never appears without scripting, so none of the hidden start states apply.

**A blocked CDN** degrades to that same plain document rather than to a blank
one. The script's very first act is to check for GSAP and ScrollTrigger together,
and to **remove** `has-js` if either is missing:

```js
if (typeof gsap !== 'undefined' && typeof ScrollTrigger !== 'undefined') {
    gsap.registerPlugin(ScrollTrigger);
    ...
} else {
    document.documentElement.classList.remove('has-js');
}
```

Registering the plugins inside that same guard is deliberate. A bare
`registerPlugin` would throw on a partial CDN failure, with the page already
half-hidden by `has-js` and nothing left to un-hide it.

**Reduced motion** gets a complete, static, readable page. Every reveal target is
restored by the stylesheet's `prefers-reduced-motion` block; the headline stays at
its resting axis values because the script never touches them in that branch; the
contents index stays the native strip; Lenis is never started. The matchMedia
condition set covers **both** states, `no-preference` and `reduce`, so exactly one
branch always matches on every device. A condition set that matches nothing means
GSAP never calls the function at all, and with the stylesheet pre-hiding every
reveal, that would ship a blank page.

**Keyboard.** A skip link jumps to the index. Every plate is a real anchor and
tabs in document order. **Focusing a plate that is off screen brings it into
view**, tweened on the same ease as everything else. That is written by hand and
it has to be: the viewport is `overflow: hidden` in draggable mode, which does not
stop the browser scrolling it to reveal a focused child, it only makes that scroll
invisible and silently desyncs the strip from the transform. So the stray scroll
is zeroed and the movement is done properly.

Only a **keyboard** focus may move the index, tested with `:focus-visible`.
Pressing a plate with a mouse or a finger focuses it too, and without that test
the pressed plate would be scrolled back into full view the moment you let go of a
drag, which reads as the whole index springing back to where you started.

**The notes in the feature** are a real ordered list with `id`s. Each reference in
the prose is an anchor to its note, and each note carries a back-link with an
`aria-label` ("Back to reference 1"), so a reader can go down and come back
without losing their place.

**Other structure worth keeping if you edit:**

- Sections are `<section>` with `id`s; the nav and colophon nav are real `<nav>`
  elements with `aria-label`s.
- Facts and contact details are `<dl>`s; quotes are `<figure>`/`<blockquote>`/
  `<figcaption>`; the type specimen is a `<figure>` with a `<figcaption>`.
- The contents viewport is `role="group"` with an `aria-label`, so its purpose is
  announced.
- The enquiry status line is `role="status"` with `aria-live="polite"`, so the
  confirmation is read out without stealing focus.
- Every form control has a real `<label>` bound by `for`, with `autocomplete`
  where one applies.
- The focus ring is `2px solid var(--accent)` with `3px` offset everywhere except
  the two dark sections, where it is cream. Do not remove it.
- Purely decorative type, the plate art and the specimen glyph, is
  `aria-hidden="true"` so a screen reader is not read a wall of monograms.

---

### Browser support

Current Chrome, Firefox, Safari and Edge, on desktop and mobile. Everything below
degrades rather than breaks, but it is worth knowing what degrades to what.

| Feature | Used for | Without it |
|---|---|---|
| **Variable font axes** (`font-variation-settings`) | the heading settle, and every display cut on the page | The declarations are ignored and the serif renders at a static weight. Headings still set, still legible, just not tuned. The headline effect has nothing to move; the specimen still prints numbers, which is the one place it would look odd |
| **`clip-path`** | the section-title wipe | The declaration is dropped, so the title is simply visible from the start. Nothing is hidden |
| **CSS scroll snapping** | the contents strip in fallback mode | The strip still scrolls horizontally, it just does not settle on a plate |
| **`aspect-ratio`** | plate art, keeping every plate 4:5 | Plate art collapses to its content height. Set an explicit height on `.plate-art` if you need to support a browser this old |
| **`:focus-visible`** | keeping mouse and touch presses from moving the index | The script catches the exception and assumes keyboard, which is the safe direction: focus still brings a plate into view |
| **`overflow-x: clip`** | stopping horizontal overflow on `<html>` and `<body>` | Falls back to no clipping. Add `overflow-x: hidden` if you see a horizontal scrollbar |
| **`overscroll-behavior-x`** | stopping a swipe on the index triggering a back gesture | The browser's own edge gesture may fire |
| **`-webkit-text-stroke`** | the outline mark on plate 07 | The type renders transparent and the mark disappears. Give that plate a different treatment if it matters |

Also used throughout, and safe in every current browser: CSS custom properties,
`clamp()`, `min()`/`max()`, CSS grid, `ch` units, `font-variant-numeric`,
`scroll-padding-inline-start`, and `document.fonts.ready` (guarded, so the page
works without it).

The page is built mobile-first in the sense that matters: there are three
breakpoints (`64rem`, `52rem`, `40rem`), the marginalia move from an outer column
to an accent-ruled note above the paragraph on narrow screens, the discipline rows
drop their third column, and the contents index behaves the same on a phone as on
a trackpad.

## 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 Branding Studio Template](https://gsapvault.com/templates/branding-studio-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
