← Back to Meridian & Sons

Design Guide

Building Meridian & Sons

A record of the brief, the system, and the techniques behind the site, written in the same design language it documents. Every code block below is lifted from the shipping page.

01 · The Brief

Old money luxury, taken apart on camera.

Meridian & Sons is a fictional independent watchmaker, founded 1911, now in its fourth generation. The brief called for near black, champagne gold, hairline rules, and enormous negative space: the visual grammar of a house that has never needed to shout.

The signature moment is a scroll scrubbed teardown of the house caliber. Rather than faking the movement with vector discs, the final build scrubs a filmed bench plate, 75 frames of the watch physically separating into its nine layers above a workbench, driven frame by frame by the visitor's scroll and annotated with engraved callouts, an instrument HUD, and a live parts counter. Around it: bespoke macro photography graded entirely in code, three references photographed on one set with prices and a private inquiry flow, and a heritage ledger whose running count spins through a century of entries.

Because this is a sales page for a considered physical purchase, the conversion path never hides: a phone number in the header on every screen, an inquire button on each reference, and a closing private viewing offer built for a buyer who wants to hold the watch before deciding.

02 · Palette and Type

Two metals do the work of ten colors.

The palette is deliberately small: a near black stage, one warm surface tone, one ivory text color, and exactly two metals, a bright champagne gold and a darker bronze. Every accent on the page comes from these two golds at different weights and opacities, so nothing competes with the watches themselves.

Background#0B0A08
Surface#141210
Text#E8E2D6
Gold#C9A96A
Bronze#8B6F3D

Near black reads as a display case under a single spotlight, not a dark mode retrofit. Champagne gold is desaturated enough to sit on screen for minutes without fatiguing the eye. Bronze exists purely as gold's shadow, used for borders and secondary metal, so the brighter gold stays reserved for the moments that should pull focus: prices, CTAs, callout numerals, the running ledger count.

Display · Cormorant Garamond

Four generations of measured time.

Body · Jost

Every Meridian timepiece is assembled, adjusted, and signed by hand in our atelier.

Cormorant Garamond carries the emotional weight of the brand the way engraving would on a caseback, and its true italic becomes the site's second voice: every emphasized word, ghost numeral, and callout number is set in it. Jost is a geometric sans in the Futura tradition, quiet and even at small sizes, built for specification tables and interface copy that need to disappear so the numbers can talk.

03 · The Techniques

How the effects actually work.

IThe filmed teardown, scrubbed frame by frame

The signature is a 75 frame webp sequence of the caliber physically coming apart on the bench, played by scroll position inside a 340vh pinned section. All frames are preloaded into Image objects on first approach; each rAF tick maps eased progress to a frame index and swaps the single img.src only when the index changes, so a full scrub costs at most 75 image swaps and zero layout work.

var FILM_N = 75, filmImgs = [], filmIdxLast = -1;
function filmSrc(i){ return 'img/mv/seq/f' + (i < 10 ? '0' + i : i) + '.webp'; }

/* inside the scrub, after easing */
var pf = clamp01(p / .78);            /* reel completes at 78% of the runway */
var fi = Math.round(pf * (FILM_N - 1));
if (fi !== filmIdxLast){
  filmIdxLast = fi;
  var im = filmImgs[fi];
  mvFilm.src = (im && im.complete) ? im.src : filmSrc(fi);
}

The film sits in a fixed 16:9 box with a thin radial feather mask at the edges only, so the separated case, caseback, and straps stay fully visible through the whole scrub while the photograph's stage melts into the page black.

IINumeric scrub: the quarter second of cinema

The teardown never binds one to one to the scrollbar. Each frame the target progress is measured, then the displayed progress chases it with a time based exponential, roughly a quarter second of catch up, the same feel as a numeric scrub value in scroll libraries. Runway is budgeted per device: 340vh of pin on desktop, 300vh on a phone, where the choreography also changes to fewer beats and a vertical stack gauge replaces the side callouts.

var pS = 0;                              /* smoothed progress */
function updateScrub(dt){
  var pT = clamp01(-rect.top / total);   /* raw scroll progress */
  pS += (pT - pS) * Math.min(1, dt * 5.5);   /* ~250ms catch up */
  if (Math.abs(pT - pS) < .0004) pS = pT;
}

IIIPhotography graded in code, revealed by the scrollbar

The two full bleed photographs, the loupe macro and the bench at dawn, are staged rather than placed: a stack of gradient grades supplies the lighting direction, a gold overlay warms the highlights, film grain rides above, and the frame opens from a letterboxed sliver as it enters, its inset clip driven 1:1 by scroll while the image drifts on a slow parallax.

.loupe-media{
  clip-path:inset(calc(var(--lc) * 11%) calc(var(--lc) * 6%)
                  calc(var(--lc) * 11%) calc(var(--lc) * 6%));
}
/* JS, linear, tied 1:1 to scroll (scrubbed motion takes no easing) */
var open = clamp01((vh * .88 - r.top) / (vh * .55));
b.root.style.setProperty('--lc', (1 - open).toFixed(4));
b.img.style.transform =
  'translateY(' + ((drift - .5) * -60).toFixed(1) + 'px) scale(1.06)';

IVVitrines: masked photographs that live in the room

The three collection photographs were shot on the same near black set the site is built from, every dial at eight minutes past ten. Each sits under a radial mask so its edges dissolve into the page, a breathing halo supplies the key light, and on arrival the photo opens like a loupe finding focus. Once revealed, a clipped highlight bar sweeps the crystal every few seconds, staggered per reference so the room feels lit rather than triggered. Clicking a vitrine commits: it opens the private inquiry for that reference.

