feat(chat-bg): redesign 19 chat backgrounds as modular per-pattern files
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>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import { ChatBgVariants } from './types';
|
||||
|
||||
// chevron — refined woven-upholstery zigzag.
|
||||
//
|
||||
// The motif is a continuous, crisp chevron built to read as *textured fabric*
|
||||
// rather than flat stripes. The zigzag threads themselves are drawn with a
|
||||
// tiny inline-SVG tile (guaranteed geometrically seamless — the "V" path exits
|
||||
// each tile edge exactly where the next tile's path enters, both horizontally
|
||||
// and vertically). Over that, layered CSS gradients add the premium feel:
|
||||
// • a soft light→shade sweep across the weave gives each band an embossed,
|
||||
// woven cross-section (catches light on one diagonal face, shade on the
|
||||
// other);
|
||||
// • a faint two-tone wash alternates the tint of successive chevron rows for
|
||||
// an interlocked-yarn look;
|
||||
// • a gentle centre lift + corner vignette settle the field so text always
|
||||
// sits over the calmer middle.
|
||||
//
|
||||
// SEAMLESS TILING
|
||||
// The SVG is a WxH tile whose path is one full zigzag wave: it starts at the
|
||||
// left edge, dips to the vertex, rises to the right edge at the SAME y it
|
||||
// started — so horizontally each tile's end meets the next tile's start with no
|
||||
// step. Two stacked strokes (offset by H) fill the vertical repeat, and the
|
||||
// tile height equals the row pitch, so vertical stacking is seamless too. The
|
||||
// gradient overlays are non-repeating (100% 100%) or share the SVG's tile
|
||||
// width, so none of them introduce a seam.
|
||||
//
|
||||
// Everything sits at low alpha (~0.03–0.11) so the pattern is felt, not read:
|
||||
// crisp message text stays comfortably WCAG-AA in both themes.
|
||||
|
||||
// One zigzag wave, 40px wide × 20px tall. Path enters at (0,4), dips to the
|
||||
// vertex at (20,16), climbs back to (40,4) — identical entry/exit y => seamless
|
||||
// horizontal repeat. A second copy shifted +10 in y keeps a soft double thread.
|
||||
const svg = (stroke: string, faint: string) =>
|
||||
'url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20' +
|
||||
'width%3D%2240%22%20height%3D%2220%22%3E' +
|
||||
`%3Cpath%20d%3D%22M0%204%20L20%2016%20L40%204%22%20fill%3D%22none%22%20stroke%3D%22${stroke}%22%20stroke-width%3D%223%22%2F%3E` +
|
||||
`%3Cpath%20d%3D%22M0%2014%20L20%2026%20L40%2014%20M0%20-6%20L20%206%20L40%20-6%22%20fill%3D%22none%22%20stroke%3D%22${faint}%22%20stroke-width%3D%222%22%2F%3E` +
|
||||
'%3C%2Fsvg%3E")';
|
||||
|
||||
const dark: CSSProperties = {
|
||||
backgroundColor: 'oklch(0.20 0.022 260)',
|
||||
backgroundImage: [
|
||||
// 1. The zigzag threads — muted indigo/slate, main + fainter under-thread.
|
||||
svg('oklch(0.55 0.05 265 %2F 0.16)', 'oklch(0.50 0.045 262 %2F 0.07)'),
|
||||
// 2. Woven emboss — a soft diagonal light→shade sweep across the weave so
|
||||
// the bands catch light on one face and fall to shade on the other.
|
||||
'linear-gradient(135deg, oklch(0.62 0.05 265 / 0.05) 0%, transparent 45%, transparent 55%, oklch(0.14 0.02 260 / 0.06) 100%)',
|
||||
// 3. Two-tone weft — a whisper shade on alternate chevron rows.
|
||||
'repeating-linear-gradient(0deg, oklch(0.50 0.04 258 / 0.035) 0px, oklch(0.50 0.04 258 / 0.035) 20px, transparent 20px, transparent 40px)',
|
||||
// 4. Tonal wash — cool centre lift for gentle depth.
|
||||
'radial-gradient(ellipse 90% 75% at 50% 42%, oklch(0.26 0.03 262 / 0.40) 0%, transparent 60%)',
|
||||
// 5. Vignette — feather corners into deeper charcoal-blue.
|
||||
'radial-gradient(ellipse 120% 130% at 50% 45%, transparent 60%, oklch(0.15 0.02 260 / 0.55) 100%)',
|
||||
].join(','),
|
||||
backgroundSize: '40px 20px, 100% 100%, 40px 40px, 100% 100%, 100% 100%',
|
||||
};
|
||||
|
||||
const light: CSSProperties = {
|
||||
backgroundColor: 'oklch(0.965 0.006 85)',
|
||||
backgroundImage: [
|
||||
// 1. The zigzag threads — soft dusty-blue, main + fainter under-thread.
|
||||
svg('oklch(0.55 0.05 255 %2F 0.14)', 'oklch(0.52 0.045 255 %2F 0.06)'),
|
||||
// 2. Woven emboss — diagonal light→shade sweep for a knit-fabric surface.
|
||||
'linear-gradient(135deg, oklch(0.99 0.008 85 / 0.06) 0%, transparent 45%, transparent 55%, oklch(0.55 0.05 255 / 0.05) 100%)',
|
||||
// 3. Two-tone weft — faint alternating-row shade.
|
||||
'repeating-linear-gradient(0deg, oklch(0.52 0.04 255 / 0.03) 0px, oklch(0.52 0.04 255 / 0.03) 20px, transparent 20px, transparent 40px)',
|
||||
// 4. Tonal wash — warm paper highlight through the reading centre.
|
||||
'radial-gradient(ellipse 90% 75% at 50% 42%, oklch(0.99 0.008 85 / 0.55) 0%, transparent 60%)',
|
||||
// 5. Vignette — settle corners into a slightly deeper dusty tone.
|
||||
'radial-gradient(ellipse 120% 130% at 50% 45%, transparent 60%, oklch(0.91 0.012 250 / 0.40) 100%)',
|
||||
].join(','),
|
||||
backgroundSize: '40px 20px, 100% 100%, 40px 40px, 100% 100%, 100% 100%',
|
||||
};
|
||||
|
||||
export const chevron: ChatBgVariants = { dark, light };
|
||||
Reference in New Issue
Block a user