weather: add synthetic rain and snow simulation states
This commit is contained in:
1 parent
2ad5d9f8f9
commit
65e31a5302
3 files changed
+131
-13
No files matched your search
+109
-6
@@ -803,6 +803,20 @@ window.addEventListener('resize', scheduleFitInfoPanel);
|
||||
backgroundColor: hexToInt(ASH.void),
|
||||
speed: 2.5
|
||||
},
|
||||
rain: {
|
||||
skyColor: hexToInt(ASH.steel),
|
||||
cloudColor: hexToInt(ASH.panel),
|
||||
lightColor: hexToInt(ASH.bone),
|
||||
backgroundColor: hexToInt(ASH.void),
|
||||
speed: 1.8
|
||||
},
|
||||
snow: {
|
||||
skyColor: hexToInt(ASH.blue),
|
||||
cloudColor: hexToInt(ASH.chalk),
|
||||
lightColor: hexToInt(ASH.chalkLight),
|
||||
backgroundColor: hexToInt(ASH.steel),
|
||||
speed: 0.7
|
||||
},
|
||||
night: {
|
||||
skyColor: hexToInt(ASH.void),
|
||||
cloudColor: hexToInt(ASH.raised),
|
||||
@@ -1444,6 +1458,22 @@ window.weatherThemes = {
|
||||
backgroundColor: hexToInt(ASH.panel),
|
||||
speed: 2.5
|
||||
},
|
||||
rain: {
|
||||
// Wet grey overcast, faster cloud motion
|
||||
skyColor: hexToInt(ASH.steel),
|
||||
cloudColor: hexToInt(ASH.stone),
|
||||
lightColor: hexToInt(ASH.bone),
|
||||
backgroundColor: hexToInt(ASH.panel),
|
||||
speed: 1.8
|
||||
},
|
||||
snow: {
|
||||
// Cold pale overcast, slow drifting cloud field
|
||||
skyColor: hexToInt(ASH.blue),
|
||||
cloudColor: hexToInt(ASH.boneLight),
|
||||
lightColor: hexToInt(ASH.chalk),
|
||||
backgroundColor: hexToInt(ASH.steel),
|
||||
speed: 0.7
|
||||
},
|
||||
night: {
|
||||
// Very dark sky, moon-lit clouds
|
||||
skyColor: hexToInt(ASH.void),
|
||||
@@ -1458,7 +1488,8 @@ window.weatherThemes = {
|
||||
if (code === 0) return 'sunny';
|
||||
if (code >= 1 && code <= 3) return 'cloudy';
|
||||
if (code >= 45 && code <= 48) return 'cloudy';
|
||||
if ((code >= 51 && code <= 67) || (code >= 80 && code <= 82) || (code >= 71 && code <= 77) || (code >= 85 && code <= 86)) return 'stormy';
|
||||
if ((code >= 51 && code <= 67) || (code >= 80 && code <= 82)) return 'rain';
|
||||
if ((code >= 71 && code <= 77) || (code >= 85 && code <= 86)) return 'snow';
|
||||
if (code >= 95) return 'stormy';
|
||||
return 'cloudy';
|
||||
}
|
||||
@@ -1497,19 +1528,64 @@ window.weatherThemes = {
|
||||
// Cycles through a list of weather states automatically. Useful
|
||||
// for A/B testing the scene against every theme without
|
||||
// waiting on the open-meteo API.
|
||||
var simWeathers = ['sunny', 'cloudy', 'stormy', 'night'];
|
||||
var SIM_CFG = window.CONFIG || {};
|
||||
var simWeathers = (Array.isArray(SIM_CFG.weatherSimStates) && SIM_CFG.weatherSimStates.length)
|
||||
? SIM_CFG.weatherSimStates.slice()
|
||||
: ['sunny', 'cloudy', 'rain', 'snow', 'stormy', 'night'];
|
||||
var simIndex = 0;
|
||||
var simTimer = null;
|
||||
var __weatherSimActive = false;
|
||||
|
||||
function weatherSimProfileFor(name) {
|
||||
var profiles = SIM_CFG.weatherSimProfile || {};
|
||||
var p = profiles[name] || {};
|
||||
var defaults = {
|
||||
sunny: { code: 0, tempC: 18, humidity: 45, precipMm: 0.0, snowMm: 0.0, windKmh: 8, windDirDeg: 240 },
|
||||
cloudy: { code: 3, tempC: 14, humidity: 70, precipMm: 0.0, snowMm: 0.0, windKmh: 14, windDirDeg: 260 },
|
||||
rain: { code: 61, tempC: 10, humidity: 92, precipMm: 1.2, snowMm: 0.0, windKmh: 22, windDirDeg: 270 },
|
||||
snow: { code: 73, tempC: -2, humidity: 85, precipMm: 0.4, snowMm: 0.8, windKmh: 12, windDirDeg: 300 },
|
||||
stormy: { code: 95, tempC: 16, humidity: 88, precipMm: 2.5, snowMm: 0.0, windKmh: 35, windDirDeg: 250 },
|
||||
night: { code: 0, tempC: 8, humidity: 65, precipMm: 0.0, snowMm: 0.0, windKmh: 6, windDirDeg: 220 }
|
||||
};
|
||||
var d = defaults[name] || defaults.cloudy;
|
||||
return {
|
||||
code: Number(p.code !== undefined ? p.code : d.code),
|
||||
tempC: Number(p.tempC !== undefined ? p.tempC : d.tempC),
|
||||
humidity: Number(p.humidity !== undefined ? p.humidity : d.humidity),
|
||||
precipMm: Number(p.precipMm !== undefined ? p.precipMm : d.precipMm),
|
||||
snowMm: Number(p.snowMm !== undefined ? p.snowMm : d.snowMm),
|
||||
windKmh: Number(p.windKmh !== undefined ? p.windKmh : d.windKmh),
|
||||
windDirDeg: Number(p.windDirDeg !== undefined ? p.windDirDeg : d.windDirDeg)
|
||||
};
|
||||
}
|
||||
|
||||
function applyWeatherSimState(name) {
|
||||
var p = weatherSimProfileFor(name);
|
||||
currentWeatherCode = p.code;
|
||||
window.__currentWeather = {
|
||||
code: p.code,
|
||||
tempC: p.tempC,
|
||||
humidity: p.humidity,
|
||||
precipMm: p.precipMm,
|
||||
snowMm: p.snowMm,
|
||||
windKmh: p.windKmh,
|
||||
windDirDeg: p.windDirDeg
|
||||
};
|
||||
window.__currentWind = {
|
||||
speedKmh: p.windKmh,
|
||||
dirDeg: p.windDirDeg
|
||||
};
|
||||
setWeatherTheme(name);
|
||||
}
|
||||
|
||||
function startWeatherSim(intervalMs) {
|
||||
stopWeatherSim();
|
||||
var step = intervalMs || (window.CONFIG && window.CONFIG.weatherSimInterval) || 30000;
|
||||
simIndex = 0;
|
||||
setWeatherTheme(simWeathers[simIndex]);
|
||||
applyWeatherSimState(simWeathers[simIndex]);
|
||||
simTimer = setInterval(function() {
|
||||
simIndex = (simIndex + 1) % simWeathers.length;
|
||||
setWeatherTheme(simWeathers[simIndex]);
|
||||
applyWeatherSimState(simWeathers[simIndex]);
|
||||
}, step);
|
||||
__weatherSimActive = true;
|
||||
}
|
||||
@@ -2229,6 +2305,33 @@ window.weatherThemes = {
|
||||
var now = sceneNow(); // virtual calendar: follows the same
|
||||
// clock the sky and the clock hands use
|
||||
var current = weatherData.current;
|
||||
if (__weatherSimActive) {
|
||||
var simState = currentWeatherThemeName || simWeathers[simIndex];
|
||||
var simProf = weatherSimProfileFor(simState);
|
||||
current = {
|
||||
temperature_2m: simProf.tempC,
|
||||
relative_humidity_2m: simProf.humidity,
|
||||
weather_code: simProf.code,
|
||||
wind_speed_10m: simProf.windKmh,
|
||||
wind_direction_10m: simProf.windDirDeg,
|
||||
precipitation: simProf.precipMm,
|
||||
snowfall: simProf.snowMm
|
||||
};
|
||||
currentWeatherCode = simProf.code;
|
||||
window.__currentWeather = {
|
||||
code: simProf.code,
|
||||
tempC: simProf.tempC,
|
||||
humidity: simProf.humidity,
|
||||
precipMm: simProf.precipMm,
|
||||
snowMm: simProf.snowMm,
|
||||
windKmh: simProf.windKmh,
|
||||
windDirDeg: simProf.windDirDeg
|
||||
};
|
||||
window.__currentWind = {
|
||||
speedKmh: simProf.windKmh,
|
||||
dirDeg: simProf.windDirDeg
|
||||
};
|
||||
}
|
||||
var hourly = weatherData.hourly;
|
||||
var daily = weatherData.daily;
|
||||
|
||||
@@ -2253,7 +2356,7 @@ window.weatherThemes = {
|
||||
// button has manual control)
|
||||
var curTemp = current.temperature_2m;
|
||||
var curCode = current.weather_code;
|
||||
if (SIM_ACTIVE) {
|
||||
if (SIM_ACTIVE && !__weatherSimActive) {
|
||||
var curIdx = findHourlyIndex(eff, hourly.time);
|
||||
curTemp = hourly.temperature_2m[curIdx];
|
||||
curCode = hourly.weather_code[curIdx];
|
||||
@@ -2285,7 +2388,7 @@ window.weatherThemes = {
|
||||
: Math.round(curTemp) + '\u00b0C';
|
||||
var curWindSpeed = current.wind_speed_10m;
|
||||
var curWindDir = current.wind_direction_10m;
|
||||
if (SIM_ACTIVE && hourly.wind_speed_10m && hourly.wind_direction_10m) {
|
||||
if (SIM_ACTIVE && !__weatherSimActive && hourly.wind_speed_10m && hourly.wind_direction_10m) {
|
||||
var curIdx = findHourlyIndex(eff, hourly.time);
|
||||
curWindSpeed = hourly.wind_speed_10m[curIdx];
|
||||
curWindDir = hourly.wind_direction_10m[curIdx];
|
||||
|
||||
@@ -101,9 +101,22 @@ window.CONFIG = {
|
||||
// false = live Open-Meteo conditions (also used for the theme choice).
|
||||
// true = cycle sunny -> cloudy -> stormy -> night, useful to compare
|
||||
// all weather looks without waiting on the API.
|
||||
weatherSim: true, // test mode: cycles sunny/cloudy/stormy/night
|
||||
weatherSim: true, // test mode: cycles configured weather states
|
||||
weatherSimInterval: 15000, // ms per weather step when weatherSim is true
|
||||
// weatherSim: false, weatherSimInterval: 30000
|
||||
// Synthetic weather states used by weatherSim. Each state sets theme,
|
||||
// Open-Meteo-like weather_code, temperature, humidity, precipitation and wind.
|
||||
weatherSimStates: ['sunny', 'cloudy', 'rain', 'snow', 'stormy', 'night'],
|
||||
weatherSimProfile: {
|
||||
sunny: { code: 0, tempC: 18, humidity: 45, precipMm: 0.0, snowMm: 0.0, windKmh: 8, windDirDeg: 240 },
|
||||
cloudy: { code: 3, tempC: 14, humidity: 70, precipMm: 0.0, snowMm: 0.0, windKmh: 14, windDirDeg: 260 },
|
||||
rain: { code: 61, tempC: 10, humidity: 92, precipMm: 1.2, snowMm: 0.0, windKmh: 22, windDirDeg: 270 },
|
||||
snow: { code: 73, tempC: -2, humidity: 85, precipMm: 0.4, snowMm: 0.8, windKmh: 12, windDirDeg: 300 },
|
||||
stormy: { code: 95, tempC: 16, humidity: 88, precipMm: 2.5, snowMm: 0.0, windKmh: 35, windDirDeg: 250 },
|
||||
night: { code: 0, tempC: 8, humidity: 65, precipMm: 0.0, snowMm: 0.0, windKmh: 6, windDirDeg: 220 }
|
||||
// weatherSimStates: ['sunny', 'rain', 'stormy']
|
||||
// weatherSimProfile: { rain: { code: 80, tempC: 9, precipMm: 2.0, windKmh: 28 } }
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Weather data
|
||||
@@ -183,7 +196,7 @@ window.CONFIG = {
|
||||
// only ever reports sunny/cloudy/stormy, so the deck keeps that
|
||||
// coverage through the night as well - 'night' is used by the weather
|
||||
// simulation (weatherSim: true) alone.
|
||||
density: { sunny: 0.25, cloudy: 0.50, stormy: 0.80 },
|
||||
density: { sunny: 0.25, cloudy: 0.50, rain: 0.75, snow: 0.65, stormy: 0.80 },
|
||||
// 'night' intentionally has no own density: it follows the last
|
||||
// non-night weather density (sunny/cloudy/stormy).
|
||||
// Cloud motion from Open-Meteo wind. Open-Meteo reports wind FROM
|
||||
@@ -197,7 +210,7 @@ window.CONFIG = {
|
||||
// wind: { speedScale: 0 } // static clouds
|
||||
// wind: { speedScale: 140, maxSpeed: 0.12 } // very visible motion
|
||||
}
|
||||
// density: { sunny: 0.05, cloudy: 0.9, stormy: 1.0 }
|
||||
// density: { sunny: 0.05, cloudy: 0.9, rain: 0.95, snow: 0.85, stormy: 1.0 }
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -538,7 +551,7 @@ window.CONFIG = {
|
||||
// time, 1440 = one simulated day per minute. Clock hands, digital readout,
|
||||
// weather and sky all use the same clock. Hash overrides: #at=... #speed=...
|
||||
day: {
|
||||
startAt: '2026-10-12T18:30', // test clock: evening, then accelerated
|
||||
startAt: '2026-01-15T18:30', // test clock: winter evening, then accelerated
|
||||
speed: 1440 // one simulated day per minute
|
||||
// startAt: null, speed: 1 // real time
|
||||
},
|
||||
|
||||
Vendored
+5
-3
@@ -5973,9 +5973,11 @@ function hex(rgb) {
|
||||
var WEATHER_DENSITY = {
|
||||
sunny: 0.25,
|
||||
cloudy: 0.50,
|
||||
// rain and storm both map to 'stormy' (open-meteo codes 51-67, 71-77,
|
||||
// 80-86, 95+). Full 1.0 packed the deck so hard that the march showed
|
||||
// its own layering, so the top end is capped below overcast.
|
||||
rain: 0.75,
|
||||
snow: 0.65,
|
||||
// Thunder/rain/storm codes are split into rain/snow/stormy themes.
|
||||
// Full 1.0 packed the deck so hard that the march showed its own
|
||||
// layering, so the top end is capped below overcast.
|
||||
stormy: 0.80
|
||||
};
|
||||
var LAST_NON_NIGHT_CLOUD_DENSITY = WEATHER_DENSITY.cloudy;
|
||||
|
||||
Reference in new issue
Block a user