.tp-photo img{
  mask-image:radial-gradient(ellipse 64% 64% at 50% 48%, #000 52%, transparent 84%);
}
.tp-iris .tp-photo img{ clip-path:circle(16% at 50% 47%); opacity:0;
  transition:clip-path 1.5s cubic-bezier(.65,.05,.36,1), opacity .7s; }
.tp-iris.in .tp-photo img{ clip-path:circle(75% at 50% 47%); opacity:1; }
.tp-stage.in .tp-glint::after{
  animation:tpGlintLoop 3.2s cubic-bezier(.65,.05,.36,1) infinite;
  animation-delay:var(--gd,0s);            /* staggered per reference */
}

VThe running ledger count

The heritage timeline is a ledger, so the right page of the spread keeps count. A sticky panel holds an outlined italic numeral that spins from No. 0001 to No. 11,048 as the visitor scrolls the century, while a year plate swaps to whichever entry is being read. One scroll progress value drives the rail, the count, and the year, and each entry's dot is struck gold as it arrives.

var t = clamp01((vh * .8 - r.top) / r.height);   /* section progress */
hgRail.style.transform = 'scaleY(' + t.toFixed(4) + ')';
var n = Math.max(1, Math.round(1 + smooth(t) * (11048 - 1)));
if (n !== lastLedgerNo){ hcNo.textContent = 'No. ' + fmtLedger(n); }

VIOne rAF loop, a cursor that reads the room

Every per frame behavior on the page, the film scrub, the parallax bands, the ledger count, the magnetic buttons, and the custom cursor, runs inside a single requestAnimationFrame loop with time based lerps, so there is exactly one scheduler to budget. The cursor is a dot plus a trailing ring that grows on any link and swaps to a labeled state, Inquire, Call, over elements that declare data-cursor. Fine pointers only; touch and reduced motion never see it.

ringX += (curX - ringX) * .16;             /* the ring trails the dot */
m.x += (m.tx - m.x) * .18;                 /* magnetic CTA settles home */
document.addEventListener('mouseover', function(e){
  var lab = e.target.closest('[data-cursor]');
  if (lab){ ringLabel.textContent = lab.getAttribute('data-cursor');
    ring.classList.add('has-label'); }
});

VIIThe identity opening

The first second is staged: a drawn dial ring and a sweeping hand over the wordmark, gone in 1.25 seconds, skippable by the first wheel or touch, and never shown to visitors who prefer reduced motion. The hero then staggers in, and the masthead's ten letters rise out of a masked line one by one, 45 milliseconds apart.

.gate-dial .ring{ stroke-dasharray:264; stroke-dashoffset:264;
  animation:gateRing 1.05s cubic-bezier(.65,.05,.36,1) .1s forwards; }
/* masthead letters, built once, staggered by index */
s.style.transitionDelay = (0.42 + i * 0.045) + 's';
window.addEventListener('wheel', finish, { passive:true, once:true });

VIIISpecification tables set like instrument paper

Every spec list is a definition list with a dotted leader between a tracked gold label and a right aligned value in tabular numerals, so prices and measurements align like a printed spec sheet rather than wrapping like prose.

.spec-row{ display:flex; align-items:baseline; gap:1.2rem;
  border-bottom:1px solid var(--line); }
.spec-row .leader{ flex:1; border-bottom:1px dotted rgba(201,169,106,.28); }
.spec-row dd{ font-variant-numeric:tabular-nums; text-align:right; }

04 · Replicate It

Build your own filmed teardown.

Lock the palette and type first

One background, one surface, one text color, two metals at most. Load the display and body fonts before writing a line of layout CSS, and give the italic a job.

Shoot or render the sequence

Produce 60 to 90 frames of the object separating on a locked camera, export as webp at 1280 wide, and name them sequentially. Keep the full separation inside the frame on every frame; the scrub cannot crop later.

Pin a tall stage

Wrap a 100svh sticky stage in a 300 to 340svh section. Compute progress from the wrapper's bounding rect, clamped 0 to 1. Budget less runway on phones, never more.

Preload, then swap one src

Warm every frame into an Image object the first time the section approaches. Map eased progress to a frame index and write img.src only when the index changes.

Chase the scrollbar, do not ride it

Keep a smoothed progress that follows the raw value with a time based lerp of about a quarter second. Scrubbed motion itself takes no easing curve; the lag is the cinema.

Annotate outside the film

Callouts, HUD readouts, and counters live in flat overlay layers tied to the same progress value. On phones, trade side callouts for a vertical gauge and a caption chip; hit areas stay 44px.

Respect the opt outs

Under prefers-reduced-motion, unpin the section, show the final exploded frame as a static figure with all callouts on, and delete the runway so no one scrolls through dead viewports.

Verify like a juror

Screenshot every viewport of the page at 1440 and 390, judge each against the hero, confirm zero console errors and zero horizontal scroll, and click everything that looks clickable.

05 · Tools Used

What actually built this.

Claude Fable 5Design direction, copywriting, and every line of markup, CSS, and JavaScript on this site, iterated against full page screenshot audits at desktop and mobile widths.
Hand written HTML, CSS, JSNo framework, no build step, no component library. One inline stylesheet, one inline script, zero dependencies beyond the browser.
Bespoke photography and filmFive brand photographs and a 75 frame teardown sequence, shot on one near black set, then graded, masked, and choreographed entirely in code.
Google FontsCormorant Garamond, Jost, and JetBrains Mono for this guide's code blocks. The only external requests the site makes.
Browser APIs onlyIntersectionObserver for reveals, requestAnimationFrame for the single master loop, CSS custom properties as the wiring between scroll math and paint.