Improved scope
Improved profiles
This commit is contained in:
fraxle
2026-05-15 09:40:42 +01:00
parent f024fd0c2d
commit 5b0e62d1b5
6 changed files with 372 additions and 108 deletions
+36 -16
View File
@@ -39,7 +39,7 @@ const html = htm.bind(h);
// • sunR — the sun's drawn radius
// • the stroke colour #c8922a is the brass — change for a different metal
// ═══════════════════════════════════════════════════════════════════
export function SkyScope({ elev, dt, size = 26 }) {
export function SkyScope({ elev, dt, glob = 0, size = 26 }) {
const r = size / 2;
const innerR = r - 1.2;
@@ -60,10 +60,13 @@ export function SkyScope({ elev, dt, size = 26 }) {
const sunY = r - Math.sin((elevClamped * Math.PI) / 180) * (innerR - 2.5);
const sunR = Math.max(2.2, innerR * 0.32);
// Near-horizon sun gets a warm glow halo
const sunGlowOpacity = elev < 10 ? Math.max(0, 1 - elev / 10) * 0.65 : 0.25;
const sunGlowR = sunR + (elev < 6 ? 3.5 : 1.8);
const sunGlowColor = isRising ? '#ff8c3a' : '#ff9a6a';
// Radial glow: strength driven by glob (W/m²). Uses a radialGradient
// so it's intense at the sun centre and fades smoothly to transparent.
const radFrac = Math.min(1, (glob || 0) / 900); // 0 (dark) → 1 (blazing)
const horizFrac = Math.max(0, 1 - elev / 20); // extra warmth near horizon
const glowColor = isRising ? '#ffb040' : '#ffc060';
const glowR = sunR + 4 + radFrac * 6; // total glow radius
const glowPeak = 0.35 + radFrac * 0.45 + horizFrac * 0.15; // centre opacity
const phase = moonPhaseFraction(dt);
const moonR = innerR * 0.55;
@@ -94,6 +97,14 @@ export function SkyScope({ elev, dt, size = 26 }) {
<stop offset="0%" stop-color=${grass.top} />
<stop offset="100%" stop-color=${grass.bot} />
</linearGradient>
<!-- Sun glow — same colour as sun disk, fades from opaque at centre to transparent -->
<radialGradient id=${`glow-${uid}`} gradientUnits="userSpaceOnUse"
cx=${r} cy=${sunY} r=${glowR}>
<stop offset="0%" stop-color="#fff8c0" stop-opacity="1" />
<stop offset=${`${Math.round(sunR / glowR * 100)}%`} stop-color="#fff8c0" stop-opacity="1" />
<stop offset="70%" stop-color="#ffe060" stop-opacity=${glowPeak * 0.5} />
<stop offset="100%" stop-color="#ffcc30" stop-opacity="0" />
</radialGradient>
<!-- Moon phase mask: lit area = white, shadow = black punched out -->
<mask id=${`moon-mask-${uid}`}>
<circle cx=${r} cy=${r} r=${moonR} fill="white" />
@@ -111,10 +122,8 @@ export function SkyScope({ elev, dt, size = 26 }) {
${isDay && html`
<g clip-path=${`url(#${clipId})`}>
<!-- Warm glow halo — bigger and more vivid near the horizon -->
<circle cx=${r} cy=${sunY} r=${sunGlowR} fill=${sunGlowColor} opacity=${sunGlowOpacity} />
<!-- Sun disk -->
<circle cx=${r} cy=${sunY} r=${sunR} fill="#fff8c0" stroke="#e6a32a" stroke-width="0.5" />
<!-- Glow + sun disk as one seamless radial gradient circle -->
<circle cx=${r} cy=${sunY} r=${glowR} fill=${`url(#glow-${uid})`} />
</g>`}
${(isTwil || isNight) && html`
@@ -294,7 +303,7 @@ export function CloudIcon({ category, size = 30, elev = 90, dt = new Date() }) {
// • (value + 10) / 60 maps UTCI -10..50 onto the 270° sweep —
// widen the dial range by changing those numbers
// ═══════════════════════════════════════════════════════════════════
export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date() }) {
export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date(), glob = 0 }) {
// ── Day/night scene behind the readout ─────────────────────────────
// The whole back of the lens is a SkyScope-style scene: sky on top,
// grass on the bottom, sun positioned by elevation (or moon at night
@@ -312,10 +321,13 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date() })
const elevClamped = Math.max(0, Math.min(90, elev)); // clamp to above horizon
const sunY = cy - Math.sin((elevClamped * Math.PI) / 180) * (lensR - 18);
const sunDrawR = 14;
// Near-horizon glow for the big dial
const sunGlowR = sunDrawR + (elev < 10 ? 7 : 3);
const sunGlowOp = elev < 10 ? Math.max(0, 1 - elev / 10) * 0.55 : 0.2;
const sunGlowCol = isRising ? '#ff8c3a' : '#ff9a6a';
// Radial glow for the big dial — sun is always at least faintly glowing
// when above the horizon; scales up with radiation strength.
const radFrac = Math.min(1, (glob || 0) / 900);
const horizFrac = Math.max(0, 1 - elev / 20);
const sunGlowCol = isRising ? '#ffb040' : '#ffc060';
const sunGlowR = sunDrawR + 20 + radFrac * 30; // total glow radius
const sunGlowPeak = 0.30 + radFrac * 0.45 + horizFrac * 0.15; // centre opacity
const moonDrawR = 15;
const moonY = cy - 45;
const phaseOffset = Math.cos(2 * Math.PI * phase) * moonDrawR;
@@ -389,6 +401,14 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date() })
<stop offset="0%" stop-color=${grass.top} />
<stop offset="100%" stop-color=${grass.bot} />
</linearGradient>
<!-- Sun glow — same colour as sun disk, fades from opaque at centre to transparent -->
<radialGradient id="scope-sun-glow" gradientUnits="userSpaceOnUse"
cx=${cx} cy=${sunY} r=${sunGlowR}>
<stop offset="0%" stop-color="#fff8c0" stop-opacity="1" />
<stop offset=${`${Math.round(sunDrawR / sunGlowR * 100)}%`} stop-color="#fff8c0" stop-opacity="1" />
<stop offset="70%" stop-color="#ffe060" stop-opacity=${sunGlowPeak * 0.5} />
<stop offset="100%" stop-color="#ffcc30" stop-opacity="0" />
</radialGradient>
<!-- Moon phase mask: white = lit area, black = shadow punched out -->
<mask id="scope-moon-mask">
<circle cx=${cx} cy=${moonY} r=${moonDrawR} fill="white" />
@@ -403,8 +423,8 @@ export function ScopeReticle({ value, cat, loading, elev = 0, dt = new Date() })
<path d=${`M ${cx - lensR} ${cy} A ${lensR} ${lensR} 0 0 0 ${cx + lensR} ${cy} Z`}
fill="url(#scope-lens-grass)" />
${isDay && html`<${Fragment}>
<circle cx=${cx} cy=${sunY} r=${sunGlowR} fill=${sunGlowCol} opacity=${sunGlowOp} />
<circle cx=${cx} cy=${sunY} r=${sunDrawR} fill="#fff8c0" stroke="#e6a32a" stroke-width="0.8" />
<!-- Glow + sun disk as one seamless radial gradient circle -->
<circle cx=${cx} cy=${sunY} r=${sunGlowR} fill="url(#scope-sun-glow)" />
</>`}
${(isTwil || (!isDay && !isTwil)) && html`<${Fragment}>
<!-- Lit crescent — full moon disk clipped by the phase mask -->