Fix clouds2d: create own canvas element

The 2D WebGL renderer now creates its own <canvas> overlay inside
the target element, instead of expecting the target to already be a
canvas. This fixes 'canvas.getContext is not a function' when the
target is a <div>.
This commit is contained in:
Richard Zink committed 2026-10-07 18:49:42 +02:00
1 parent e8df75eebc
commit c6764fd534
4 files changed
+77 -63

No files matched your search

+31 -28
View File
@@ -4,6 +4,7 @@
* fragment shader to produce animated cloud-like patterns.
*
* Drop-in replacement for Vanta when CONFIG.renderer === 'clouds2d'.
* Creates its own <canvas> overlay and attaches to the target element.
*/
(function() {
@@ -90,7 +91,7 @@ var FRAG_SRC = [
function init(canvas) {
var gl = canvas.getContext('webgl', { antialias: false, alpha: false });
if (!gl) {
console.error('clouds2d: WebGL not available, using fallback');
console.error('clouds2d: WebGL not available');
return null;
}
var prog = makeProgram(gl, VERT_SRC, FRAG_SRC);
@@ -119,22 +120,38 @@ function init(canvas) {
function hex(r, g, b) { return [r/255, g/255, b/255]; }
window.clouds2dRender = function(canvas) {
if (!canvas) {
console.error('clouds2d: no canvas');
window.clouds2dRender = function(target) {
if (!target || typeof target !== 'object') {
console.error('clouds2d: invalid target');
return;
}
if (!canvas._clouds2d) {
canvas._clouds2d = init(canvas);
if (!canvas._clouds2d) {
// Fallback: render the body background color via 2D canvas
return;
}
// Get or create the WebGL canvas
var canvas = target.__clouds2dCanvas;
if (!canvas) {
// Replace the target's content with a WebGL 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%';
// Empty the target and insert the canvas as the only child
while (target.firstChild) target.removeChild(target.firstChild);
target.appendChild(canvas);
target.style.position = 'relative';
target.__clouds2dCanvas = canvas;
}
var s = canvas._clouds2d;
if (!canvas.__state) {
canvas.__state = init(canvas);
if (!canvas.__state) return;
}
var s = canvas.__state;
var gl = s.gl;
var w = canvas.width, h = canvas.height;
gl.viewport(0, 0, w, h);
canvas.width = target.clientWidth || window.innerWidth;
canvas.height = target.clientHeight || window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
@@ -144,14 +161,12 @@ window.clouds2dRender = function(canvas) {
gl.enableVertexAttribArray(s.aPos);
gl.vertexAttribPointer(s.aPos, 2, gl.FLOAT, false, 0, 0);
gl.uniform2f(s.uRes, w, h);
gl.uniform2f(s.uRes, canvas.width, canvas.height);
gl.uniform1f(s.uTime, performance.now() / 1000);
// 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];
// 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) {
@@ -167,16 +182,4 @@ 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);
};
})();