Make clouds2d.js theme-agnostic
- Remove all hardcoded fallback hex/rgb values - Skip draw until __currentPalette is published by parent - applyWeatherTheme now also mixes cloudShadow (was dropped)
This commit is contained in:
1 parent
c6764fd534
commit
3812f80f40
3 files changed
+170
-46
No files matched your search
+85
-23
@@ -1094,7 +1094,8 @@ else window.SunCalc = SunCalc;
|
|||||||
* fragment shader to produce animated cloud-like patterns.
|
* fragment shader to produce animated cloud-like patterns.
|
||||||
*
|
*
|
||||||
* Drop-in replacement for Vanta when CONFIG.renderer === 'clouds2d'.
|
* Drop-in replacement for Vanta when CONFIG.renderer === 'clouds2d'.
|
||||||
* Creates its own <canvas> overlay and attaches to the target element.
|
* Reads day/night palette + weather theme from window globals set
|
||||||
|
* by the parent (background.html's animate() loop).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@@ -1132,14 +1133,21 @@ var VERT_SRC = [
|
|||||||
'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }'
|
'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
// Fragment shader: animates an fBm cloud field, modulates density
|
||||||
|
// by weather, blends day/night palette colours, and adds a soft
|
||||||
|
// horizon gradient so the sky transitions naturally.
|
||||||
var FRAG_SRC = [
|
var FRAG_SRC = [
|
||||||
'precision highp float;',
|
'precision highp float;',
|
||||||
'uniform vec2 uResolution;',
|
'uniform vec2 uResolution;',
|
||||||
'uniform float uTime;',
|
'uniform float uTime;',
|
||||||
'uniform vec3 uSky;',
|
'uniform vec3 uSky;',
|
||||||
'uniform vec3 uCloud;',
|
'uniform vec3 uCloud;',
|
||||||
|
'uniform vec3 uCloudShadow;',
|
||||||
'uniform vec3 uLight;',
|
'uniform vec3 uLight;',
|
||||||
|
'uniform vec3 uBg;',
|
||||||
'uniform float uSpeed;',
|
'uniform float uSpeed;',
|
||||||
|
'uniform float uDensity;', // 0..1 how thick the clouds are
|
||||||
|
'uniform float uDayProgress;', // 0..1 (day vs night)
|
||||||
'float hash(vec2 p) {',
|
'float hash(vec2 p) {',
|
||||||
'p = fract(p * vec2(123.34, 456.21));',
|
'p = fract(p * vec2(123.34, 456.21));',
|
||||||
'p += dot(p, p + 45.32);',
|
'p += dot(p, p + 45.32);',
|
||||||
@@ -1170,10 +1178,21 @@ var FRAG_SRC = [
|
|||||||
'vec2 p1 = uv * vec2(3.0, 1.7) + vec2(uTime * 0.012, uTime * 0.004);',
|
'vec2 p1 = uv * vec2(3.0, 1.7) + vec2(uTime * 0.012, uTime * 0.004);',
|
||||||
'vec2 p2 = uv * vec2(5.0, 2.6) + vec2(uTime * 0.020, -uTime * 0.006);',
|
'vec2 p2 = uv * vec2(5.0, 2.6) + vec2(uTime * 0.020, -uTime * 0.006);',
|
||||||
'float n = fbm(p1 * uSpeed) * 0.6 + fbm(p2 * uSpeed) * 0.4;',
|
'float n = fbm(p1 * uSpeed) * 0.6 + fbm(p2 * uSpeed) * 0.4;',
|
||||||
'float cloud = smoothstep(0.35, 0.75, n);',
|
// Density threshold widens with uDensity (1 = always cloudy, 0 = clear sky)
|
||||||
'float horizon = smoothstep(0.0, 0.45, uv.y);',
|
'float thresh = mix(0.85, 0.30, uDensity);',
|
||||||
'vec3 col = mix(uSky, uCloud, cloud * (1.0 - horizon * 0.3));',
|
'float cloud = smoothstep(thresh - 0.10, thresh + 0.10, n);',
|
||||||
'col = mix(col, uLight, cloud * horizon * 0.5);',
|
// Soft horizon: top of frame is more sky, bottom more clouds
|
||||||
|
'float horizon = smoothstep(0.0, 0.5, uv.y);',
|
||||||
|
// Sky gradient (top vs bottom)
|
||||||
|
'vec3 sky = mix(uBg, uSky, horizon);',
|
||||||
|
// Cloud body (lit top + shadow bottom)
|
||||||
|
'vec3 cloudCol = mix(uCloudShadow, uCloud, horizon);',
|
||||||
|
// Add light tint to the lit side
|
||||||
|
'cloudCol = mix(cloudCol, uLight, cloud * horizon * 0.4 * uDayProgress);',
|
||||||
|
// Final composite: sky where there's no cloud, cloud where there is
|
||||||
|
'vec3 col = mix(sky, cloudCol, cloud);',
|
||||||
|
// At night, blend everything toward bg color (darken)
|
||||||
|
'col = mix(col, mix(uBg, cloudCol, 0.3), (1.0 - uDayProgress) * 0.5);',
|
||||||
'gl_FragColor = vec4(col, 1.0);',
|
'gl_FragColor = vec4(col, 1.0);',
|
||||||
'}'
|
'}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
@@ -1198,34 +1217,51 @@ function init(canvas) {
|
|||||||
var uTime = gl.getUniformLocation(prog, 'uTime');
|
var uTime = gl.getUniformLocation(prog, 'uTime');
|
||||||
var uSky = gl.getUniformLocation(prog, 'uSky');
|
var uSky = gl.getUniformLocation(prog, 'uSky');
|
||||||
var uCloud = gl.getUniformLocation(prog, 'uCloud');
|
var uCloud = gl.getUniformLocation(prog, 'uCloud');
|
||||||
|
var uCloudShadow = gl.getUniformLocation(prog, 'uCloudShadow');
|
||||||
var uLight = gl.getUniformLocation(prog, 'uLight');
|
var uLight = gl.getUniformLocation(prog, 'uLight');
|
||||||
|
var uBg = gl.getUniformLocation(prog, 'uBg');
|
||||||
var uSpeed = gl.getUniformLocation(prog, 'uSpeed');
|
var uSpeed = gl.getUniformLocation(prog, 'uSpeed');
|
||||||
|
var uDensity = gl.getUniformLocation(prog, 'uDensity');
|
||||||
|
var uDayProgress = gl.getUniformLocation(prog, 'uDayProgress');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
gl: gl, prog: prog, buf: buf, aPos: aPos,
|
gl: gl, prog: prog, buf: buf, aPos: aPos,
|
||||||
uRes: uRes, uTime: uTime, uSky: uSky, uCloud: uCloud,
|
uRes: uRes, uTime: uTime, uSky: uSky, uCloud: uCloud,
|
||||||
uLight: uLight, uSpeed: uSpeed
|
uCloudShadow: uCloudShadow, uLight: uLight, uBg: uBg,
|
||||||
|
uSpeed: uSpeed, uDensity: uDensity, uDayProgress: uDayProgress
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function hex(r, g, b) { return [r/255, g/255, b/255]; }
|
// Convert 24-bit int (0xRRGGBB) to [r,g,b] 0..1 floats.
|
||||||
|
// Theme-agnostic: caller decides what colour value to pass in.
|
||||||
|
function hex(rgb) {
|
||||||
|
return [((rgb >> 16) & 255) / 255,
|
||||||
|
((rgb >> 8) & 255) / 255,
|
||||||
|
(rgb & 255) / 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cloud density per weather (0 = clear, 1 = overcast).
|
||||||
|
// Names mirror the weather themes defined in background.html.
|
||||||
|
var WEATHER_DENSITY = {
|
||||||
|
sunny: 0.20,
|
||||||
|
cloudy: 0.70,
|
||||||
|
stormy: 1.00,
|
||||||
|
night: 0.45
|
||||||
|
};
|
||||||
|
|
||||||
window.clouds2dRender = function(target) {
|
window.clouds2dRender = function(target) {
|
||||||
if (!target || typeof target !== 'object') {
|
if (!target || typeof target !== 'object') {
|
||||||
console.error('clouds2d: invalid target');
|
console.error('clouds2d: invalid target');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get or create the WebGL canvas
|
|
||||||
var canvas = target.__clouds2dCanvas;
|
var canvas = target.__clouds2dCanvas;
|
||||||
if (!canvas) {
|
if (!canvas) {
|
||||||
// Replace the target's content with a WebGL canvas
|
|
||||||
canvas = document.createElement('canvas');
|
canvas = document.createElement('canvas');
|
||||||
canvas.style.position = 'absolute';
|
canvas.style.position = 'absolute';
|
||||||
canvas.style.top = '0';
|
canvas.style.top = '0';
|
||||||
canvas.style.left = '0';
|
canvas.style.left = '0';
|
||||||
canvas.style.width = '100%';
|
canvas.style.width = '100%';
|
||||||
canvas.style.height = '100%';
|
canvas.style.height = '100%';
|
||||||
// Empty the target and insert the canvas as the only child
|
|
||||||
while (target.firstChild) target.removeChild(target.firstChild);
|
while (target.firstChild) target.removeChild(target.firstChild);
|
||||||
target.appendChild(canvas);
|
target.appendChild(canvas);
|
||||||
target.style.position = 'relative';
|
target.style.position = 'relative';
|
||||||
@@ -1254,20 +1290,38 @@ window.clouds2dRender = function(target) {
|
|||||||
gl.uniform2f(s.uRes, canvas.width, canvas.height);
|
gl.uniform2f(s.uRes, canvas.width, canvas.height);
|
||||||
gl.uniform1f(s.uTime, performance.now() / 1000);
|
gl.uniform1f(s.uTime, performance.now() / 1000);
|
||||||
|
|
||||||
var sky = [0.39, 0.54, 0.78];
|
// Pull palette + weather from globals (set by animate() in background.html).
|
||||||
var cloud = [0.43, 0.43, 0.43];
|
// No hardcoded fallbacks: until the parent has published a palette we
|
||||||
var light = [0.89, 0.87, 0.82];
|
// skip the draw and leave the WebGL context cleared. This keeps the
|
||||||
var cfg = window.CONFIG || {};
|
// renderer 100% theme-agnostic — the parent fully owns colour decisions.
|
||||||
var theme = (cfg.currentWeatherTheme || (cfg.weatherThemes && cfg.weatherThemes[cfg.theme])) || null;
|
var pal = window.__currentPalette;
|
||||||
if (theme) {
|
if (!pal) {
|
||||||
sky = hex((theme.skyColor >> 16) & 255, (theme.skyColor >> 8) & 255, theme.skyColor & 255);
|
gl.clearColor(0, 0, 0, 1);
|
||||||
cloud = hex((theme.cloudColor >> 16) & 255, (theme.cloudColor >> 8) & 255, theme.cloudColor & 255);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
light = hex((theme.lightColor >> 16) & 255, (theme.lightColor >> 8) & 255, theme.lightColor & 255);
|
return;
|
||||||
}
|
}
|
||||||
gl.uniform3fv(s.uSky, sky);
|
|
||||||
gl.uniform3fv(s.uCloud, cloud);
|
var weather = window.__currentWeatherName;
|
||||||
gl.uniform3fv(s.uLight, light);
|
var dayProgress = window.__currentDayProgress;
|
||||||
gl.uniform1f(s.uSpeed, 1.0);
|
var themeSpeed = window.__currentThemeSpeed;
|
||||||
|
|
||||||
|
gl.uniform3fv(s.uSky, hex(pal.sky));
|
||||||
|
gl.uniform3fv(s.uCloud, hex(pal.cloud));
|
||||||
|
gl.uniform3fv(s.uCloudShadow, hex(pal.cloudShadow !== undefined ? pal.cloudShadow : pal.sky));
|
||||||
|
gl.uniform3fv(s.uLight, hex(pal.light));
|
||||||
|
gl.uniform3fv(s.uBg, hex(pal.bg));
|
||||||
|
|
||||||
|
var density = (weather && WEATHER_DENSITY[weather] !== undefined)
|
||||||
|
? WEATHER_DENSITY[weather] : 0.5;
|
||||||
|
gl.uniform1f(s.uDensity, density);
|
||||||
|
|
||||||
|
var day = (typeof dayProgress === 'number')
|
||||||
|
? Math.max(0, Math.min(1, dayProgress)) : 0.5;
|
||||||
|
gl.uniform1f(s.uDayProgress, day);
|
||||||
|
|
||||||
|
var speed = (typeof themeSpeed === 'number')
|
||||||
|
? Math.max(0.1, Math.min(3, themeSpeed)) : 1.0;
|
||||||
|
gl.uniform1f(s.uSpeed, speed);
|
||||||
|
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
||||||
};
|
};
|
||||||
@@ -2215,6 +2269,9 @@ window.weatherThemes = {
|
|||||||
return {
|
return {
|
||||||
sky: mixColor(c.sky, themeColors.skyColor, mix),
|
sky: mixColor(c.sky, themeColors.skyColor, mix),
|
||||||
cloud: mixColor(c.cloud, themeColors.cloudColor, mix),
|
cloud: mixColor(c.cloud, themeColors.cloudColor, mix),
|
||||||
|
cloudShadow: c.cloudShadow !== undefined
|
||||||
|
? mixColor(c.cloudShadow, themeColors.cloudColor, mix * 0.8)
|
||||||
|
: mixColor(c.cloud, themeColors.cloudColor, mix * 0.8),
|
||||||
light: mixColor(c.sun, themeColors.lightColor, mix * 0.5),
|
light: mixColor(c.sun, themeColors.lightColor, mix * 0.5),
|
||||||
bg: mixColor(c.bg, themeColors.backgroundColor, mix)
|
bg: mixColor(c.bg, themeColors.backgroundColor, mix)
|
||||||
};
|
};
|
||||||
@@ -2444,6 +2501,11 @@ window.weatherThemes = {
|
|||||||
var t = (Date.now() - startTime) / CYCLE % 1;
|
var t = (Date.now() - startTime) / CYCLE % 1;
|
||||||
var c = getColor(t);
|
var c = getColor(t);
|
||||||
c = applyWeatherTheme(c);
|
c = applyWeatherTheme(c);
|
||||||
|
// Expose current palette + weather info for the 2D renderer
|
||||||
|
window.__currentPalette = c;
|
||||||
|
window.__currentWeatherName = currentWeatherThemeName;
|
||||||
|
window.__currentDayProgress = realDayProgress;
|
||||||
|
window.__currentThemeSpeed = currentThemeSpeed;
|
||||||
effect.setOptions({
|
effect.setOptions({
|
||||||
skyColor: c.sky,
|
skyColor: c.sky,
|
||||||
cloudColor: c.cloud,
|
cloudColor: c.cloud,
|
||||||
|
|||||||
@@ -1416,6 +1416,9 @@ window.weatherThemes = {
|
|||||||
return {
|
return {
|
||||||
sky: mixColor(c.sky, themeColors.skyColor, mix),
|
sky: mixColor(c.sky, themeColors.skyColor, mix),
|
||||||
cloud: mixColor(c.cloud, themeColors.cloudColor, mix),
|
cloud: mixColor(c.cloud, themeColors.cloudColor, mix),
|
||||||
|
cloudShadow: c.cloudShadow !== undefined
|
||||||
|
? mixColor(c.cloudShadow, themeColors.cloudColor, mix * 0.8)
|
||||||
|
: mixColor(c.cloud, themeColors.cloudColor, mix * 0.8),
|
||||||
light: mixColor(c.sun, themeColors.lightColor, mix * 0.5),
|
light: mixColor(c.sun, themeColors.lightColor, mix * 0.5),
|
||||||
bg: mixColor(c.bg, themeColors.backgroundColor, mix)
|
bg: mixColor(c.bg, themeColors.backgroundColor, mix)
|
||||||
};
|
};
|
||||||
@@ -1645,6 +1648,11 @@ window.weatherThemes = {
|
|||||||
var t = (Date.now() - startTime) / CYCLE % 1;
|
var t = (Date.now() - startTime) / CYCLE % 1;
|
||||||
var c = getColor(t);
|
var c = getColor(t);
|
||||||
c = applyWeatherTheme(c);
|
c = applyWeatherTheme(c);
|
||||||
|
// Expose current palette + weather info for the 2D renderer
|
||||||
|
window.__currentPalette = c;
|
||||||
|
window.__currentWeatherName = currentWeatherThemeName;
|
||||||
|
window.__currentDayProgress = realDayProgress;
|
||||||
|
window.__currentThemeSpeed = currentThemeSpeed;
|
||||||
effect.setOptions({
|
effect.setOptions({
|
||||||
skyColor: c.sky,
|
skyColor: c.sky,
|
||||||
cloudColor: c.cloud,
|
cloudColor: c.cloud,
|
||||||
|
|||||||
Vendored
+77
-23
@@ -4,7 +4,8 @@
|
|||||||
* fragment shader to produce animated cloud-like patterns.
|
* fragment shader to produce animated cloud-like patterns.
|
||||||
*
|
*
|
||||||
* Drop-in replacement for Vanta when CONFIG.renderer === 'clouds2d'.
|
* Drop-in replacement for Vanta when CONFIG.renderer === 'clouds2d'.
|
||||||
* Creates its own <canvas> overlay and attaches to the target element.
|
* Reads day/night palette + weather theme from window globals set
|
||||||
|
* by the parent (background.html's animate() loop).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@@ -42,14 +43,21 @@ var VERT_SRC = [
|
|||||||
'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }'
|
'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
// Fragment shader: animates an fBm cloud field, modulates density
|
||||||
|
// by weather, blends day/night palette colours, and adds a soft
|
||||||
|
// horizon gradient so the sky transitions naturally.
|
||||||
var FRAG_SRC = [
|
var FRAG_SRC = [
|
||||||
'precision highp float;',
|
'precision highp float;',
|
||||||
'uniform vec2 uResolution;',
|
'uniform vec2 uResolution;',
|
||||||
'uniform float uTime;',
|
'uniform float uTime;',
|
||||||
'uniform vec3 uSky;',
|
'uniform vec3 uSky;',
|
||||||
'uniform vec3 uCloud;',
|
'uniform vec3 uCloud;',
|
||||||
|
'uniform vec3 uCloudShadow;',
|
||||||
'uniform vec3 uLight;',
|
'uniform vec3 uLight;',
|
||||||
|
'uniform vec3 uBg;',
|
||||||
'uniform float uSpeed;',
|
'uniform float uSpeed;',
|
||||||
|
'uniform float uDensity;', // 0..1 how thick the clouds are
|
||||||
|
'uniform float uDayProgress;', // 0..1 (day vs night)
|
||||||
'float hash(vec2 p) {',
|
'float hash(vec2 p) {',
|
||||||
'p = fract(p * vec2(123.34, 456.21));',
|
'p = fract(p * vec2(123.34, 456.21));',
|
||||||
'p += dot(p, p + 45.32);',
|
'p += dot(p, p + 45.32);',
|
||||||
@@ -80,10 +88,21 @@ var FRAG_SRC = [
|
|||||||
'vec2 p1 = uv * vec2(3.0, 1.7) + vec2(uTime * 0.012, uTime * 0.004);',
|
'vec2 p1 = uv * vec2(3.0, 1.7) + vec2(uTime * 0.012, uTime * 0.004);',
|
||||||
'vec2 p2 = uv * vec2(5.0, 2.6) + vec2(uTime * 0.020, -uTime * 0.006);',
|
'vec2 p2 = uv * vec2(5.0, 2.6) + vec2(uTime * 0.020, -uTime * 0.006);',
|
||||||
'float n = fbm(p1 * uSpeed) * 0.6 + fbm(p2 * uSpeed) * 0.4;',
|
'float n = fbm(p1 * uSpeed) * 0.6 + fbm(p2 * uSpeed) * 0.4;',
|
||||||
'float cloud = smoothstep(0.35, 0.75, n);',
|
// Density threshold widens with uDensity (1 = always cloudy, 0 = clear sky)
|
||||||
'float horizon = smoothstep(0.0, 0.45, uv.y);',
|
'float thresh = mix(0.85, 0.30, uDensity);',
|
||||||
'vec3 col = mix(uSky, uCloud, cloud * (1.0 - horizon * 0.3));',
|
'float cloud = smoothstep(thresh - 0.10, thresh + 0.10, n);',
|
||||||
'col = mix(col, uLight, cloud * horizon * 0.5);',
|
// Soft horizon: top of frame is more sky, bottom more clouds
|
||||||
|
'float horizon = smoothstep(0.0, 0.5, uv.y);',
|
||||||
|
// Sky gradient (top vs bottom)
|
||||||
|
'vec3 sky = mix(uBg, uSky, horizon);',
|
||||||
|
// Cloud body (lit top + shadow bottom)
|
||||||
|
'vec3 cloudCol = mix(uCloudShadow, uCloud, horizon);',
|
||||||
|
// Add light tint to the lit side
|
||||||
|
'cloudCol = mix(cloudCol, uLight, cloud * horizon * 0.4 * uDayProgress);',
|
||||||
|
// Final composite: sky where there's no cloud, cloud where there is
|
||||||
|
'vec3 col = mix(sky, cloudCol, cloud);',
|
||||||
|
// At night, blend everything toward bg color (darken)
|
||||||
|
'col = mix(col, mix(uBg, cloudCol, 0.3), (1.0 - uDayProgress) * 0.5);',
|
||||||
'gl_FragColor = vec4(col, 1.0);',
|
'gl_FragColor = vec4(col, 1.0);',
|
||||||
'}'
|
'}'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
@@ -108,34 +127,51 @@ function init(canvas) {
|
|||||||
var uTime = gl.getUniformLocation(prog, 'uTime');
|
var uTime = gl.getUniformLocation(prog, 'uTime');
|
||||||
var uSky = gl.getUniformLocation(prog, 'uSky');
|
var uSky = gl.getUniformLocation(prog, 'uSky');
|
||||||
var uCloud = gl.getUniformLocation(prog, 'uCloud');
|
var uCloud = gl.getUniformLocation(prog, 'uCloud');
|
||||||
|
var uCloudShadow = gl.getUniformLocation(prog, 'uCloudShadow');
|
||||||
var uLight = gl.getUniformLocation(prog, 'uLight');
|
var uLight = gl.getUniformLocation(prog, 'uLight');
|
||||||
|
var uBg = gl.getUniformLocation(prog, 'uBg');
|
||||||
var uSpeed = gl.getUniformLocation(prog, 'uSpeed');
|
var uSpeed = gl.getUniformLocation(prog, 'uSpeed');
|
||||||
|
var uDensity = gl.getUniformLocation(prog, 'uDensity');
|
||||||
|
var uDayProgress = gl.getUniformLocation(prog, 'uDayProgress');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
gl: gl, prog: prog, buf: buf, aPos: aPos,
|
gl: gl, prog: prog, buf: buf, aPos: aPos,
|
||||||
uRes: uRes, uTime: uTime, uSky: uSky, uCloud: uCloud,
|
uRes: uRes, uTime: uTime, uSky: uSky, uCloud: uCloud,
|
||||||
uLight: uLight, uSpeed: uSpeed
|
uCloudShadow: uCloudShadow, uLight: uLight, uBg: uBg,
|
||||||
|
uSpeed: uSpeed, uDensity: uDensity, uDayProgress: uDayProgress
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function hex(r, g, b) { return [r/255, g/255, b/255]; }
|
// Convert 24-bit int (0xRRGGBB) to [r,g,b] 0..1 floats.
|
||||||
|
// Theme-agnostic: caller decides what colour value to pass in.
|
||||||
|
function hex(rgb) {
|
||||||
|
return [((rgb >> 16) & 255) / 255,
|
||||||
|
((rgb >> 8) & 255) / 255,
|
||||||
|
(rgb & 255) / 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cloud density per weather (0 = clear, 1 = overcast).
|
||||||
|
// Names mirror the weather themes defined in background.html.
|
||||||
|
var WEATHER_DENSITY = {
|
||||||
|
sunny: 0.20,
|
||||||
|
cloudy: 0.70,
|
||||||
|
stormy: 1.00,
|
||||||
|
night: 0.45
|
||||||
|
};
|
||||||
|
|
||||||
window.clouds2dRender = function(target) {
|
window.clouds2dRender = function(target) {
|
||||||
if (!target || typeof target !== 'object') {
|
if (!target || typeof target !== 'object') {
|
||||||
console.error('clouds2d: invalid target');
|
console.error('clouds2d: invalid target');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get or create the WebGL canvas
|
|
||||||
var canvas = target.__clouds2dCanvas;
|
var canvas = target.__clouds2dCanvas;
|
||||||
if (!canvas) {
|
if (!canvas) {
|
||||||
// Replace the target's content with a WebGL canvas
|
|
||||||
canvas = document.createElement('canvas');
|
canvas = document.createElement('canvas');
|
||||||
canvas.style.position = 'absolute';
|
canvas.style.position = 'absolute';
|
||||||
canvas.style.top = '0';
|
canvas.style.top = '0';
|
||||||
canvas.style.left = '0';
|
canvas.style.left = '0';
|
||||||
canvas.style.width = '100%';
|
canvas.style.width = '100%';
|
||||||
canvas.style.height = '100%';
|
canvas.style.height = '100%';
|
||||||
// Empty the target and insert the canvas as the only child
|
|
||||||
while (target.firstChild) target.removeChild(target.firstChild);
|
while (target.firstChild) target.removeChild(target.firstChild);
|
||||||
target.appendChild(canvas);
|
target.appendChild(canvas);
|
||||||
target.style.position = 'relative';
|
target.style.position = 'relative';
|
||||||
@@ -164,20 +200,38 @@ window.clouds2dRender = function(target) {
|
|||||||
gl.uniform2f(s.uRes, canvas.width, canvas.height);
|
gl.uniform2f(s.uRes, canvas.width, canvas.height);
|
||||||
gl.uniform1f(s.uTime, performance.now() / 1000);
|
gl.uniform1f(s.uTime, performance.now() / 1000);
|
||||||
|
|
||||||
var sky = [0.39, 0.54, 0.78];
|
// Pull palette + weather from globals (set by animate() in background.html).
|
||||||
var cloud = [0.43, 0.43, 0.43];
|
// No hardcoded fallbacks: until the parent has published a palette we
|
||||||
var light = [0.89, 0.87, 0.82];
|
// skip the draw and leave the WebGL context cleared. This keeps the
|
||||||
var cfg = window.CONFIG || {};
|
// renderer 100% theme-agnostic — the parent fully owns colour decisions.
|
||||||
var theme = (cfg.currentWeatherTheme || (cfg.weatherThemes && cfg.weatherThemes[cfg.theme])) || null;
|
var pal = window.__currentPalette;
|
||||||
if (theme) {
|
if (!pal) {
|
||||||
sky = hex((theme.skyColor >> 16) & 255, (theme.skyColor >> 8) & 255, theme.skyColor & 255);
|
gl.clearColor(0, 0, 0, 1);
|
||||||
cloud = hex((theme.cloudColor >> 16) & 255, (theme.cloudColor >> 8) & 255, theme.cloudColor & 255);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
light = hex((theme.lightColor >> 16) & 255, (theme.lightColor >> 8) & 255, theme.lightColor & 255);
|
return;
|
||||||
}
|
}
|
||||||
gl.uniform3fv(s.uSky, sky);
|
|
||||||
gl.uniform3fv(s.uCloud, cloud);
|
var weather = window.__currentWeatherName;
|
||||||
gl.uniform3fv(s.uLight, light);
|
var dayProgress = window.__currentDayProgress;
|
||||||
gl.uniform1f(s.uSpeed, 1.0);
|
var themeSpeed = window.__currentThemeSpeed;
|
||||||
|
|
||||||
|
gl.uniform3fv(s.uSky, hex(pal.sky));
|
||||||
|
gl.uniform3fv(s.uCloud, hex(pal.cloud));
|
||||||
|
gl.uniform3fv(s.uCloudShadow, hex(pal.cloudShadow !== undefined ? pal.cloudShadow : pal.sky));
|
||||||
|
gl.uniform3fv(s.uLight, hex(pal.light));
|
||||||
|
gl.uniform3fv(s.uBg, hex(pal.bg));
|
||||||
|
|
||||||
|
var density = (weather && WEATHER_DENSITY[weather] !== undefined)
|
||||||
|
? WEATHER_DENSITY[weather] : 0.5;
|
||||||
|
gl.uniform1f(s.uDensity, density);
|
||||||
|
|
||||||
|
var day = (typeof dayProgress === 'number')
|
||||||
|
? Math.max(0, Math.min(1, dayProgress)) : 0.5;
|
||||||
|
gl.uniform1f(s.uDayProgress, day);
|
||||||
|
|
||||||
|
var speed = (typeof themeSpeed === 'number')
|
||||||
|
? Math.max(0.1, Math.min(3, themeSpeed)) : 1.0;
|
||||||
|
gl.uniform1f(s.uSpeed, speed);
|
||||||
|
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user