Noise-driven YES, sticky hero with frosted cards, full light theme
Deploy / deploy (push) Successful in 1m0s
Deploy / deploy (push) Successful in 1m0s
Three changes that belong together, all verified against a real mounted page in headless WebKit: - yes.js's two behavior dials (containment/wiggle) now drift on a smooth two-octave value-noise field at cloud pace (~25s per weather change) instead of following the mouse. Includes a real bug fix found in verification: the hash's final XOR yields a SIGNED 32-bit value in JS, so the "0..1" noise dipped to -0.36 without a reinterpreting >>> 0. - The landing hero is position: sticky, so the piece keeps animating behind the whole page. Cards go translucent with backdrop blur and a soft shadow so the piece reads faintly through and around them (near-opaque fallback where backdrop-filter is unsupported). The hero copy fades out over the first half-screen of scroll - pinned, it ghosted through the cards. The bottom fade gradient is gone: its hard-cut reason disappeared with the canvas behind everything. - Full prefers-color-scheme light theme: warm paper, near-black ink, accent deepened from dusty cyan to teal ink (#8ec2c0 washes out on white), wordmark inverted via filter. yes.js mirrors the palette itself (canvas can't read CSS vars): CMYK process-ink strokes dark enough to carry on paper, raster ghost repainted as multiply-blended gray on white, live re-theme on scheme flip with a trail clear. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ee91b092d1
commit
1b7ffe0f43
+88
-22
@@ -47,11 +47,22 @@
|
||||
--accent-soft: rgba(142, 194, 192, 0.16);
|
||||
|
||||
--paper: #0a0a0a;
|
||||
--paper-raised: #161616;
|
||||
--ink: #ededed;
|
||||
--ink-dim: #9a9a9a;
|
||||
--line: #2a2a2a;
|
||||
|
||||
/* Cards float over the sticky YES canvas - translucent so the piece
|
||||
reads faintly through them (paired with backdrop-filter on
|
||||
.alt-card), shadowed so their edge against the animated backdrop
|
||||
is a soft lift rather than a hard contrast line. */
|
||||
--card-bg: rgba(22, 22, 22, 0.55);
|
||||
--card-bg-opaque: rgba(22, 22, 22, 0.94);
|
||||
--card-shadow: rgba(0, 0, 0, 0.5);
|
||||
|
||||
--error: #ff6b6b;
|
||||
/* Behind .hero-copy: dark halo on dark stock, paper halo on light. */
|
||||
--hero-glow: rgba(0, 0, 0, 0.8);
|
||||
|
||||
--heading: "Quicksand", var(--sans);
|
||||
--sans: -apple-system, "SF Pro Text", ui-sans-serif, "Segoe UI", system-ui, sans-serif;
|
||||
|
||||
@@ -64,6 +75,44 @@
|
||||
font-size: max(12px, calc(2.1lvmin + 3pt));
|
||||
}
|
||||
|
||||
/* Light theme: the same muted-press idea on white stock - warm paper,
|
||||
near-black ink, and the accent deepened from dusty cyan to a teal
|
||||
ink that actually carries as text on light paper (the dark theme's
|
||||
#8ec2c0 washes out there). yes.js mirrors this palette on its own
|
||||
(matchMedia in setupTheme) since canvas paint can't read CSS vars. */
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
--accent: #47807e;
|
||||
--accent-soft: rgba(71, 128, 126, 0.16);
|
||||
|
||||
--paper: #f6f5f1;
|
||||
--ink: #1d1d1b;
|
||||
--ink-dim: #6d6c66;
|
||||
--line: #d9d7cf;
|
||||
|
||||
--card-bg: rgba(252, 251, 248, 0.55);
|
||||
--card-bg-opaque: rgba(252, 251, 248, 0.94);
|
||||
--card-shadow: rgba(50, 48, 42, 0.18);
|
||||
|
||||
--error: #a83a32;
|
||||
--hero-glow: rgba(246, 245, 241, 0.85);
|
||||
}
|
||||
|
||||
/* The wordmark SVG is a hardcoded white stroke (also used raw in
|
||||
dark contexts elsewhere) - flip it to ink here rather than fork
|
||||
the asset. */
|
||||
.wordmark img {
|
||||
filter: invert(0.92);
|
||||
}
|
||||
|
||||
/* overlay against near-white paper resolves to ~white and the
|
||||
raster ghost vanishes; multiply lets the light theme's gray YES
|
||||
(see rasterizeText's themed repaint in yes.js) show as ink. */
|
||||
.hero-canvas #rasterCanvas {
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -157,7 +206,14 @@ main.not-found {
|
||||
than interrupting the canvas. */
|
||||
|
||||
.hero-yes {
|
||||
position: relative;
|
||||
/* Sticky at the viewport top for the whole scroll (its containing
|
||||
block is the page itself), so the piece stays animating behind
|
||||
everything that follows - the translucent cards scroll over it
|
||||
and it shows through them and in the gaps around them. z-index 0
|
||||
so positioned content below can stack above with z-index 1. */
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 0;
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
/* svh here is only the pre-JS/no-JS fallback (and first paint before
|
||||
@@ -203,28 +259,17 @@ main.not-found {
|
||||
z-index: 1;
|
||||
padding: 0 1.5rem 3.5rem;
|
||||
gap: 0.6rem;
|
||||
text-shadow: 0 0.12em 1.4em rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
/* Softens the otherwise hard cut where the full-bleed canvas meets the
|
||||
page background right below it - fades to the same --paper color
|
||||
over the last few ems instead of stopping dead. Non-interactive so
|
||||
it never steals clicks meant for the canvas underneath. */
|
||||
.hero-yes::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 8rem;
|
||||
background: linear-gradient(to bottom, transparent, var(--paper));
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
text-shadow: 0 0.12em 1.4em var(--hero-glow);
|
||||
}
|
||||
|
||||
/* alternatives */
|
||||
|
||||
/* position + z-index on these three: everything that scrolls over the
|
||||
sticky canvas must be a positioned box above the hero's z-index 0,
|
||||
or the (positioned) hero would paint over it. */
|
||||
.alternatives {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 75ch;
|
||||
margin: 0 auto 5rem;
|
||||
padding: 0 1.5rem;
|
||||
@@ -232,6 +277,12 @@ main.not-found {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.question-nav,
|
||||
.question-responsible {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 43.75rem) {
|
||||
.alternatives {
|
||||
padding: 0;
|
||||
@@ -295,10 +346,25 @@ main.not-found {
|
||||
}
|
||||
|
||||
.alt-card {
|
||||
background: var(--paper-raised);
|
||||
background: var(--card-bg);
|
||||
/* Frosted glass over the animated canvas behind: the blur is what
|
||||
keeps text on a translucent card readable while the piece still
|
||||
reads through it in color and motion. */
|
||||
-webkit-backdrop-filter: blur(0.8rem);
|
||||
backdrop-filter: blur(0.8rem);
|
||||
border: 0.06rem solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.75rem 1.9rem;
|
||||
box-shadow: 0 1.1rem 2.4rem var(--card-shadow);
|
||||
}
|
||||
|
||||
/* Without backdrop blur, 0.55-alpha cards put text straight over the
|
||||
moving canvas - illegible. Engines lacking the filter get a
|
||||
near-opaque card instead. */
|
||||
@supports not ((backdrop-filter: blur(1rem)) or (-webkit-backdrop-filter: blur(1rem))) {
|
||||
.alt-card {
|
||||
background: var(--card-bg-opaque);
|
||||
}
|
||||
}
|
||||
|
||||
.alt-image {
|
||||
@@ -570,7 +636,7 @@ textarea:focus {
|
||||
font-family: var(--sans);
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
color: #0a0a0a;
|
||||
color: var(--paper);
|
||||
background: var(--accent);
|
||||
border: none;
|
||||
border-radius: 0.7rem;
|
||||
@@ -609,7 +675,7 @@ textarea:focus {
|
||||
}
|
||||
|
||||
.resource-error {
|
||||
color: #ff6b6b;
|
||||
color: var(--error);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user