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