// Weather controller. Two drivers feed the background canvas: // // 1. The server picks a *seasonal* variant + intensity from the Lisbon-local // date and writes them to . This is the // default when the visitor hasn't set a location. // 2. weather-forecast.js, when a postal code is saved, fetches the real // forecast and calls PeteWeather.set(variant, intensity) to override the // background with live conditions. // // Rendering is delegated to an engine: the WebGL2 one (weather-gl.js) when the // browser supports it — GPU sprites, shader fog/aurora, real lightning — with // the original Canvas2D renderer (weather-2d.js) as the fallback. This file // only owns the toggle button, the on/off preference and the public API. (function () { var root = document.documentElement; var canvas = document.getElementById("pete-weather"); if (!canvas) return; var reducedMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; var engines = window.PeteWeatherEngines || {}; var engine = (engines.webgl2 && engines.webgl2(canvas)) || null; if (!engine && engines.canvas2d) engine = engines.canvas2d(canvas); if (!engine) return; var STORAGE_KEY = "pete-weather-off"; var toggleBtn = document.querySelector("[data-weather-toggle]"); var star = document.querySelector("[data-weather-star]"); function userDisabled() { try { return localStorage.getItem(STORAGE_KEY) === "1"; } catch (e) { return false; } } function setDisabled(v) { try { if (v) localStorage.setItem(STORAGE_KEY, "1"); else localStorage.removeItem(STORAGE_KEY); } catch (e) {} if (window.PetePrefs) window.PetePrefs.push(); } function syncBtn(enabled) { if (!toggleBtn) return; toggleBtn.setAttribute("aria-pressed", enabled ? "true" : "false"); toggleBtn.title = enabled ? "Turn off weather animation" : "Turn on weather animation"; if (star) { star.style.color = "var(--accent)"; star.style.opacity = enabled ? "1" : "0.3"; star.style.filter = enabled ? "none" : "grayscale(1)"; } } var enabled = !userDisabled() && !reducedMotion; // Public hook so weather-forecast.js (and the /weather demo) can swap the // seasonal default for other conditions. Passing a falsy variant clears the // canvas. window.PeteWeather = { set: function (v, inten) { root.dataset.weather = v || ""; if (inten) root.dataset.intensity = inten; engine.set(v || null, inten || root.dataset.intensity || "heavy"); if (enabled && v) engine.start(); }, isEnabled: function () { return enabled; }, renderer: function () { return engine.name; } }; syncBtn(enabled); engine.set(root.dataset.weather || null, root.dataset.intensity || "heavy"); if (enabled && root.dataset.weather) engine.start(); if (toggleBtn) { toggleBtn.addEventListener("click", function () { enabled = !enabled; setDisabled(!enabled); syncBtn(enabled); if (enabled) engine.start(); else engine.stop(); }); } document.addEventListener("visibilitychange", function () { if (!enabled) return; if (document.hidden) engine.stop(); else engine.start(); }); })();