No edit summary |
No edit summary |
||
| Line 33: | Line 33: | ||
style="position:relative;display:block;width:100%;background:transparent;"> | style="position:relative;display:block;width:100%;background:transparent;"> | ||
</div> | </div> | ||
<button id="<!--{$id| | <button id="<!--{$id|default:'wh'|escape:'html'}-->-play" | ||
style="font-size:1rem;padding:.2rem .6rem;cursor:pointer;">▶</button> | |||
</div> | |||
<!-- Date line --> | |||
<div style="margin:.25rem 0 .5rem;"> | |||
<strong>Date:</strong> | |||
<span id="<!--{$id|default:'wh'|escape:'html'}-->-date">Fortnight of Renewal (Dawning), day 1</span> | |||
</div> | |||
<!-- Stage (centered sky, suns layered) --> | |||
<div id="<!--{$id|default:'wh'|escape:'html'}-->-stage" | |||
style="position:relative;width:100%;aspect-ratio:3/2;isolation:isolate;border:1px solid #333;background:#000;overflow:hidden;"> | |||
<img id="<!--{$id|default:'wh'|escape:'html'}-->-sky" | |||
src="<!--{$sky|default:'/images/WyrdeHaven_Sky.png'|escape:'html'}-->" alt="Sky" | |||
decoding="async" draggable="false" | |||
style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;z-index:1;"/> | |||
<img id="<!--{$id|default:'wh'|escape:'html'}-->-sol" | |||
src="<!--{$solara|default:'/wiki/images/f/fe/Solara.png'|escape:'html'}-->" alt="Solara" | |||
decoding="async" draggable="false" | |||
style="position:absolute;left:50%;top:35%;transform:translate(-50%,-50%);width:12%;height:auto;z-index:3;"/> | |||
<img id="<!--{$id|default:'wh'|escape:'html'}-->-vae" | |||
src="<!--{$vaelus|default:'/wiki/images/7/7a/Vaelus.png'|escape:'html'}-->" alt="Vaelus" | |||
decoding="async" draggable="false" | |||
style="position:absolute;left:50%;top:35%;transform:translate(-50%,-50%);width:8%;height:auto;z-index:2;"/> | |||
</div> | |||
<!-- Inclination readouts --> | |||
<div style="margin:.5rem 0 .25rem;"> | |||
<strong>Relative Solar Inclination (Δ):</strong> | |||
<span id="<!--{$id|default:'wh'|escape:'html'}-->-delta">+2.50° (Closing)</span> | |||
</div> | |||
<div> | |||
<strong>Seasonal Equatorial Inclination (barycenter):</strong> | |||
<span id="<!--{$id|default:'wh'|escape:'html'}-->-season">-8.00°</span> | |||
</div> | |||
</div> | |||
<script type="text/javascript"> | |||
(function(){ | |||
var ID = "<!--{$id|default:'wh'|escape:'js'}-->"; | |||
var FPS = parseFloat("<!--{$fps|default:5|escape:'js'}-->") || 5; | |||
var N = 479; | |||
var SEASON_AMP = parseFloat("<!--{$seasonAmp|default:8|escape:'js'}-->"); // degrees | |||
var WOBBLE_TOT = parseFloat("<!--{$wobbleTotal|default:2.5|escape:'js'}-->"); // degrees total | |||
// Split wobble: Solara 40%, Vaelus 60% (1.0° / 1.5° if total=2.5°) | |||
var SOL_WOB = WOBBLE_TOT * 0.40; | |||
var VAE_WOB = WOBBLE_TOT * 0.60; | |||
function ge(s){ return document.getElementById(ID + s); } | |||
var el = { | |||
x: ge("-x"), | |||
play: ge("-play"), | |||
dayc: ge("-daycenter"), | |||
date: ge("-date"), | |||
sol: ge("-sol"), | |||
vae: ge("-vae"), | |||
delta: ge("-delta"), | |||
season: ge("-season"), | |||
stage: ge("-stage") | |||
}; | |||
// Month / calendar helpers | |||
var months = [ | |||
"Primaris","Vernalis","Tharion","Lunarae","Cindrel","Solvane","Auren", | |||
"Veyrath","Rhendol","Tirien","Gairos","Fenmir","Wyrdrun","Cernis","Eirathen" | |||
]; | |||
function dayToCalendar(d){ | |||
// d: 1..479 ; first 7 = FR 8..14 (Dawning), last 7 = FR 1..7 (Fading) | |||
if (d <= 7) { | |||
return "Fortnight of Renewal (Dawning), day " + d; | |||
} else if (d > 472) { | |||
return "Fortnight of Renewal (Fading), day " + (d - 472); | |||
} else { | |||
var dd = d - 7; // shift into 1..465 | |||
var m = Math.floor((dd-1)/31); | |||
var md = ((dd-1)%31) + 1; | |||
return months[m] + ", day " + md; | |||
} | |||
} | |||
function fmtDeg(x){ | |||
var s = (x>=0?"+":"−"); // true minus when negative | |||
var a = Math.abs(x).toFixed(2); | |||
return s + a + "°"; | |||
} | |||
function update(){ | |||
var X = parseInt(el.x.value,10); // 1..479 | |||
var t = (X-1)/N * 2*Math.PI; // phase, cos starts at +1 on day 1 | |||
// Seasonal inclination: lowest at midwinter (day 1), highest at midsummer | |||
var season = -SEASON_AMP * Math.cos(t); | |||
// Relative Δ between suns follows cos(t) with total amplitude WOBBLE_TOT | |||
var delta = WOBBLE_TOT * Math.cos(t); | |||
// Opening / Closing based on derivative sign of |Δ| toward 0 or max | |||
var ddt = -WOBBLE_TOT * Math.sin(t); // derivative of Δ | |||
var opening = (ddt > 0); // increasing toward +max => moving away from 0 | |||
var phaseWord; | |||
// We define "Closing" = moving from max toward 0; "Opening" = from 0 toward max | |||
// Around Δ ~ cos(t): when |Δ| decreasing => Closing; when increasing => Opening | |||
var dAbs = (delta>=0?1:-1)*ddt; // derivative of |Δ| (sign(Δ)*Δ') | |||
phaseWord = (dAbs < 0) ? "Closing" : "Opening"; | |||
// Vertical placements: | |||
// Base center (percent from top). Keep near top third for visibility. | |||
var centerY = 35; // % | |||
// Convert degrees to pixel offset relative to stage height (small scaling for realism) | |||
var H = el.stage.clientHeight || 1; | |||
// 1 visual degree = 0.9% of stage height (tweakable, purely visual) | |||
var pxPerDeg = 0.009 * H; | |||
var solY = centerY - (season + SOL_WOB * Math.cos(t)) * (pxPerDeg*100/H); | |||
var vaeY = centerY - (season - VAE_WOB * Math.cos(t)) * (pxPerDeg*100/H); | |||
el.sol.style.top = solY + "%"; | |||
el.vae.style.top = vaeY + "%"; | |||
// Keep both horizontally centered over the stage (no right offset) | |||
el.sol.style.left = "50%"; | |||
el.vae.style.left = "50%"; | |||
// Readouts | |||
el.dayc.textContent = X + " / " + N; | |||
el.date.textContent = dayToCalendar(X); | |||
el.delta.textContent = fmtDeg(delta) + " (" + phaseWord + ")"; | |||
el.season.textContent = fmtDeg(season); | |||
// Cosine image is already width:100% under the slider and vertically centered. | |||
} | |||
// Scrub with rAF | |||
var raf = null; | |||
el.x.addEventListener("input", function(){ | |||
if(raf) return; | |||
raf = requestAnimationFrame(function(){ raf=null; update(); }); | |||
}); | |||
// Play/stop | |||
var playing=false, timer=null, interval=1000/Math.max(1,FPS); | |||
function step(){ | |||
var v = parseInt(el.x.value,10); | |||
v = (v>=N)?1:(v+1); | |||
el.x.value = v; | |||
update(); | |||
} | |||
el.play.addEventListener("click", function(){ | |||
if(!playing){ | |||
playing=true; | |||
el.play.textContent="■"; | |||
timer=setInterval(step, interval); | |||
} else { | |||
playing=false; | |||
el.play.textContent="▶"; | |||
clearInterval(timer); timer=null; | |||
} | |||
}); | |||
// Initial | |||
update(); | |||
})(); | |||
</script> | |||
</includeonly> | |||
Revision as of 20:08, 11 November 2025
This widget displays WyrdeHaven’s Twin Suns with seasonal wobble and calendar.
Usage
1 / 479
Date:
Fortnight of Renewal (Dawning), day 8 (FR 8)
Relative Solar Inclination (Δ):
+2.50° (Closing)
Seasonal Equatorial Inclination (barycenter):
-8.00°