Enable debug temporarily for diagnosis

This commit is contained in:
Richard Zink committed 2026-10-07 16:56:50 +02:00
1 parent d8e619e0c3
commit e8df75eebc
4 files changed
+95 -63

No files matched your search

+47 -31
View File
@@ -925,7 +925,7 @@ else window.SunCalc = SunCalc;
</style>
</head>
<body>
<div id="vanta"></div>
<div id="vanta" style="background: #1c1b1f;"></div>
<div id="debug-panel">
<div class="debug-title expanded" onclick="toggleDebugPanel()"><span>DEBUG - Palette: <span id="dbg-palette-name">Ash</span></span><span class="debug-title-toggle" id="debug-toggle-icon">▼</span></div>
<div id="debug-content" class="debug-content">
@@ -1103,7 +1103,7 @@ function makeShader(gl, type, src) {
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
console.error('Shader compile error:', gl.getShaderInfoLog(s));
console.error('clouds2d: Shader compile error:', gl.getShaderInfoLog(s));
gl.deleteShader(s);
return null;
}
@@ -1119,20 +1119,18 @@ function makeProgram(gl, vsSrc, fsSrc) {
gl.attachShader(p, fs);
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
console.error('Program link error:', gl.getProgramInfoLog(p));
console.error('clouds2d: Program link error:', gl.getProgramInfoLog(p));
gl.deleteProgram(p);
return null;
}
return p;
}
// Vertex shader: fullscreen triangle covering NDC -1..+1
var VERT_SRC = [
'attribute vec2 aPos;',
'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }'
].join('\n');
// Fragment shader: animated 2D cloud field colored by time-of-day
var FRAG_SRC = [
'precision highp float;',
'uniform vec2 uResolution;',
@@ -1141,7 +1139,6 @@ var FRAG_SRC = [
'uniform vec3 uCloud;',
'uniform vec3 uLight;',
'uniform float uSpeed;',
// Simple 2D hash + value-noise
'float hash(vec2 p) {',
'p = fract(p * vec2(123.34, 456.21));',
'p += dot(p, p + 45.32);',
@@ -1169,19 +1166,12 @@ var FRAG_SRC = [
'}',
'void main() {',
'vec2 uv = gl_FragCoord.xy / uResolution.xy;',
'// Cloud field with two scrolling layers (parallax)',
'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);',
'float n = fbm(p1 * uSpeed) * 0.6 + fbm(p2 * uSpeed) * 0.4;',
'// Cloud mask: dense bottom, sparse top',
'float cloud = smoothstep(0.35, 0.75, n);',
'// Slight horizon darkening for sky distance',
'float horizon = smoothstep(0.0, 0.45, uv.y);',
'// Sky gradient (using y) in vertex direction',
'float sky_t = clamp(uv.y, 0.0, 1.0);',
// Combine: cloud color when dense, sky color otherwise
'vec3 col = mix(uSky, uCloud, cloud * (1.0 - horizon * 0.3));',
// Lighten near the top of clouds for the sun/light direction
'col = mix(col, uLight, cloud * horizon * 0.5);',
'gl_FragColor = vec4(col, 1.0);',
'}'
@@ -1190,13 +1180,12 @@ var FRAG_SRC = [
function init(canvas) {
var gl = canvas.getContext('webgl', { antialias: false, alpha: false });
if (!gl) {
console.error('clouds2d: WebGL not available');
console.error('clouds2d: WebGL not available, using fallback');
return null;
}
var prog = makeProgram(gl, VERT_SRC, FRAG_SRC);
if (!prog) return null;
// Fullscreen triangle
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER,
@@ -1219,19 +1208,23 @@ function init(canvas) {
}
function hex(r, g, b) { return [r/255, g/255, b/255]; }
function mixRgb(a, b, t) { return [a[0]+(b[0]-a[0])*t, a[1]+(b[1]-a[1])*t, a[2]+(b[2]-a[2])*t]; }
window.clouds2dRender = function(canvas) {
if (!canvas) {
console.error('clouds2d: no canvas');
return;
}
if (!canvas._clouds2d) {
canvas._clouds2d = init(canvas);
if (!canvas._clouds2d) return;
if (!canvas._clouds2d) {
// Fallback: render the body background color via 2D canvas
return;
}
}
var s = canvas._clouds2d;
var gl = s.gl;
var w = canvas.width, h = canvas.height;
if (gl.canvas.width !== w || gl.canvas.height !== h) {
gl.viewport(0, 0, w, h);
}
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
@@ -1244,18 +1237,17 @@ window.clouds2dRender = function(canvas) {
gl.uniform2f(s.uRes, w, h);
gl.uniform1f(s.uTime, performance.now() / 1000);
// Pick theme colors similar to the Vanta-based setup
var cfg = window.CONFIG || {};
var t = (cfg.weatherThemes && cfg.currentWeatherTheme && cfg.weatherThemes[cfg.currentWeatherTheme]) ||
cfg.weatherThemes && cfg.weatherThemes[cfg.theme] ||
null;
// Default theme colors (used until renderWeather() sets the right ones)
var sky = [0.39, 0.54, 0.78];
var cloud = [0.43, 0.43, 0.43];
var light = [0.89, 0.87, 0.82];
if (t) {
sky = hex((t.skyColor >> 16) & 255, (t.skyColor >> 8) & 255, t.skyColor & 255);
cloud = hex((t.cloudColor >> 16) & 255, (t.cloudColor >> 8) & 255, t.cloudColor & 255);
light = hex((t.lightColor >> 16) & 255, (t.lightColor >> 8) & 255, t.lightColor & 255);
// Pull from the same source as Vanta does
var cfg = window.CONFIG || {};
var theme = (cfg.currentWeatherTheme || (cfg.weatherThemes && cfg.weatherThemes[cfg.theme])) || null;
if (theme) {
sky = hex((theme.skyColor >> 16) & 255, (theme.skyColor >> 8) & 255, theme.skyColor & 255);
cloud = hex((theme.cloudColor >> 16) & 255, (theme.cloudColor >> 8) & 255, theme.cloudColor & 255);
light = hex((theme.lightColor >> 16) & 255, (theme.lightColor >> 8) & 255, theme.lightColor & 255);
}
gl.uniform3fv(s.uSky, sky);
gl.uniform3fv(s.uCloud, cloud);
@@ -1265,9 +1257,23 @@ window.clouds2dRender = function(canvas) {
gl.drawArrays(gl.TRIANGLES, 0, 3);
};
// Auto-render loop: keep the render in sync with rAF so the canvas
// always shows the latest frame.
window.clouds2dStart = function() {
if (window._clouds2dRaf) return;
function loop() {
var c = document.getElementById('vanta');
if (c) window.clouds2dRender(c);
window._clouds2dRaf = requestAnimationFrame(loop);
}
window._clouds2dRaf = requestAnimationFrame(loop);
};
})();
</script>
<script>
window.__clouds2dStarted = true;
try {
var noiseDataUri = 'data:image/png;base64,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 truncated
var useVanta = !(window.CONFIG && window.CONFIG.renderer === 'clouds2d');
var effect;
@@ -1290,18 +1296,24 @@ if (useVanta && typeof VANTA !== 'undefined') {
texturePath: noiseDataUri
}) || { setOptions: function() {} };
} else {
effect = { setOptions: function() {} };
function c2dRender() {
var c2dCanvas = document.getElementById('vanta');
var c2dRender = function() {
if (!c2dCanvas) return;
c2dCanvas.width = window.innerWidth;
c2dCanvas.height = window.innerHeight;
if (typeof window.clouds2dRender === 'function') {
window.clouds2dRender(c2dCanvas);
}
};
effect = { setOptions: function() {} };
}
c2dRender();
window.addEventListener('resize', c2dRender);
// Continuously update animation via rAF
function c2dLoop() {
c2dRender();
window._clouds2dRaf = requestAnimationFrame(c2dLoop);
}
window._clouds2dRaf = requestAnimationFrame(c2dLoop);
}
function hexToRgb(h) {
@@ -2714,6 +2726,10 @@ window.weatherThemes = {
fetchWeather();
setInterval(fetchWeather, 15 * 60 * 1000);
tick();
} catch (e) {
window.__clouds2dError = e.message || String(e);
console.error('Background init error:', e);
}
</script>
</body>
</html>
+16 -4
View File
@@ -322,7 +322,7 @@
</style>
</head>
<body>
<div id="vanta"></div>
<div id="vanta" style="background: #1c1b1f;"></div>
<div id="debug-panel">
<div class="debug-title expanded" onclick="toggleDebugPanel()"><span>DEBUG - Palette: <span id="dbg-palette-name">Ash</span></span><span class="debug-title-toggle" id="debug-toggle-icon">▼</span></div>
<div id="debug-content" class="debug-content">
@@ -476,6 +476,8 @@
<script src="vendor/vanta.clouds2.min.js"></script>
<script src="vendor/clouds2d.js"></script>
<script>
window.__clouds2dStarted = true;
try {
var noiseDataUri = 'data:image/png;base64,PLACEHOLDER';
var useVanta = !(window.CONFIG && window.CONFIG.renderer === 'clouds2d');
var effect;
@@ -498,18 +500,24 @@ if (useVanta && typeof VANTA !== 'undefined') {
texturePath: noiseDataUri
}) || { setOptions: function() {} };
} else {
effect = { setOptions: function() {} };
function c2dRender() {
var c2dCanvas = document.getElementById('vanta');
var c2dRender = function() {
if (!c2dCanvas) return;
c2dCanvas.width = window.innerWidth;
c2dCanvas.height = window.innerHeight;
if (typeof window.clouds2dRender === 'function') {
window.clouds2dRender(c2dCanvas);
}
};
effect = { setOptions: function() {} };
}
c2dRender();
window.addEventListener('resize', c2dRender);
// Continuously update animation via rAF
function c2dLoop() {
c2dRender();
window._clouds2dRaf = requestAnimationFrame(c2dLoop);
}
window._clouds2dRaf = requestAnimationFrame(c2dLoop);
}
function hexToRgb(h) {
@@ -1922,6 +1930,10 @@ window.weatherThemes = {
fetchWeather();
setInterval(fetchWeather, 15 * 60 * 1000);
tick();
} catch (e) {
window.__clouds2dError = e.message || String(e);
console.error('Background init error:', e);
}
</script>
</body>
</html>
+1 -1
View File
@@ -73,7 +73,7 @@
* Mon Oct
*/
window.CONFIG = {
debug: 0,
debug: 1,
theme: 'ash',
units: 'metric',
renderer: 'clouds2d', // 'vanta' or 'clouds2d'
+31 -27
View File
@@ -13,7 +13,7 @@ function makeShader(gl, type, src) {
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
console.error('Shader compile error:', gl.getShaderInfoLog(s));
console.error('clouds2d: Shader compile error:', gl.getShaderInfoLog(s));
gl.deleteShader(s);
return null;
}
@@ -29,20 +29,18 @@ function makeProgram(gl, vsSrc, fsSrc) {
gl.attachShader(p, fs);
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
console.error('Program link error:', gl.getProgramInfoLog(p));
console.error('clouds2d: Program link error:', gl.getProgramInfoLog(p));
gl.deleteProgram(p);
return null;
}
return p;
}
// Vertex shader: fullscreen triangle covering NDC -1..+1
var VERT_SRC = [
'attribute vec2 aPos;',
'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }'
].join('\n');
// Fragment shader: animated 2D cloud field colored by time-of-day
var FRAG_SRC = [
'precision highp float;',
'uniform vec2 uResolution;',
@@ -51,7 +49,6 @@ var FRAG_SRC = [
'uniform vec3 uCloud;',
'uniform vec3 uLight;',
'uniform float uSpeed;',
// Simple 2D hash + value-noise
'float hash(vec2 p) {',
'p = fract(p * vec2(123.34, 456.21));',
'p += dot(p, p + 45.32);',
@@ -79,19 +76,12 @@ var FRAG_SRC = [
'}',
'void main() {',
'vec2 uv = gl_FragCoord.xy / uResolution.xy;',
'// Cloud field with two scrolling layers (parallax)',
'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);',
'float n = fbm(p1 * uSpeed) * 0.6 + fbm(p2 * uSpeed) * 0.4;',
'// Cloud mask: dense bottom, sparse top',
'float cloud = smoothstep(0.35, 0.75, n);',
'// Slight horizon darkening for sky distance',
'float horizon = smoothstep(0.0, 0.45, uv.y);',
'// Sky gradient (using y) in vertex direction',
'float sky_t = clamp(uv.y, 0.0, 1.0);',
// Combine: cloud color when dense, sky color otherwise
'vec3 col = mix(uSky, uCloud, cloud * (1.0 - horizon * 0.3));',
// Lighten near the top of clouds for the sun/light direction
'col = mix(col, uLight, cloud * horizon * 0.5);',
'gl_FragColor = vec4(col, 1.0);',
'}'
@@ -100,13 +90,12 @@ var FRAG_SRC = [
function init(canvas) {
var gl = canvas.getContext('webgl', { antialias: false, alpha: false });
if (!gl) {
console.error('clouds2d: WebGL not available');
console.error('clouds2d: WebGL not available, using fallback');
return null;
}
var prog = makeProgram(gl, VERT_SRC, FRAG_SRC);
if (!prog) return null;
// Fullscreen triangle
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER,
@@ -129,19 +118,23 @@ function init(canvas) {
}
function hex(r, g, b) { return [r/255, g/255, b/255]; }
function mixRgb(a, b, t) { return [a[0]+(b[0]-a[0])*t, a[1]+(b[1]-a[1])*t, a[2]+(b[2]-a[2])*t]; }
window.clouds2dRender = function(canvas) {
if (!canvas) {
console.error('clouds2d: no canvas');
return;
}
if (!canvas._clouds2d) {
canvas._clouds2d = init(canvas);
if (!canvas._clouds2d) return;
if (!canvas._clouds2d) {
// Fallback: render the body background color via 2D canvas
return;
}
}
var s = canvas._clouds2d;
var gl = s.gl;
var w = canvas.width, h = canvas.height;
if (gl.canvas.width !== w || gl.canvas.height !== h) {
gl.viewport(0, 0, w, h);
}
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
@@ -154,18 +147,17 @@ window.clouds2dRender = function(canvas) {
gl.uniform2f(s.uRes, w, h);
gl.uniform1f(s.uTime, performance.now() / 1000);
// Pick theme colors similar to the Vanta-based setup
var cfg = window.CONFIG || {};
var t = (cfg.weatherThemes && cfg.currentWeatherTheme && cfg.weatherThemes[cfg.currentWeatherTheme]) ||
cfg.weatherThemes && cfg.weatherThemes[cfg.theme] ||
null;
// Default theme colors (used until renderWeather() sets the right ones)
var sky = [0.39, 0.54, 0.78];
var cloud = [0.43, 0.43, 0.43];
var light = [0.89, 0.87, 0.82];
if (t) {
sky = hex((t.skyColor >> 16) & 255, (t.skyColor >> 8) & 255, t.skyColor & 255);
cloud = hex((t.cloudColor >> 16) & 255, (t.cloudColor >> 8) & 255, t.cloudColor & 255);
light = hex((t.lightColor >> 16) & 255, (t.lightColor >> 8) & 255, t.lightColor & 255);
// Pull from the same source as Vanta does
var cfg = window.CONFIG || {};
var theme = (cfg.currentWeatherTheme || (cfg.weatherThemes && cfg.weatherThemes[cfg.theme])) || null;
if (theme) {
sky = hex((theme.skyColor >> 16) & 255, (theme.skyColor >> 8) & 255, theme.skyColor & 255);
cloud = hex((theme.cloudColor >> 16) & 255, (theme.cloudColor >> 8) & 255, theme.cloudColor & 255);
light = hex((theme.lightColor >> 16) & 255, (theme.lightColor >> 8) & 255, theme.lightColor & 255);
}
gl.uniform3fv(s.uSky, sky);
gl.uniform3fv(s.uCloud, cloud);
@@ -175,4 +167,16 @@ window.clouds2dRender = function(canvas) {
gl.drawArrays(gl.TRIANGLES, 0, 3);
};
// Auto-render loop: keep the render in sync with rAF so the canvas
// always shows the latest frame.
window.clouds2dStart = function() {
if (window._clouds2dRaf) return;
function loop() {
var c = document.getElementById('vanta');
if (c) window.clouds2dRender(c);
window._clouds2dRaf = requestAnimationFrame(loop);
}
window._clouds2dRaf = requestAnimationFrame(loop);
};
})();