diff --git a/background-final.html b/background-final.html index dbaac45..66635b1 100644 --- a/background-final.html +++ b/background-final.html @@ -1480,14 +1480,15 @@ if (useVanta && typeof VANTA !== 'undefined') { // Rebuild palette window.sunPalettes = [ { alt: -Math.PI / 2, sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, - { alt: -0.1, sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, + { alt: -0.262, sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, + { alt: -0.087, sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, { alt: 0.0, sky: hexToInt(ASH.rust), cloud: hexToInt(ASH.border), light: hexToInt(ASH.gold), bg: hexToInt(ASH.rust), cloudShadow: hexToInt(ASH.raised), sun: hexToInt(ASH.ember), sunGlare: hexToInt(ASH.gold), sunLight: hexToInt(ASH.ember), sunVis: 0.8 }, - { alt: 0.15, sky: hexToInt(ASH.blood), cloud: hexToInt(ASH.border), light: hexToInt(ASH.ember), bg: hexToInt(ASH.blood), cloudShadow: hexToInt(ASH.raised), sun: hexToInt(ASH.ember), sunGlare: hexToInt(ASH.ember), sunLight: hexToInt(ASH.ember), sunVis: 0.7 }, + { alt: 0.087, sky: hexToInt(ASH.blood), cloud: hexToInt(ASH.border), light: hexToInt(ASH.ember), bg: hexToInt(ASH.blood), cloudShadow: hexToInt(ASH.raised), sun: hexToInt(ASH.ember), sunGlare: hexToInt(ASH.ember), sunLight: hexToInt(ASH.ember), sunVis: 0.7 }, { alt: 0.4, sky: hexToInt(ASH.steel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.bone), bg: hexToInt(ASH.steel), cloudShadow: hexToInt(ASH.steel), sun: hexToInt(ASH.chalk), sunGlare: hexToInt(ASH.bone), sunLight: hexToInt(ASH.chalk), sunVis: 1 }, { alt: Math.PI / 2, sky: hexToInt(ASH.steelLight), cloud: hexToInt(ASH.border), light: hexToInt(ASH.chalk), bg: hexToInt(ASH.steelLight), cloudShadow: hexToInt(ASH.steelLight), sun: hexToInt(ASH.chalk), sunGlare: hexToInt(ASH.bone), sunLight: hexToInt(ASH.chalk), sunVis: 1 } ]; - window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; - window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; + window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.raised), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; + window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; window.weatherThemes = { sunny: { skyColor: hexToInt(ASH.steelLight), @@ -1524,18 +1525,23 @@ if (useVanta && typeof VANTA !== 'undefined') { // altitude in radians: -pi/2 (below) to pi/2 (zenith) // Sun position palette (altitude-based) - all colors from current theme // altitude in radians: -pi/2 (below) to pi/2 (zenith) - window.sunPalettes = [ + // Compressed twilight: dusk and dawn palette entries are now at +// -5deg / +5deg so the sunset transition completes within roughly +// an hour of clock time. -15deg is already full-night (void), so +// the sky is properly dark by ~1h after sunset. +window.sunPalettes = [ { alt: -Math.PI / 2, sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, - { alt: -0.1, sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, + { alt: -0.262, sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, + { alt: -0.087, sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone), sunVis: 0 }, { alt: 0.0, sky: hexToInt(ASH.rust), cloud: hexToInt(ASH.border), light: hexToInt(ASH.gold), bg: hexToInt(ASH.rust), cloudShadow: hexToInt(ASH.raised), sun: hexToInt(ASH.ember), sunGlare: hexToInt(ASH.gold), sunLight: hexToInt(ASH.ember), sunVis: 0.8 }, - { alt: 0.15, sky: hexToInt(ASH.blood), cloud: hexToInt(ASH.border), light: hexToInt(ASH.ember), bg: hexToInt(ASH.blood), cloudShadow: hexToInt(ASH.raised), sun: hexToInt(ASH.ember), sunGlare: hexToInt(ASH.ember), sunLight: hexToInt(ASH.ember), sunVis: 0.7 }, + { alt: 0.087, sky: hexToInt(ASH.blood), cloud: hexToInt(ASH.border), light: hexToInt(ASH.ember), bg: hexToInt(ASH.blood), cloudShadow: hexToInt(ASH.raised), sun: hexToInt(ASH.ember), sunGlare: hexToInt(ASH.ember), sunLight: hexToInt(ASH.ember), sunVis: 0.7 }, { alt: 0.4, sky: hexToInt(ASH.steel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.bone), bg: hexToInt(ASH.steel), cloudShadow: hexToInt(ASH.steel), sun: hexToInt(ASH.chalk), sunGlare: hexToInt(ASH.bone), sunLight: hexToInt(ASH.chalk), sunVis: 1 }, { alt: Math.PI / 2, sky: hexToInt(ASH.steelLight), cloud: hexToInt(ASH.border), light: hexToInt(ASH.chalk), bg: hexToInt(ASH.steelLight), cloudShadow: hexToInt(ASH.steelLight), sun: hexToInt(ASH.chalk), sunGlare: hexToInt(ASH.bone), sunLight: hexToInt(ASH.chalk), sunVis: 1 } ]; // Night palette based on moon phase (0 = new, 0.5 = full, 1 = new) - Ash colors - window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; - window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; + window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.raised), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; + window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; var MIN_NIGHT_BRIGHTNESS = 0.25; // minimum night brightness (even at new moon) @@ -1584,16 +1590,18 @@ if (useVanta && typeof VANTA !== 'undefined') { sunGlare: lerpColor(window.nightPaletteNew.sunGlare, window.nightPaletteFull.sunGlare, s), sunLight: lerpColor(window.nightPaletteNew.sunLight, window.nightPaletteFull.sunLight, s) }; - // Pull the whole night palette down by 'darkness' (a value - // 0..1 toward pure black) so new-moon skies are visibly darker - // than day, and full-moon skies still have some colour. + // 'light' is moonlight shining ON clouds / stars — keep it + // bright. Only sky / bg / bg-adjacent get the new-moon + // darkening, and only partially (otherwise new-moon nights + // are pitch black with no cloud structure). var darkness = 1.0 - (MIN_NIGHT_BRIGHTNESS + (1 - MIN_NIGHT_BRIGHTNESS) * s); + var shift = -Math.round(255 * darkness * 0.4); return { - sky: shiftColor(c.sky, -Math.round(255 * darkness * 0.6)), - cloud: shiftColor(c.cloud, -Math.round(255 * darkness * 0.6)), - light: shiftColor(c.light, -Math.round(255 * darkness * 0.6)), - bg: shiftColor(c.bg, -Math.round(255 * darkness * 0.6)), - cloudShadow: c.cloudShadow, + sky: shiftColor(c.sky, shift), + cloud: c.cloud, // keep contrast vs sky + light: c.light, // moonlight stays bright + bg: shiftColor(c.bg, shift), + cloudShadow: shiftColor(c.cloudShadow, Math.round(-shift * 0.5)), sun: c.sun, sunGlare: c.sunGlare, sunLight: c.sunLight diff --git a/background.html b/background.html index 1022ca7..12b7f58 100644 --- a/background.html +++ b/background.html @@ -634,8 +634,8 @@ if (useVanta && typeof VANTA !== 'undefined') { { alt: 0.4, sky: hexToInt(ASH.steel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.bone), bg: hexToInt(ASH.steel), cloudShadow: hexToInt(ASH.steel), sun: hexToInt(ASH.chalk), sunGlare: hexToInt(ASH.bone), sunLight: hexToInt(ASH.chalk), sunVis: 1 }, { alt: Math.PI / 2, sky: hexToInt(ASH.steelLight), cloud: hexToInt(ASH.border), light: hexToInt(ASH.chalk), bg: hexToInt(ASH.steelLight), cloudShadow: hexToInt(ASH.steelLight), sun: hexToInt(ASH.chalk), sunGlare: hexToInt(ASH.bone), sunLight: hexToInt(ASH.chalk), sunVis: 1 } ]; - window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; - window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; + window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.raised), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; + window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; window.weatherThemes = { sunny: { skyColor: hexToInt(ASH.steelLight), @@ -687,8 +687,8 @@ window.sunPalettes = [ ]; // Night palette based on moon phase (0 = new, 0.5 = full, 1 = new) - Ash colors - window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.void), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; - window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.panel), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; + window.nightPaletteNew = { sky: hexToInt(ASH.void), cloud: hexToInt(ASH.raised), light: hexToInt(ASH.stone), bg: hexToInt(ASH.void), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.stone), sunGlare: hexToInt(ASH.ash), sunLight: hexToInt(ASH.stone) }; + window.nightPaletteFull = { sky: hexToInt(ASH.panel), cloud: hexToInt(ASH.border), light: hexToInt(ASH.icon), bg: hexToInt(ASH.panel), cloudShadow: hexToInt(ASH.void), sun: hexToInt(ASH.icon), sunGlare: hexToInt(ASH.mid), sunLight: hexToInt(ASH.icon) }; var MIN_NIGHT_BRIGHTNESS = 0.25; // minimum night brightness (even at new moon) @@ -737,16 +737,18 @@ window.sunPalettes = [ sunGlare: lerpColor(window.nightPaletteNew.sunGlare, window.nightPaletteFull.sunGlare, s), sunLight: lerpColor(window.nightPaletteNew.sunLight, window.nightPaletteFull.sunLight, s) }; - // Pull the whole night palette down by 'darkness' (a value - // 0..1 toward pure black) so new-moon skies are visibly darker - // than day, and full-moon skies still have some colour. + // 'light' is moonlight shining ON clouds / stars — keep it + // bright. Only sky / bg / bg-adjacent get the new-moon + // darkening, and only partially (otherwise new-moon nights + // are pitch black with no cloud structure). var darkness = 1.0 - (MIN_NIGHT_BRIGHTNESS + (1 - MIN_NIGHT_BRIGHTNESS) * s); + var shift = -Math.round(255 * darkness * 0.4); return { - sky: shiftColor(c.sky, -Math.round(255 * darkness * 0.6)), - cloud: shiftColor(c.cloud, -Math.round(255 * darkness * 0.6)), - light: shiftColor(c.light, -Math.round(255 * darkness * 0.6)), - bg: shiftColor(c.bg, -Math.round(255 * darkness * 0.6)), - cloudShadow: c.cloudShadow, + sky: shiftColor(c.sky, shift), + cloud: c.cloud, // keep contrast vs sky + light: c.light, // moonlight stays bright + bg: shiftColor(c.bg, shift), + cloudShadow: shiftColor(c.cloudShadow, Math.round(-shift * 0.5)), sun: c.sun, sunGlare: c.sunGlare, sunLight: c.sunLight diff --git a/vendor/clouds3d.js b/vendor/clouds3d.js index 206acfc..51cd43e 100644 --- a/vendor/clouds3d.js +++ b/vendor/clouds3d.js @@ -141,12 +141,13 @@ var FRAG_SRC = [ 'float skyT = clamp(rd.y * 0.7 + 0.5, 0.0, 1.0);', 'vec3 col = mix(uBg, uSky, skyT);', // Stars: hash-grid sphere, above horizon, only at night. - // Night = sun altitude below 0. Visibility extends well into the -// lower half of the sky so the airplane-cockpit view shows stars -// from the horizon up. +// Night = sun altitude below 0. Visibility extends well into the + // lower half of the sky so the airplane-cockpit view shows stars + // from the horizon up. 'float nightFactor = smoothstep(0.05, -0.15, uSunAlt);', 'float skyMask = smoothstep(-0.10, 0.30, rd.y);', 'float stars = starField(rd) * skyMask * nightFactor;', + // (nightFactor is also used below for the final darken pass.)', 'col = mix(col, uLight, clamp(stars, 0.0, 1.0) * 0.9);', // Density threshold: weather 'sunny' -> high (sparse clouds), // 'stormy' -> low (overcast deck). @@ -169,7 +170,7 @@ var FRAG_SRC = [ 'float lit = clamp((p.y + 0.3) / 2.1, 0.0, 1.0);', 'vec3 cloudCol = mix(uCloudShadow, uCloud, lit);', // Sun tint on the lit side, fades at night - 'cloudCol = mix(cloudCol, uLight, uDayProgress * 0.35 * lit);', + 'cloudCol = mix(cloudCol, uLight, max(0.15, uDayProgress) * 0.35 * lit);', 'float alpha = clamp(d * stepSize * 0.9, 0.0, 1.0);', 'col = mix(col, cloudCol, alpha * trans);', 'trans *= (1.0 - alpha);', @@ -177,8 +178,10 @@ var FRAG_SRC = [ '}', 't += stepSize;', '}', - // Night darkening - 'col = mix(col, mix(uBg, col, 0.4), (1.0 - uDayProgress) * 0.55);', + // Night darkening — driven by sun altitude, not uDayProgress + // (uDayProgress is the 0..1 clock progress through 24h, which + // is not the same as 'is it night'). + 'col = mix(col, mix(uBg, col, 0.4), nightFactor * 0.45);', 'gl_FragColor = vec4(col, 1.0);', '}' ].join('\n');