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),
|
backgroundColor: hexToInt(ASH.void),
|
||||||
speed: 2.5
|
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: {
|
night: {
|
||||||
skyColor: hexToInt(ASH.void),
|
skyColor: hexToInt(ASH.void),
|
||||||
cloudColor: hexToInt(ASH.raised),
|
cloudColor: hexToInt(ASH.raised),
|
||||||
@@ -1444,6 +1458,22 @@ window.weatherThemes = {
|
|||||||
backgroundColor: hexToInt(ASH.panel),
|
backgroundColor: hexToInt(ASH.panel),
|
||||||
speed: 2.5
|
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: {
|
night: {
|
||||||
// Very dark sky, moon-lit clouds
|
// Very dark sky, moon-lit clouds
|
||||||
skyColor: hexToInt(ASH.void),
|
skyColor: hexToInt(ASH.void),
|
||||||
@@ -1458,7 +1488,8 @@ window.weatherThemes = {
|
|||||||
if (code === 0) return 'sunny';
|
if (code === 0) return 'sunny';
|
||||||
if (code >= 1 && code <= 3) return 'cloudy';
|
if (code >= 1 && code <= 3) return 'cloudy';
|
||||||
if (code >= 45 && code <= 48) 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';
|
if (code >= 95) return 'stormy';
|
||||||
return 'cloudy';
|
return 'cloudy';
|
||||||
}
|
}
|
||||||
@@ -1497,19 +1528,64 @@ window.weatherThemes = {
|
|||||||
// Cycles through a list of weather states automatically. Useful
|
// Cycles through a list of weather states automatically. Useful
|
||||||
// for A/B testing the scene against every theme without
|
// for A/B testing the scene against every theme without
|
||||||
// waiting on the open-meteo API.
|
// 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 simIndex = 0;
|
||||||
var simTimer = null;
|
var simTimer = null;
|
||||||
var __weatherSimActive = false;
|
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) {
|
function startWeatherSim(intervalMs) {
|
||||||
stopWeatherSim();
|
stopWeatherSim();
|
||||||
var step = intervalMs || (window.CONFIG && window.CONFIG.weatherSimInterval) || 30000;
|
var step = intervalMs || (window.CONFIG && window.CONFIG.weatherSimInterval) || 30000;
|
||||||
simIndex = 0;
|
simIndex = 0;
|
||||||
setWeatherTheme(simWeathers[simIndex]);
|
applyWeatherSimState(simWeathers[simIndex]);
|
||||||
simTimer = setInterval(function() {
|
simTimer = setInterval(function() {
|
||||||
simIndex = (simIndex + 1) % simWeathers.length;
|
simIndex = (simIndex + 1) % simWeathers.length;
|
||||||
setWeatherTheme(simWeathers[simIndex]);
|
applyWeatherSimState(simWeathers[simIndex]);
|
||||||
}, step);
|
}, step);
|
||||||
__weatherSimActive = true;
|
__weatherSimActive = true;
|
||||||
}
|
}
|
||||||
@@ -2229,6 +2305,33 @@ window.weatherThemes = {
|
|||||||
var now = sceneNow(); // virtual calendar: follows the same
|
var now = sceneNow(); // virtual calendar: follows the same
|
||||||
// clock the sky and the clock hands use
|
// clock the sky and the clock hands use
|
||||||
var current = weatherData.current;
|
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 hourly = weatherData.hourly;
|
||||||
var daily = weatherData.daily;
|
var daily = weatherData.daily;
|
||||||
|
|
||||||
@@ -2253,7 +2356,7 @@ window.weatherThemes = {
|
|||||||
// button has manual control)
|
// button has manual control)
|
||||||
var curTemp = current.temperature_2m;
|
var curTemp = current.temperature_2m;
|
||||||
var curCode = current.weather_code;
|
var curCode = current.weather_code;
|
||||||
if (SIM_ACTIVE) {
|
if (SIM_ACTIVE && !__weatherSimActive) {
|
||||||
var curIdx = findHourlyIndex(eff, hourly.time);
|
var curIdx = findHourlyIndex(eff, hourly.time);
|
||||||
curTemp = hourly.temperature_2m[curIdx];
|
curTemp = hourly.temperature_2m[curIdx];
|
||||||
curCode = hourly.weather_code[curIdx];
|
curCode = hourly.weather_code[curIdx];
|
||||||
@@ -2285,7 +2388,7 @@ window.weatherThemes = {
|
|||||||
: Math.round(curTemp) + '\u00b0C';
|
: Math.round(curTemp) + '\u00b0C';
|
||||||
var curWindSpeed = current.wind_speed_10m;
|
var curWindSpeed = current.wind_speed_10m;
|
||||||
var curWindDir = current.wind_direction_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);
|
var curIdx = findHourlyIndex(eff, hourly.time);
|
||||||
curWindSpeed = hourly.wind_speed_10m[curIdx];
|
curWindSpeed = hourly.wind_speed_10m[curIdx];
|
||||||
curWindDir = hourly.wind_direction_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).
|
// false = live Open-Meteo conditions (also used for the theme choice).
|
||||||
// true = cycle sunny -> cloudy -> stormy -> night, useful to compare
|
// true = cycle sunny -> cloudy -> stormy -> night, useful to compare
|
||||||
// all weather looks without waiting on the API.
|
// 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
|
weatherSimInterval: 15000, // ms per weather step when weatherSim is true
|
||||||
// weatherSim: false, weatherSimInterval: 30000
|
// 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
|
// Weather data
|
||||||
@@ -183,7 +196,7 @@ window.CONFIG = {
|
|||||||
// only ever reports sunny/cloudy/stormy, so the deck keeps that
|
// only ever reports sunny/cloudy/stormy, so the deck keeps that
|
||||||
// coverage through the night as well - 'night' is used by the weather
|
// coverage through the night as well - 'night' is used by the weather
|
||||||
// simulation (weatherSim: true) alone.
|
// 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
|
// 'night' intentionally has no own density: it follows the last
|
||||||
// non-night weather density (sunny/cloudy/stormy).
|
// non-night weather density (sunny/cloudy/stormy).
|
||||||
// Cloud motion from Open-Meteo wind. Open-Meteo reports wind FROM
|
// Cloud motion from Open-Meteo wind. Open-Meteo reports wind FROM
|
||||||
@@ -197,7 +210,7 @@ window.CONFIG = {
|
|||||||
// wind: { speedScale: 0 } // static clouds
|
// wind: { speedScale: 0 } // static clouds
|
||||||
// wind: { speedScale: 140, maxSpeed: 0.12 } // very visible motion
|
// 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,
|
// time, 1440 = one simulated day per minute. Clock hands, digital readout,
|
||||||
// weather and sky all use the same clock. Hash overrides: #at=... #speed=...
|
// weather and sky all use the same clock. Hash overrides: #at=... #speed=...
|
||||||
day: {
|
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
|
speed: 1440 // one simulated day per minute
|
||||||
// startAt: null, speed: 1 // real time
|
// startAt: null, speed: 1 // real time
|
||||||
},
|
},
|
||||||
|
|||||||
Vendored
+5
-3
@@ -5973,9 +5973,11 @@ function hex(rgb) {
|
|||||||
var WEATHER_DENSITY = {
|
var WEATHER_DENSITY = {
|
||||||
sunny: 0.25,
|
sunny: 0.25,
|
||||||
cloudy: 0.50,
|
cloudy: 0.50,
|
||||||
// rain and storm both map to 'stormy' (open-meteo codes 51-67, 71-77,
|
rain: 0.75,
|
||||||
// 80-86, 95+). Full 1.0 packed the deck so hard that the march showed
|
snow: 0.65,
|
||||||
// its own layering, so the top end is capped below overcast.
|
// 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
|
stormy: 0.80
|
||||||
};
|
};
|
||||||
var LAST_NON_NIGHT_CLOUD_DENSITY = WEATHER_DENSITY.cloudy;
|
var LAST_NON_NIGHT_CLOUD_DENSITY = WEATHER_DENSITY.cloudy;
|
||||||
|
|||||||
Reference in new issue
Block a user