No edit summary |
No edit summary |
||
| (7 intermediate revisions by the same user not shown) | |||
| Line 7: | Line 7: | ||
| size=768 | | size=768 | ||
| fps=5 | | fps=5 | ||
| wobble= | | wobble=5 | ||
| equator=8 | | equator=8 | ||
| sep=2.5 | | sep=2.5 | ||
| degpx= | | degpx=10 | ||
| solara=https://www.wyrdehavenchronicl.es/wiki/images/f/fe/Solara.png | | solara=https://www.wyrdehavenchronicl.es/wiki/images/f/fe/Solara.png | ||
| vaelus=https://www.wyrdehavenchronicl.es/wiki/images/7/7a/Vaelus.png | | vaelus=https://www.wyrdehavenchronicl.es/wiki/images/7/7a/Vaelus.png | ||
| Line 84: | Line 84: | ||
var ID = "<!--{$id|default:'ts'|escape:'js'}-->"; | var ID = "<!--{$id|default:'ts'|escape:'js'}-->"; | ||
var FPS = parseFloat("<!--{$fps|default:5|escape:'js'}-->") || 5; | var FPS = parseFloat("<!--{$fps|default:5|escape:'js'}-->") || 5; | ||
var WOBBLE = parseFloat("<!--{$wobble|default:2.5|escape:'js'}-->") || 2.5; | var WOBBLE = parseFloat("<!--{$wobble|default:2.5|escape:'js'}-->") || 2.5; // observable Δ (deg) | ||
var EQUATOR = parseFloat("<!--{$equator|default:8|escape:'js'}-->") || 8; | var EQUATOR = parseFloat("<!--{$equator|default:8|escape:'js'}-->") || 8; // seasonal max (deg) | ||
var SEP = parseFloat("<!--{$sep|default:2.5|escape:'js'}-->") || 2.5; | var SEP = parseFloat("<!--{$sep|default:2.5|escape:'js'}-->") || 2.5; // horizontal sep (deg) | ||
var DEGPX = parseFloat("<!--{$degpx|default:10|escape:'js'}-->") || 10; | var DEGPX = parseFloat("<!--{$degpx|default:10|escape:'js'}-->") || 10; // px per degree | ||
function | // Find and init exactly one instance in a given DOM scope | ||
function initIn(root){ | |||
var wrap = root.querySelector('.wh-twins'); | |||
if(!wrap) return; | |||
function ge(s){ return document.getElementById(ID + s); } | |||
var el = { | var el = { | ||
day: ge("-daylabel"), | day: ge("-daylabel"), | ||
| Line 113: | Line 107: | ||
eq: ge("-eqinc") | eq: ge("-eqinc") | ||
}; | }; | ||
for (var k in el){ if(!el[k]) return; } // quietly bail if something’s missing | |||
var TAU = Math.PI*2; | |||
function cosPhase(d){ return Math.cos(TAU*((d-1)/479)); } | |||
function fmtDeg(x){ var s=(x>=0?"+":""); return s + x.toFixed(2) + "°"; } | |||
var TAU = Math.PI * 2; | function openingClosing(_, phase){ | ||
function cosPhase(d){ return Math.cos(TAU * ((d-1)/479)); } | var s = Math.sin(TAU*phase); | ||
function fmtDeg(x){ var s = (x>=0?"+":""); return s + x.toFixed(2) + "°"; } | return (-s>0) ? "Closing" : "Opening"; | ||
function openingClosing( | |||
var s = Math.sin(TAU * phase); | |||
return (-s > 0) ? "Closing" : "Opening"; | |||
} | } | ||
var months = ["Primaris","Vernalis","Tharion","Lunarae","Cindrel","Solvane","Auren","Veyrath","Rhendol","Tirien","Gairos","Fenmir","Wyrdrun","Cernis","Eirathen"]; | var months = ["Primaris","Vernalis","Tharion","Lunarae","Cindrel","Solvane","Auren","Veyrath","Rhendol","Tirien","Gairos","Fenmir","Wyrdrun","Cernis","Eirathen"]; | ||
function dateText(d){ | function dateText(d){ | ||
if(d <= 7) | if(d<=7) return "Fortnight of Renewal (Dawning), day " + (d+7) + " (FR " + (d+7) + ")"; | ||
if(d >= 473){var k=d-472; return "Fortnight of Renewal (Fading), day " + k + " (FR " + k + ")";} | if(d>=473){var k=d-472; return "Fortnight of Renewal (Fading), day " + k + " (FR " + k + ")";} | ||
var n = d - 7, m = Math.ceil(n/31), day = ((n-1)%31)+1; | var n=d-7, m=Math.ceil(n/31), day=((n-1)%31)+1; return day + " " + months[m-1]; | ||
} | } | ||
var SOL_SHARE = 1.0, VAE_SHARE = 1.5, SUM = SOL_SHARE + VAE_SHARE; | var SOL_SHARE=1.0, VAE_SHARE=1.5, SUM=SOL_SHARE+VAE_SHARE; | ||
function setStarSizes(){ | function setStarSizes(){ | ||
var w = el.stage.clientWidth || el.stage.getBoundingClientRect().width || 0; | var w = el.stage.clientWidth || el.stage.getBoundingClientRect().width || 0; | ||
if(!w) | if(!w) return; | ||
var base = Math.round(w * 0. | var base = Math.round(w*0.08); | ||
el.s.width = el.s.height = base; | el.s.width = el.s.height = base; | ||
el.v.width = el.v.height = Math.round(base * 0. | el.v.width = el.v.height = Math.round(base*0.8); | ||
} | } | ||
| Line 148: | Line 139: | ||
var phase = (d-1)/479; | var phase = (d-1)/479; | ||
var delta = WOBBLE * cosPhase(d); | // Your “observable” Δ already in sky-arc degrees | ||
var eq = -EQUATOR * cosPhase(d); | var delta = (WOBBLE * cosPhase(d)) / 8; // ±WOBBLE | ||
var eq = -EQUATOR * cosPhase(d); // lowest at midwinter | |||
el.day.textContent = d + " / 479"; | el.day.textContent = d + " / 479"; | ||
| Line 157: | Line 149: | ||
var w = el.stage.clientWidth, h = el.stage.clientHeight; | var w = el.stage.clientWidth, h = el.stage.clientHeight; | ||
if(!w || !h) | if(!w||!h) return; | ||
var cx = w * 0.5, cy = h * 0.33; | var cx = w*0.5, cy = h*0.33; | ||
var dx = (SEP/2) * DEGPX; | var dx = (SEP/2)*DEGPX; | ||
var solOff = (delta * (SOL_SHARE/SUM)) * DEGPX; | var solOff = (delta*(SOL_SHARE/SUM))*DEGPX; | ||
var vaeOff = -(delta * (VAE_SHARE/SUM)) * DEGPX; | var vaeOff = -(delta*(VAE_SHARE/SUM))*DEGPX; | ||
var yBase = cy - (eq * DEGPX); | var yBase = cy - (eq*DEGPX); | ||
el.s.style.left = (cx - dx) + "px"; | el.s.style.left = (cx - dx) + "px"; | ||
| Line 170: | Line 162: | ||
el.s.style.top = (yBase - solOff) + "px"; | el.s.style.top = (yBase - solOff) + "px"; | ||
el.v.style.top = (yBase - vaeOff) + "px"; | el.v.style.top = (yBase - vaeOff) + "px"; | ||
}catch(e){ | }catch(e){} | ||
} | } | ||
function ensureSizedThen(fn){ | function ensureSizedThen(fn){ | ||
setStarSizes(); | setStarSizes(); | ||
if(el.stage.clientWidth) | if(el.stage.clientWidth) fn(); | ||
else | else setTimeout(function(){ ensureSizedThen(fn); }, 50); | ||
} | } | ||
var timer=null, playing=false, interval = 1000/Math.max(1,FPS); | var timer=null, playing=false, interval=1000/Math.max(1,FPS); | ||
function step(){ var v = parseInt(el.rng.value,10)||1; el.rng.value = (v>=479)?1:(v+1); update(); } | function step(){ var v=parseInt(el.rng.value,10)||1; el.rng.value=(v>=479)?1:(v+1); update(); } | ||
el.rng.addEventListener("input", update); | el.rng.addEventListener("input", update); | ||
| Line 188: | Line 179: | ||
else { playing=false; el.play.textContent="▶"; clearInterval(timer); timer=null; } | else { playing=false; el.play.textContent="▶"; clearInterval(timer); timer=null; } | ||
}); | }); | ||
window.addEventListener("resize", function(){ setStarSizes(); update(); }); | |||
ensureSizedThen(update); | |||
} | |||
// Run on normal load | |||
if (document.readyState === "complete" || document.readyState === "interactive"){ | |||
initIn(document); | |||
} else { | |||
document.addEventListener("DOMContentLoaded", function(){ initIn(document); }, {once:true}); | |||
} | |||
// Also run when MediaWiki injects content (tabs, previews, etc.) | |||
} | if (window.mw && mw.hook) { | ||
mw.hook('wikipage.content').add(function($c){ | |||
initIn($c && $c[0] ? $c[0] : document); | |||
}); | |||
} | |||
})(); | })(); | ||
</script> | </script> | ||
</includeonly> | </includeonly> | ||
Latest revision as of 21:50, 11 November 2025
This widget shows WyrdeHaven’s twin suns with seasonal wobble & 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°
| param | meaning | default |
|---|---|---|
| size | max stage width (px) | 768 |
| fps | play speed (frames/s) | 5 |
| wobble | solar relative wobble amplitude (Δ, degrees) | 2.5 |
| equator | seasonal/barycenter max tilt (degrees) | 8 |
| sep | visible horizontal separation between suns (degrees) | 2.5 |
| degpx | vertical degree→pixel scale (px per degree) | 10 |