Lossless Changelog
product

Vibrant Mode, Brand Mark Wrapper, and Animated Grain Overlay

Differentiated vibrant mode with a distinct background color, added mode-aware brand mark switching in the header, introduced an animated SVG grain noise overlay with per-mode intensity, added --fx-flare-color token for mode-adaptive canvas elements, and extended the --fx-* effect token system.

Michael StatonMusic Editoraugmented with Claude Code on Opus 4.6

Changelog - 2026-04-20 (03)

Vibrant Mode, Brand Mark Wrapper, and Animated Grain Overlay

Overview

Three related improvements to the banner-site's visual identity and mode system: vibrant mode now has a visually distinct background, the header brand mark swaps automatically based on light/dark/vibrant mode, and the homepage has an animated static grain noise overlay inspired by the existing bannervc.com Squarespace site.


New Named Brand Colors

Added two new named colors to the emblem theme's :root block in emblem-theme.css:

  • --color-navy-blue: #0059DE — deep vivid blue

  • --color-blue--fierce: #040bf4 — intense electric indigo-blue

These follow the existing convention of named brand colors defined once in :root and referenced by mode-specific token selectors.

Vibrant Mode Background

Previously, vibrant mode shared the same --color-haiti-blue (#141531) background as dark mode, making the two modes nearly indistinguishable. Vibrant mode now uses --color-blue--fierce (#040bf4) as its background — a saturated indigo-blue that immediately communicates the mode switch.

SiteBrandMarkModeWrapper Component

New component at src/components/ui/SiteBrandMarkModeWrapper.astro — renders both a light-background and dark-background brand mark image, toggling visibility via CSS based on the active data-mode attribute on <html>.

How it works:

  • Renders two <img> tags inside a height-constrained wrapper

  • CSS selectors html[data-mode="dark"] and html[data-mode="vibrant"] hide the light variant and show the dark variant

  • Light mode shows the light variant by default

  • No JavaScript required — pure CSS driven by the same data-mode contract as all theme tokens

Design decisions (improvements over the TWF reference implementation):

  • Accepts lightSrc / darkSrc as props instead of hardcoding paths

  • Supports vibrant mode (TWF only handled light/dark)

  • No !important — html[data-mode] ancestor specificity is sufficient

  • No .dark class fallback — banner-site uses data-mode exclusively

  • Height-constrained wrapper with h-full w-auto images for consistent sizing

Header integration:

  • Light mode shows trademarks__BannerVC--Brand-Blue.webp (blue mark on light background)

  • Dark and vibrant modes show trademarks__BannerVC.webp (white/light mark on dark background)

Animated Grain Noise Overlay

Added an SVG feTurbulence-based animated grain effect to the homepage, replicating the static noise texture from the existing bannervc.com Squarespace site.

Implementation:

  • An inline SVG defines a <filter id="grain"> with feTurbulence (fractal noise) and feColorMatrix (desaturation)

  • <animate> cycles the turbulence seed from 0 to 100 over 1.5 seconds on repeat, creating the flickering grain

  • A ::before pseudo-element on .homepage references the filter via filter: url(#grain)

  • Fixed positioning covers the full viewport; pointer-events: none keeps it non-interactive

Tunable parameters:

  • baseFrequency="0.40" — grain particle size (lower = larger, higher = finer)

  • numOctaves="3" — noise detail layers

  • dur="6.0s" — flicker animation speed (slowed from 1.5s for subtlety)

Per-mode grain intensity (--fx-grain-opacity):

The grain overlay opacity is now a theme token rather than a hardcoded value. Each mode gets the right intensity for its background:

Mode--fx-grain-opacityRationale
Light0.18Bright backgrounds wash out noise — needs more punch
Dark0.12Natural contrast on dark navy — already visible
Vibrant0.20Saturated blue bg competes with the grain — extra intensity

The overlay covers the entire viewport including header and footer (z-index: 9999, pointer-events: none), giving the page a unified film-grain texture across all elements.

Mode-Adaptive Flare Color (--fx-flare-color)

Three.js canvas elements (like FlagPixel) resolve CSS variables once at construction time and bake the color into the WebGL material. When the user toggles modes, the CSS variable changes but the canvas doesn't re-read it.

Solution: Added --fx-flare-color token per mode, plus a MutationObserver in FlagPixel that watches data-mode on <html> and re-resolves the CSS variable to update the Three.js material live.

Mode--fx-flare-colorContrast against background
Light--color-brand-blue-deep (#003DB3)Dark on ivory
Dark--color-brand-blue-bright (#2B7AFF)Bright on haiti-blue
Vibrant--color-electric (#60A5FA)Light blue on fierce blue

The homepage flare now uses var(--fx-flare-color) instead of var(--color-primary), so the flag is always visible regardless of mode.

Blueprint Documentation

Updated context-v/blueprints/Maintain-Themes-Mode-Across-CSS-Tailwind.md:

  • Section 8: SiteBrandMarkModeWrapper pattern — motivation, code snippets, integration with the mode system, design decisions, and a porting checklist.

  • Section 9: Effect tokens (--fx-*) — the canonical token naming convention, per-mode intensity scaling, how CSS and Three.js components consume the tokens differently, and the porting strategy for new sites.