From 0f54adefda894c97377085b808856107b9ed8027 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Wed, 7 Oct 2026 20:58:36 +0200 Subject: [PATCH] Fix clouds3d: missing closing quote on long string literal at line 202 --- vendor/clouds2d.js | 283 --------------------------------------------- vendor/clouds3d.js | 2 +- 2 files changed, 1 insertion(+), 284 deletions(-) diff --git a/vendor/clouds2d.js b/vendor/clouds2d.js index 6ae0acd..e69de29 100644 --- a/vendor/clouds2d.js +++ b/vendor/clouds2d.js @@ -1,283 +0,0 @@ -/* Texture-based 2D cloud renderer. - * - * Inspired by fizzer's tiny ShaderToy cloud shader: instead of - * computing fBm in-shader with hash functions, sample a noise - * texture (4 lookups = 4 octaves) and weight the results. This - * trades a tiny amount of texture memory for a large drop in ALU - * per pixel — significant on low-end integrated GPUs. - * - * Texture is loaded from window.__noiseDataUri (a data URI baked - * from noise.png by the build). Falls back to /noise.png if the - * URI is unavailable. Theme-agnostic: parent owns colour via - * __currentPalette. - */ - -(function() { - -function makeShader(gl, type, src) { - var s = gl.createShader(type); - gl.shaderSource(s, src); - gl.compileShader(s); - if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) { - console.error('clouds2d: Shader compile error:', gl.getShaderInfoLog(s)); - gl.deleteShader(s); - return null; - } - return s; -} - -function makeProgram(gl, vsSrc, fsSrc) { - var vs = makeShader(gl, gl.VERTEX_SHADER, vsSrc); - var fs = makeShader(gl, gl.FRAGMENT_SHADER, fsSrc); - if (!vs || !fs) return null; - var p = gl.createProgram(); - gl.attachShader(p, vs); - gl.attachShader(p, fs); - gl.linkProgram(p); - if (!gl.getProgramParameter(p, gl.LINK_STATUS)) { - console.error('clouds2d: Program link error:', gl.getProgramInfoLog(p)); - gl.deleteProgram(p); - return null; - } - return p; -} - -var VERT_SRC = [ - 'attribute vec2 aPos;', - 'void main() { gl_Position = vec4(aPos, 0.0, 1.0); }' -].join('\n'); - -// 4-octave fBm by sampling a noise texture. The texture is REPEAT- -// wrapped so we can scroll through it endlessly. Scrolling uses a -// hash-based per-pixel jitter so the regular tiling pattern doesn't -// cause horizon flicker (same fix as clouds3d). -var FRAG_SRC = [ - 'precision highp float;', - 'uniform vec2 uResolution;', - 'uniform float uTime;', - 'uniform sampler2D uNoise;', - 'uniform vec3 uSky;', - 'uniform vec3 uCloud;', - 'uniform vec3 uCloudShadow;', - 'uniform vec3 uLight;', - 'uniform vec3 uBg;', - 'uniform float uSpeed;', - 'uniform float uDensity;', - 'uniform float uDayProgress;', - 'uniform float uSunAlt;', - 'float hash21(vec2 p) {', - 'p = fract(p * vec2(123.34, 456.21));', - 'p += dot(p, p + 45.32);', - 'return fract(p.x * p.y);', - '}', - // 4-octave texture fBm. Each octave doubles frequency and halves - // amplitude (1, 0.5, 0.25, 0.125). Total normalised by 1/0.9375. - 'float fbm(vec2 p) {', - 'float total = 0.0;', - 'total += 1.0 * texture2D(uNoise, p * 1.0).r;', - 'total += 0.5 * texture2D(uNoise, p * 2.0).r;', - 'total += 0.25 * texture2D(uNoise, p * 4.0).r;', - 'total += 0.125 * texture2D(uNoise, p * 8.0).r;', - 'return total / 1.875;', - '}', - 'void main() {', - 'vec2 uv = gl_FragCoord.xy / uResolution.xy;', - // Scroll the noise field horizontally with time, plus a small - // vertical drift for slow cloud movement. Multiply by uv's - // aspect so clouds don't squash on wide displays. - 'float aspect = uResolution.x / uResolution.y;', - 'vec2 p = vec2(', - '(uv.x - 0.5) * aspect * 3.0 + uTime * 0.04 * uSpeed,', - 'uv.y * 2.5 + uTime * 0.012 * uSpeed', - ');', - // Per-pixel jitter to break the regular tiling pattern that - // would otherwise flicker at the cloud horizon. - 'p += (hash21(gl_FragCoord.xy + uTime) - 0.5) * 0.015;', - 'float n = fbm(p);', - // Density threshold widens with weather (sunny = sparse, - // stormy = overcast). - 'float thresh = mix(0.70, 0.35, uDensity);', - 'float cloud = smoothstep(thresh, thresh + 0.18, n);', - // Sky gradient: bg below, sky above - 'vec3 sky = mix(uBg, uSky, smoothstep(0.0, 0.6, uv.y));', - // Cloud body: shadow on the bottom, lit on the top - 'vec3 cloudCol = mix(uCloudShadow, uCloud, smoothstep(0.0, 0.7, uv.y));', - // Light tint on the lit side (always slightly, so even at - // night the cloud edge catches some illumination) - 'cloudCol = mix(cloudCol, uLight, cloud * uv.y * 0.45 * max(0.15, uDayProgress));', - // Composite - 'vec3 col = mix(sky, cloudCol, cloud);', - // Night darkening, driven by sun altitude (not uDayProgress - // which is a 24h clock progress, not "is it night") - 'float nightFactor = smoothstep(0.05, -0.15, uSunAlt);', - // Stronger than clouds3d because there's no cloud-mask - // blending here — just multiply. - 'col *= 1.0 - nightFactor * 0.7;', - 'gl_FragColor = vec4(col, 1.0);', - '}' -].join('\n'); - -function hex(rgb) { - return [((rgb >> 16) & 255) / 255, - ((rgb >> 8) & 255) / 255, - (rgb & 255) / 255]; -} - -var WEATHER_DENSITY = { - sunny: 0.20, - cloudy: 0.70, - stormy: 1.00, - night: 0.45 -}; - -// Load the noise image and upload it as a REPEAT-wrapped texture. -// Priority: window.__noiseDataUri (if it has real data, not -// PLACEHOLDER), else fetch /noise.png from the server. -function loadNoiseTexture(gl) { - return new Promise(function(resolve, reject) { - var inline = window.__noiseDataUri; - var hasInline = inline && inline.indexOf('PLACEHOLDER') < 0; - var src = hasInline ? inline : 'noise.png'; - var img = new Image(); - img.onload = function() { - var tex = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, tex); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - resolve(tex); - }; - img.onerror = function() { - reject(new Error('clouds2d: failed to load noise image: ' + src)); - }; - img.src = src; - }); -} - -window.clouds2dRender = function(target) { - if (!target || typeof target !== 'object') { - console.error('clouds2d: invalid target'); - return; - } - var canvas = target.__clouds2dCanvas; - if (!canvas) { - canvas = document.createElement('canvas'); - canvas.style.position = 'absolute'; - canvas.style.top = '0'; - canvas.style.left = '0'; - canvas.style.width = '100%'; - canvas.style.height = '100%'; - while (target.firstChild) target.removeChild(target.firstChild); - target.appendChild(canvas); - target.style.position = 'relative'; - target.__clouds2dCanvas = canvas; - } - - var gl = canvas.__gl; - if (!gl) { - gl = canvas.getContext('webgl', { antialias: false, alpha: false }); - if (!gl) { - console.error('clouds2d: WebGL not available'); - return; - } - canvas.__gl = gl; - } - - if (!canvas.__state) { - // Compile shaders synchronously, load texture asynchronously. - var buf = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buf); - gl.bufferData(gl.ARRAY_BUFFER, - new Float32Array([ -1,-1, 3,-1, -1,3 ]), - gl.STATIC_DRAW); - var prog = makeProgram(gl, VERT_SRC, FRAG_SRC); - if (!prog) return; - canvas.__state = { - gl: gl, prog: prog, buf: buf, - aPos: gl.getAttribLocation(prog, 'aPos'), - uRes: gl.getUniformLocation(prog, 'uResolution'), - uTime: gl.getUniformLocation(prog, 'uTime'), - uNoise: gl.getUniformLocation(prog, 'uNoise'), - uSky: gl.getUniformLocation(prog, 'uSky'), - uCloud: gl.getUniformLocation(prog, 'uCloud'), - uCloudShadow: gl.getUniformLocation(prog, 'uCloudShadow'), - uLight: gl.getUniformLocation(prog, 'uLight'), - uBg: gl.getUniformLocation(prog, 'uBg'), - uSpeed: gl.getUniformLocation(prog, 'uSpeed'), - uDensity: gl.getUniformLocation(prog, 'uDensity'), - uDayProgress: gl.getUniformLocation(prog, 'uDayProgress'), - uSunAlt: gl.getUniformLocation(prog, 'uSunAlt') - }; - canvas.__noiseReady = false; - loadNoiseTexture(gl).then(function(tex) { - canvas.__noise = tex; - canvas.__noiseReady = true; - }).catch(function(err) { - console.error(err); - }); - } - - var s = canvas.__state; - canvas.width = target.clientWidth || window.innerWidth; - canvas.height = target.clientHeight || window.innerHeight; - gl.viewport(0, 0, canvas.width, canvas.height); - - // Texture not loaded yet — just clear, frame after will draw. - if (!canvas.__noiseReady) { - gl.clearColor(0, 0, 0, 1); - gl.clear(gl.COLOR_BUFFER_BIT); - return; - } - - gl.useProgram(s.prog); - gl.bindBuffer(gl.ARRAY_BUFFER, s.buf); - gl.enableVertexAttribArray(s.aPos); - gl.vertexAttribPointer(s.aPos, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, canvas.__noise); - gl.uniform1i(s.uNoise, 0); - - gl.uniform2f(s.uRes, canvas.width, canvas.height); - gl.uniform1f(s.uTime, performance.now() / 1000); - - var pal = window.__currentPalette; - if (!pal) { - gl.clearColor(0, 0, 0, 1); - gl.clear(gl.COLOR_BUFFER_BIT); - return; - } - - var weather = window.__currentWeatherName; - var dayProgress = window.__currentDayProgress; - var themeSpeed = window.__currentThemeSpeed; - var sunAlt = window.__currentSunAlt; - - 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.uniform1f(s.uSunAlt, (typeof sunAlt === 'number') ? sunAlt : 0); - - gl.drawArrays(gl.TRIANGLES, 0, 3); -}; - -})(); \ No newline at end of file diff --git a/vendor/clouds3d.js b/vendor/clouds3d.js index 4142df7..89e25bb 100644 --- a/vendor/clouds3d.js +++ b/vendor/clouds3d.js @@ -199,7 +199,7 @@ var FRAG_SRC = [ // remain visible against a deep but not void-black sky. 'float skyDarkness = nightFactor * 0.55;', 'col = mix(col, col * (1.0 - skyDarkness), 1.0 - cloud);', - '// Horizon: cast the ray onto the ground plane (y=0) and sample the satellite image at that world (x,z) coordinate. As the camera drifts forward over time the texture scrolls past, giving the illusion of flying over real terrain. Distant ground fades toward sky colour (atmospheric perspective). + '// Horizon: cast the ray onto the ground plane (y=0) and sample the satellite image at that world (x,z) coordinate. As the camera drifts forward over time the texture scrolls past, giving the illusion of flying over real terrain. Distant ground fades toward sky colour (atmospheric perspective).', 'float tGround = (ro.y > 0.0 && rd.y < -0.001) ? -ro.y / rd.y : -1.0;', 'vec3 hitPoint = ro + rd * tGround;', '// UV from world (hitPoint - centre) / size + 0.5 — the mosaic moves with the camera so the centre is always at 0.5',