diff --git a/assets/js/app.js b/assets/js/app.js index 1317086..abe4462 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -40,15 +40,22 @@ export function UTCIForecast() { // Each useState() pairs a value with a setter. Calling the setter // re-renders the page with the new value. - // The location we're forecasting for. Change the values below to set - // a different starting location for new visitors. - const [location, setLocation] = useState({ - name: 'Pangbourne, Berkshire', - lat: 51.4839, - lon: -1.0725, - country: 'GB', + // The location we're forecasting for. Restored from localStorage if the + // user has visited before, otherwise defaults to Pangbourne, Berkshire. + const [location, setLocation] = useState(() => { + try { + const saved = localStorage.getItem('sunscope_last_location'); + if (saved) return JSON.parse(saved); + } catch (e) { /* ignore */ } + return { name: 'Pangbourne, Berkshire', lat: 51.4839, lon: -1.0725, country: 'GB' }; }); + // Wrapper that persists the location before updating state. + const setLocationAndSave = (loc) => { + try { localStorage.setItem('sunscope_last_location', JSON.stringify(loc)); } catch (e) { /* ignore */ } + setLocation(loc); + }; + const [forecast, setForecast] = useState(null); // raw Open-Meteo response const [loading, setLoading] = useState(false); // true while fetching const [error, setError] = useState(null); // fetch error message @@ -750,7 +757,7 @@ export function UTCIForecast() { key=${`${r.id}-${r.latitude}`} class="utci-result" onClick=${() => { - setLocation({ + setLocationAndSave({ name: `${r.name}${r.admin1 ? ', ' + r.admin1 : ''}`, lat: r.latitude, lon: r.longitude, diff --git a/assets/js/physics.js b/assets/js/physics.js index 13a1d16..71ca283 100644 --- a/assets/js/physics.js +++ b/assets/js/physics.js @@ -308,6 +308,30 @@ export function calcVehicleInteriorTemp(Ta, globalRad, solElev, vehicleType = 'c return Math.max(Ta, Math.min(Ti, 90)); } +// ── FUTURE FEATURE: Vehicle-at-speed thermal model ──────────────────────────── +// Idea: extend calcVehicleInteriorTemp (or add a companion function) to model +// cabin temperature for a vehicle travelling at speed, not just parked. +// +// Key physics differences from the static model: +// • Forced convection over the shell scales with vehicle speed (v²), so +// hOut rises significantly — shell cools much faster than when parked. +// • Above ~30 mph the vehicle's own forward motion dominates airflow, so +// ambient wind direction becomes largely irrelevant (simplifies the model). +// • Speed classes to model: urban (~20 mph), dual carriageway (~50 mph), +// motorway (~70 mph) — each with a derived hOut multiplier. +// • Windows-open behaviour changes completely at speed: at 70 mph open +// windows create high-velocity through-flow, dramatically cutting cabin +// temp vs. the sealed-car case (but much less pleasant than AC!). +// • Roof and bonnet solar gain stays the same; side-glass gain is unchanged. +// • AC-off vs AC-on would be the primary user toggle alongside speed class. +// +// Suggested signature: +// calcVehicleInteriorTempAtSpeed(Ta, globalRad, solElev, vehicleType, speedMph, windowsOpen) +// +// This would be a useful companion output column (e.g. "Vehicle (moving)") +// for road-trip planning, dog-in-car safety at a rest stop vs. motorway, etc. +// ───────────────────────────────────────────────────────────────────────────── + // Vapour pressure (Magnus → hPa) export function vaporPressureHpa(Ta, RH) { const es = 6.105 * Math.exp((17.27 * Ta) / (237.7 + Ta));