discovery: tune the wave dial — green->blue spectrum, calmer waves, subtler orb, refined header

Feedback pass: red read as "bad", so the spectrum is now green -> blue through cyan (deep/exploratory,
not alarming). The orb glow was way too hot — cut it right down and softened the pulse ring + the colour
aura. Dialed the wiggle back (lower amplitude, fewer cycles, slower) so the adventurous end is lively,
not chaotic. Header is now a small uppercase "ADVENTUROUSNESS" overline above the big colour-shifting
state word, instead of the plain bold title.
This commit is contained in:
BoulderBadgeDad 2026-06-29 16:54:53 -07:00
parent d9bd5c1d7f
commit fcd768ffee
3 changed files with 20 additions and 19 deletions

View file

@ -3152,7 +3152,7 @@
<div class="adv-wave" id="adv-wave"
title="Pushes globally-popular artists down so more obscure picks surface in your recommendations">
<div class="adv-wave-head">
<span class="adv-wave-title">Adventurousness</span>
<span class="adv-wave-label">Adventurousness</span>
<span class="adv-wave-state" id="adv-wave-state">Balanced</span>
</div>
<div class="adv-wave-track" id="adv-wave-track">

View file

@ -35,19 +35,20 @@ function _advState(v) {
if (v < 0.70) return 'Adventurous';
return 'Deep cuts only';
}
// green (120°) → red (0°) through the warm spectrum (yellow, orange) as the orb moves right.
// green (120°) → blue (220°) through cyan as the orb moves right. Blue reads "deep / exploratory"
// rather than red's "danger / bad" — safe at the green end, adventurous at the cool blue end.
function _advColor(v, light, alpha) {
const hue = 120 * (1 - Math.max(0, Math.min(1, v)));
const hue = 120 + 100 * Math.max(0, Math.min(1, v));
const l = light || 55;
return alpha != null ? `hsla(${hue.toFixed(0)}, 85%, ${l}%, ${alpha})` : `hsl(${hue.toFixed(0)}, 85%, ${l}%)`;
}
// Wave height (viewBox units, centre 40) at position u (0..1) for adventurousness v.
function _advWaveY(u, v) {
const amp = 2 + v * 22; // gentle ripple at 0, tall waves at 1
const freq = 1.1 + v * 3.2; // more cycles as it gets adventurous
const amp = 2 + v * 12; // gentle ripple at 0, lively (not wild) at 1
const freq = 1.1 + v * 2.0; // a few more cycles as it gets adventurous
let y = 40 + amp * Math.sin(freq * u * Math.PI * 2 + _advWave.phase);
if (v > 0) { // a detuned second harmonic adds the erratic wobble
y += v * amp * 0.55 * Math.sin(freq * 2.4 * u * Math.PI * 2 + _advWave.phase * 1.7 + 1.3);
if (v > 0) { // a detuned second harmonic adds a touch of wobble
y += v * amp * 0.38 * Math.sin(freq * 2.2 * u * Math.PI * 2 + _advWave.phase * 1.6 + 1.3);
}
return y;
}
@ -57,7 +58,7 @@ function _advDraw() {
if (!path || !track) { _advWave.raf = null; return; }
if (track.offsetParent !== null) { // skip the work while the Discover page is hidden
const v = _advWave.value;
_advWave.phase += 0.03 + v * 0.07; // waves faster the more adventurous
_advWave.phase += 0.022 + v * 0.045; // waves a little faster the more adventurous
let line = '';
const N = 90;
for (let i = 0; i <= N; i++) {
@ -88,12 +89,12 @@ function _advApply(v) {
orb.style.left = (v * 100).toFixed(2) + '%';
orb.style.color = c; // currentColor for the pulsing ring
orb.style.background = cBright;
orb.style.boxShadow = `0 0 22px 3px ${c}, 0 0 0 6px rgba(255,255,255,0.08), inset 0 0 0 2px rgba(255,255,255,0.6)`;
orb.style.boxShadow = `0 0 9px 0 ${c}, inset 0 0 0 2px rgba(255,255,255,0.5)`;
}
const aura = document.getElementById('adv-wave-aura'); // colour wash that follows the orb
if (aura) {
aura.style.left = (v * 100).toFixed(2) + '%';
aura.style.background = `radial-gradient(circle, ${_advColor(v, 50, 0.42)} 0%, transparent 68%)`;
aura.style.background = `radial-gradient(circle, ${_advColor(v, 50, 0.26)} 0%, transparent 70%)`;
}
const stateEl = document.getElementById('adv-wave-state');
if (stateEl) { stateEl.textContent = _advState(v); stateEl.style.color = cBright; }

View file

@ -35177,9 +35177,9 @@ div.artist-hero-badge {
box-shadow: 0 10px 34px rgba(0,0,0,0.30);
overflow: hidden; /* contain the colour aura wash */
}
.adv-wave-head { display: flex; align-items: baseline; gap: 12px; position: relative; z-index: 2; }
.adv-wave-title { font-size: 15px; font-weight: 800; color: #fff; letter-spacing: 0.2px; }
.adv-wave-state { font-size: 12px; font-weight: 700; transition: color 0.25s; }
.adv-wave-head { display: flex; flex-direction: column; gap: 1px; position: relative; z-index: 2; }
.adv-wave-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 2.5px; color: rgba(255,255,255,0.38); }
.adv-wave-state { font-size: 21px; font-weight: 800; letter-spacing: -0.3px; line-height: 1.15; transition: color 0.25s; }
.adv-wave-track {
position: relative; height: 104px; margin: 6px 0 2px;
cursor: grab; touch-action: none;
@ -35197,18 +35197,18 @@ div.artist-hero-badge {
width: 22px; height: 22px; border-radius: 50%;
transform: translate(-50%, -50%);
background: #1DB954; color: #1DB954;
box-shadow: 0 0 20px 3px #1DB954, 0 0 0 6px rgba(255,255,255,0.08), inset 0 0 0 2px rgba(255,255,255,0.6);
box-shadow: 0 0 9px 0 #1DB954, inset 0 0 0 2px rgba(255,255,255,0.5);
pointer-events: none; /* the track captures the pointer; the orb is purely visual */
will-change: left, top;
}
.adv-wave-orb::after {
content: ''; position: absolute; inset: -7px; border-radius: 50%;
border: 2px solid currentColor; opacity: 0.5;
animation: adv-orb-pulse 2.4s ease-out infinite;
content: ''; position: absolute; inset: -5px; border-radius: 50%;
border: 1.5px solid currentColor; opacity: 0.4;
animation: adv-orb-pulse 2.8s ease-out infinite;
}
@keyframes adv-orb-pulse {
0% { transform: scale(0.7); opacity: 0.55; }
100% { transform: scale(1.95); opacity: 0; }
0% { transform: scale(0.75); opacity: 0.4; }
100% { transform: scale(1.5); opacity: 0; }
}
.adv-wave-ends {
display: flex; justify-content: space-between;