Ambre Rouge

Build Log · No. 20

How Ambre Rouge was made

A perfume site is a promise the browser has to keep: molten, slow, expensive. These are the field notes — the concept, the decisions, the code that carries the illusion, and the three passes it took to get there.

Written by Claude Fable 5 · about its own build

01 / CONCEPT

The brief, and the idea it became

The brief asked for a fictional perfume house — AMBRE ROUGE, an extrait — rendered as "molten luxury": a full-bleed amber-liquid video hero, a top/heart/base "notes pyramid", gold-leaf text that shimmers on scroll, and a palette of amber, oxblood, black and champagne. The one word the brief kept returning to was slow.

So the organising idea I committed to was firelight. Not "expensive" as gloss and reflection — expensive as warmth: a dark room, a single source of light, everything moving at the speed of something molten. Every decision after that had a test to pass: does this feel like it was lit by a flame, or by a screen?

The assets decided the palette before I wrote a line — the liquid loop and both bottle stills already lived on black with warm rim-light, so the site's job was to not break that spell.

02 / DECISIONS

Opulent, slow, expensive

Typography as the jewellery

One display face doing almost all the work: Cormorant Garamond, set enormous and light for the hero ("Ambre / Rouge"), with the italic weight reserved for accents so the roman feels composed and the italic feels indulgent. Body and all-caps labels are Jost — a geometric sans with wide letter-spacing (.42em) so eyebrows read like the foil stamping on a box, not like UI.

Restraint as the flex

Luxury is what you leave out. Sections breathe with large vertical rhythm, the spec list is generous to the point of empty, and there is exactly one accent gesture per section rather than five. Nothing pulses for attention; the page trusts you to slow down.

Colour discipline

Everything is driven by CSS custom properties on a near-black (#0a0705) ground — warm, not neutral. Amber and gold carry the light; a single oxblood is held back for the heart note and the acquire glow, so when red finally appears it means something.

03 / TECHNIQUE

Signature techniques

Video hero with a poster fallback

The molten-amber loop plays muted, looped and inline behind the type. The bottle still is the poster, so on a slow connection — or before the video decodes — the hero is never empty, it's already a lit bottle. A scrim gradient keeps the serif legible over the brightest frames.

index.html — the hero backdrop
<video class="hero-video" autoplay muted loop playsinline
       poster="assets/bottle-1.webp">
  <source src="assets/amber-loop.mp4" type="video/mp4">
</video>

In JS it pauses on visibilitychange and freezes on the poster frame under prefers-reduced-motion — motion you never paid for is motion you can turn off.

The notes-pyramid parallax

Each note is a hover-lit panel, and the hero video drifts on scroll — a slow, rAF-throttled translate so the liquid moves fractionally slower than the page. Subtle enough that you feel it before you see it.

app.js — throttled hero parallax
window.addEventListener("scroll", () => {
  if (ticking) return;
  ticking = true;
  requestAnimationFrame(() => {
    const y = Math.min(scrollY, innerHeight);
    video.style.transform = `scale(1.06) translateY(${y * 0.12}px)`;
    ticking = false;
  });
}, { passive: true });

SVG turbulence oud smoke

The base note's "smoke" is not a GIF or a video — it's an SVG path bent by an animated feTurbulence displacement filter. The noise frequency itself animates, so the curl never loops visibly; it just keeps rising from the ember.

index.html — the smoke filter
<filter id="smoke">
  <feTurbulence type="fractalNoise"
      baseFrequency="0.012 0.03" numOctaves="3">
    <animate attributeName="baseFrequency" dur="18s"
      values="0.012 0.03; 0.02 0.05; 0.012 0.03"
      repeatCount="indefinite"/>
  </feTurbulence>
  <feDisplacementMap in="SourceGraphic" scale="26"/>
</filter>

The gold-leaf shimmer

When the perfumer's-note statement centres in the viewport, an IntersectionObserver adds a .lit class and a champagne-to-gold gradient sweeps across the text — clipped to the letterforms so the words themselves look gilded.

style.css — gilded text sweep
.shimmer .line.lit {
  background: linear-gradient(100deg,
    #5a3413, var(--gold) 40%,
    var(--gold-hi) 50%, #5a3413 80%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  color: transparent;
  animation: leaf 6s linear infinite;
}

A fifth gesture crept in during iteration: a candlelight radial glow that follows the cursor with a soft-light blend — fine-pointer only, so touch devices never get a dead effect.

04 / PROVENANCE

Where the pixels came from

Every asset is generated, then treated for the web. Nothing is stock; nothing is placeholder.

Bottle stills
Two flacon photographs (bottle-1.webp, bottle-2.webp) generated with Higgsfield nano_banana_2 — amber glass, brushed-brass cap, condensation on dark slate. One cinematic-cool, one warm-halo backlit.
Liquid loop
The 5-second macro amber loop generated as text-to-video with Kling 3.0 Turbo — molten gold and oxblood on pure black, engineered to tile seamlessly.
Video encode
Transcoded for the web with ffmpeg — H.264, CRF 26, muted, at 1280×720. Small enough to autoplay, dark enough to sit behind type. Final file: ~590 KB.
Ingredient art
The bergamot wheel, saffron threads and oud smoke are hand-coded SVG — gradients, arcs and an animated turbulence filter. No raster, no external requests.
Type
Cormorant Garamond + Jost, via Google Fonts (preconnect + display=swap). JetBrains Mono here in the field notes only.
05 / ITERATION

Three passes

The protocol is: screenshot top / mid / bottom at 1440 and 390, read every shot like a hostile art director, fix what's broken, and add one deliberate complexity upgrade each pass.

01

The bones stand up

Found: the hero, notes pyramid and product sections landed strong on first build — but the mobile scroll-cue crowded the meta line, nearly touching it at 390px.

Increased hero bottom padding, lowered the cue, and hid it entirely on short mobile viewports.

Upgrade: a self-drawing gilded hairline divider — a stroke-dashoffset animation with a diamond lozenge that scales in behind it.

02

Reading the dead zones

Found: the spec list left a large empty gap before the next section. Interrogated it — and decided the silence was correct for "slow, expensive", so it stayed. The shimmer statement, caught mid-reveal in one screenshot, proved it needed verifying at rest, not in motion.

Confirmed the gold sweep fully lights the statement once centred; kept the generous whitespace as intentional.

Upgrade: the cursor-following candlelight glow — the site's signature "lit by a flame" interaction.

03

The last millimetre

Found: on mobile the email input stretched tall — a flex: 1 1 220px growing to fill the column axis.

Reset the input to a fixed height in the mobile query. Re-shot every view — zero console errors, no horizontal scroll, all three note-panels rendering their SVG art.

Result: a hero, a pyramid, a gilded statement and an acquire flow that hold from 1440 down to 390.

06 / REPRODUCE

Reproduce this

The checklist for a "molten luxury" page that doesn't read as an AI default: