02b2ce8109
Same treatment as the seasonal themes: split the 502-line chatBackground.ts Record into one premium module per background under lotus/backgrounds/ (each exposes a tuned dark + light ChatBgVariants), one Opus agent per background against a shared brief. chatBackground.ts now assembles DARK/LIGHT from the modules; getChatBg is unchanged. Carbon + Aurora are kept inline as-is (user favorites); none stays the empty layer. Every redesign: layered oklch palettes, seamless tiling with worked-out tile math (integer-multiple periods; edge-wrapping inline-SVG data-URIs for circuit/hexgrid/waves/herringbone/chevron/tactical), independently-tuned dark+light (not a recolor), and low "felt-not-read" opacity so chat text stays WCAG-AA legible. The 5 animated backgrounds (rain, star drift, grid pulse, aurora flow, fireflies) each colocate a vanilla-extract keyframe .css.ts, animate only background-position for a jump-free loop, and — since getChatBg strips animation for reduced-motion — render a finished static frame too. Redesigned: blueprint, stars, topographic, herringbone, crosshatch, chevron, polka, triangles, plaid, tactical, circuit, hexgrid, waves, neon, anim-rain, anim-stars, anim-pulse, anim-aurora, anim-fireflies. Gates: tsc clean, ESLint clean, Prettier clean, build OK, 551 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
104 lines
6.0 KiB
TypeScript
104 lines
6.0 KiB
TypeScript
import { CSSProperties } from 'react';
|
|
import { ChatBgVariants } from './types';
|
|
|
|
// triangles — elegant low-poly / faceted-crystal mesh.
|
|
//
|
|
// The motif stays true to its name — a triangular tessellation — but is rebuilt
|
|
// to read as a *faceted crystalline surface* rather than the old flat isometric
|
|
// lines. Neighbouring triangular facets carry barely-there tonal shifts (one
|
|
// face catches a whisper of light, the adjacent one falls into a whisper of
|
|
// shade) so the plane looks gently faceted and dimensional, like brushed slate
|
|
// or cut glass seen at a shallow angle. A hairline "mesh glint" traces the facet
|
|
// edges so the crystalline structure is felt, never read. A soft tonal wash and
|
|
// a feathered vignette give the whole field quiet architectural depth.
|
|
//
|
|
// FACET SHADING
|
|
// An isometric triangle grid is three families of parallel lines at 0deg, 60deg
|
|
// and 120deg. Each `linear-gradient` below is a *hard-edged* two-band ramp along
|
|
// one of those axes: a faint tonal band followed by transparent, repeating
|
|
// across the tile. Overlapping the three axes partitions the plane into small
|
|
// triangular cells; because each axis contributes its shade to a different set
|
|
// of cells, up-pointing and down-pointing facets end up carrying subtly
|
|
// different summed tones — the alternating light/shadow facet look. A separate
|
|
// hairline layer per axis draws the thin edge glint at the facet borders.
|
|
//
|
|
// SEAMLESS TILING
|
|
// Equilateral geometry needs the tile height to be the width times sqrt(3). We
|
|
// use a 48x83px tile (48 * 1.732 = 83.1, rounded to 83) so the 60deg/120deg
|
|
// ramps close exactly on the tile box, and the horizontal edge family repeats on
|
|
// half-height (48x41.5 -> the 0deg hairline is sized to the full tile so its
|
|
// bands land on tile edges). Every facet-shade and edge layer shares this tile
|
|
// (or an exact multiple), and the 60/120 layers meet at the tile's mid columns,
|
|
// so triangles interlock across every seam with no drift. Wash and vignette are
|
|
// single non-repeating gradients at 100% 100%, so they never seam.
|
|
|
|
const dark: CSSProperties = {
|
|
// Deep navy base — the crystal sits on cool night stone.
|
|
backgroundColor: 'oklch(0.19 0.028 258)',
|
|
backgroundImage: [
|
|
// --- Facet shading: three cool-slate tonal ramps, one per triangle axis.
|
|
// Ascending-diagonal facets — a soft light band on one face family.
|
|
'linear-gradient(60deg,' +
|
|
' oklch(0.46 0.03 250 / 0.07) 0%, oklch(0.46 0.03 250 / 0.07) 50%,' +
|
|
' transparent 50%, transparent 100%)',
|
|
// Descending-diagonal facets — the shade family, closing the triangles.
|
|
'linear-gradient(120deg,' +
|
|
' oklch(0.34 0.03 255 / 0.06) 0%, oklch(0.34 0.03 255 / 0.06) 50%,' +
|
|
' transparent 50%, transparent 100%)',
|
|
// Horizontal facets — a third, fainter slate band so cells read three-sided.
|
|
'linear-gradient(0deg,' +
|
|
' oklch(0.42 0.028 248 / 0.045) 0%, oklch(0.42 0.028 248 / 0.045) 50%,' +
|
|
' transparent 50%, transparent 100%)',
|
|
// --- Mesh glint: hairline edges tracing the crystalline facet borders.
|
|
'linear-gradient(60deg, transparent 0, transparent calc(50% - 0.5px),' +
|
|
' oklch(0.62 0.035 250 / 0.10) calc(50% - 0.5px), oklch(0.62 0.035 250 / 0.10) 50%,' +
|
|
' transparent 50%)',
|
|
'linear-gradient(120deg, transparent 0, transparent calc(50% - 0.5px),' +
|
|
' oklch(0.62 0.035 250 / 0.10) calc(50% - 0.5px), oklch(0.62 0.035 250 / 0.10) 50%,' +
|
|
' transparent 50%)',
|
|
// --- Tonal wash — a gentle cool lift through the reading centre for depth.
|
|
'radial-gradient(ellipse 95% 80% at 50% 40%, oklch(0.28 0.03 255 / 0.45) 0%, transparent 62%)',
|
|
// --- Vignette — feather the corners into deeper navy.
|
|
'radial-gradient(ellipse 125% 130% at 50% 45%, transparent 58%, oklch(0.13 0.022 258 / 0.55) 100%)',
|
|
].join(','),
|
|
backgroundSize: '48px 83px, 48px 83px, 48px 83px, 48px 83px, 48px 83px, 100% 100%, 100% 100%',
|
|
// Offset the 120deg (shade) and its glint by half a tile so up/down facets
|
|
// interlock — this is what alternates the light/shadow triangles.
|
|
backgroundPosition: '0 0, 24px 0, 0 0, 0 0, 24px 0, 0 0, 0 0',
|
|
};
|
|
|
|
const light: CSSProperties = {
|
|
// Pale ice-white base — cut glass on frosted paper.
|
|
backgroundColor: 'oklch(0.975 0.004 250)',
|
|
backgroundImage: [
|
|
// --- Facet shading: soft cool-grey tonal ramps, one per triangle axis.
|
|
// Ascending-diagonal facets — a barely-there shade on one face family.
|
|
'linear-gradient(60deg,' +
|
|
' oklch(0.66 0.022 252 / 0.09) 0%, oklch(0.66 0.022 252 / 0.09) 50%,' +
|
|
' transparent 50%, transparent 100%)',
|
|
// Descending-diagonal facets — a hair darker, closing the triangles.
|
|
'linear-gradient(120deg,' +
|
|
' oklch(0.58 0.024 255 / 0.08) 0%, oklch(0.58 0.024 255 / 0.08) 50%,' +
|
|
' transparent 50%, transparent 100%)',
|
|
// Horizontal facets — the third, faintest cool-grey band.
|
|
'linear-gradient(0deg,' +
|
|
' oklch(0.62 0.02 250 / 0.055) 0%, oklch(0.62 0.02 250 / 0.055) 50%,' +
|
|
' transparent 50%, transparent 100%)',
|
|
// --- Mesh glint: crisp hairline facet edges in cool slate.
|
|
'linear-gradient(60deg, transparent 0, transparent calc(50% - 0.5px),' +
|
|
' oklch(0.50 0.03 255 / 0.11) calc(50% - 0.5px), oklch(0.50 0.03 255 / 0.11) 50%,' +
|
|
' transparent 50%)',
|
|
'linear-gradient(120deg, transparent 0, transparent calc(50% - 0.5px),' +
|
|
' oklch(0.50 0.03 255 / 0.11) calc(50% - 0.5px), oklch(0.50 0.03 255 / 0.11) 50%,' +
|
|
' transparent 50%)',
|
|
// --- Tonal wash — a clean white highlight through the reading centre.
|
|
'radial-gradient(ellipse 95% 80% at 50% 40%, oklch(0.995 0.003 250 / 0.60) 0%, transparent 62%)',
|
|
// --- Vignette — settle the corners into a faint cool grey.
|
|
'radial-gradient(ellipse 125% 130% at 50% 45%, transparent 58%, oklch(0.90 0.012 252 / 0.42) 100%)',
|
|
].join(','),
|
|
backgroundSize: '48px 83px, 48px 83px, 48px 83px, 48px 83px, 48px 83px, 100% 100%, 100% 100%',
|
|
backgroundPosition: '0 0, 24px 0, 0 0, 0 0, 24px 0, 0 0, 0 0',
|
|
};
|
|
|
|
export const triangles: ChatBgVariants = { dark, light };
|