Widget:TwinSuns: Difference between revisions

From WyrdeWiki
(Created page with "<noinclude>__NOTOC__ This widget displays WyrdeHaven’s Twin Suns with seasonal wobble and calendar. =Usage= {{#widget:TwinSuns | id=wh | size=512 | fps=5 | solara=https://www.wyrdehavenchronicl.es/wiki/images/f/fe/Solara.png | vaelus=https://www.wyrdehavenchronicl.es/wiki/images/7/7a/Vaelus.png | backdrop=http://wyrdehavenchronicl.es/images/WyrdeHaven_Sky.png | cosine=http://wyrdehavenchronicl.es/images/Cosinus.png }} {| class="wikitable" |- ! Param !! Meaning...")
 
No edit summary
Line 4: Line 4:
=Usage=
=Usage=
{{#widget:TwinSuns
{{#widget:TwinSuns
  | id=wh
  | id=ts1
  | size=512
  | size=768
  | fps=5
  | fps=5
  | solara=https://www.wyrdehavenchronicl.es/wiki/images/f/fe/Solara.png
| seasonAmp=8        <!-- seasonal equatorial inclination amplitude (deg) -->
  | vaelus=https://www.wyrdehavenchronicl.es/wiki/images/7/7a/Vaelus.png
| wobbleTotal=2.5    <!-- total relative wobble between suns (deg); split 40/60 -->
  | backdrop=http://wyrdehavenchronicl.es/images/WyrdeHaven_Sky.png
  | solara=/wiki/images/f/fe/Solara.png
  | cosine=http://wyrdehavenchronicl.es/images/Cosinus.png
  | vaelus=/wiki/images/7/7a/Vaelus.png
  | sky=/images/WyrdeHaven_Sky.png
  | cosine=/images/Cosinus.png
}}
}}
{| class="wikitable"
|-
! Param !! Meaning !! Default
|-
| id || Unique id prefix || wh
|-
| size || Stage width/height in px || 512
|-
| fps || Animation fps || 5
|-
| solara || Solara PNG (transparent) || (URL above)
|-
| vaelus || Vaelus PNG (transparent) || (URL above)
|-
| backdrop || Sky backdrop image || (URL above)
|-
| cosine || Cosinus trace PNG (transparent) || (URL above)
|}
</noinclude><includeonly>
</noinclude><includeonly>
<div class="wh-twinsuns" style="max-width:<!--{$size|default:512|escape:'html'}-->px;margin:1rem 0;">
<div class="wh-twinsuns" style="max-width:<!--{$size|default:768|escape:'html'}-->px;margin:1rem 0;">
   <!-- Day number centered over slider -->
   <!-- Top line with centered day readout -->
   <div style="display:flex;justify-content:center;font-weight:600;margin-bottom:.25rem;">
   <div style="display:flex;align-items:center;gap:.5rem;">
     <span id="<!--{$id|default:'wh'|escape:'html'}-->-daynum">1</span> / 479
    <div style="flex:1;height:0.1rem;"></div>
     <div id="<!--{$id|default:'wh'|escape:'html'}-->-daycenter"
        style="font-weight:600;">1 / 479</div>
    <div style="flex:1;height:0.1rem;"></div>
   </div>
   </div>


   <!-- Slider with cosine behind -->
   <!-- Slider + cosine (cosine exactly the slider width, aligned) -->
   <div style="position:relative;display:flex;align-items:center;gap:.5rem;margin-bottom:.25rem;">
   <div style="position:relative;display:flex;align-items:center;gap:.5rem;margin:.25rem 0 .5rem;">
     <div style="position:relative;flex:1;">
     <div style="position:relative;flex:1;">
       <img id="<!--{$id|default:'wh'|escape:'html'}-->-cos"
       <img src="<!--{$cosine|default:'/images/Cosinus.png'|escape:'html'}-->"
          src="<!--{$cosine|default:'http://wyrdehavenchronicl.es/images/Cosinus.png'|escape:'html'}-->"
           alt="cosine" decoding="async" draggable="false"
           alt="Cosinus"
           style="position:absolute;left:0;top:50%;transform:translateY(-50%);width:100%;height:auto;pointer-events:none;opacity:.65;"/>
          decoding="async" fetchpriority="low"
           style="position:absolute;inset:0;object-fit:contain;pointer-events:none;"/>
       <input id="<!--{$id|default:'wh'|escape:'html'}-->-x" type="range" min="1" max="479" value="1"
       <input id="<!--{$id|default:'wh'|escape:'html'}-->-x" type="range" min="1" max="479" value="1"
             style="position:relative;width:100%;background:transparent;">
             style="position:relative;display:block;width:100%;background:transparent;">
    </div>
    <button id="<!--{$id|default:'wh'|escape:'html'}-->-play"
            style="font-size:1rem;padding:.2rem .5rem;cursor:pointer;line-height:1;">▶</button>
  </div>
 
  <!-- Date text -->
  <div style="margin:.25rem 0;">
    <strong>Date:</strong>
    <span id="<!--{$id|default:'wh'|escape:'html'}-->-date">Fortnight of Renewal (Dawning), day 8</span>
  </div>
 
  <!-- Stage -->
  <div id="<!--{$id|default:'wh'|escape:'html'}-->-stage"
      style="position:relative;width:<!--{$size|default:512|escape:'html'}-->px;height:<!--{$size|default:512|escape:'html'}-->px;isolation:isolate;border:1px solid #333;overflow:hidden;background:#9cccf6;">
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-bg"
        src="<!--{$backdrop|default:'http://wyrdehavenchronicl.es/images/WyrdeHaven_Sky.png'|escape:'html'}-->"
        alt="Backdrop"
        decoding="async" fetchpriority="high" draggable="false"
        style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1;"/>
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-solara"
        src="<!--{$solara|default:'https://www.wyrdehavenchronicl.es/wiki/images/f/fe/Solara.png'|escape:'html'}-->"
        alt="Solara"
        style="position:absolute;transform:translate(-50%,-50%);z-index:3;width:24%;max-width:180px;image-rendering:auto;"/>
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-vaelus"
        src="<!--{$vaelus|default:'https://www.wyrdehavenchronicl.es/wiki/images/7/7a/Vaelus.png'|escape:'html'}-->"
        alt="Vaelus"
        style="position:absolute;transform:translate(-50%,-50%);z-index:2;width:18%;max-width:140px;image-rendering:auto;"/>
  </div>
 
  <!-- Inclination info -->
  <div style="margin-top:.5rem;line-height:1.4;">
    <div><strong>Relative Solar Inclination (Δ):</strong>
      <span id="<!--{$id|default:'wh'|escape:'html'}-->-rel">+2.50°</span>
      (<span id="<!--{$id|default:'wh'|escape:'html'}-->-state">Closing</span>)
    </div>
    <div><strong>Seasonal Equatorial Inclination (barycenter):</strong>
      <span id="<!--{$id|default:'wh'|escape:'html'}-->-bar">-2.50°</span>
     </div>
     </div>
  </div>
    <button id="<!--{$id|de
</div>
 
<script type="text/javascript">
(function(){
  var ID = "<!--{$id|default:'wh'|escape:'js'}-->";
  function ge(s){ return document.getElementById(ID + s); }
  var el = {
    x:  ge("-x"),
    day: ge("-daynum"),
    date:ge("-date"),
    cos: ge("-cos"),
    play:ge("-play"),
    stage:ge("-stage"),
    s:  ge("-solara"),
    v:  ge("-vaelus"),
    rel: ge("-rel"),
    bar: ge("-bar"),
    st:  ge("-state")
  };
 
  // sizing
  var SIZE = <!--{$size|default:512|escape:'js'}-->;
  // animation
  var FPS = <!--{$fps|default:5|escape:'js'}-->;
  var interval = 1000 / Math.max(1, FPS);
  var timer = null, playing = false;
 
  // months (15×31), Fortnight mapping per spec
  var months = [
    "Primaris","Vernalis","Tharion","Lunarae","Cindrel","Solvane","Auren","Veyrath",
    "Rhendol","Tirien","Gairos","Fenmir","Wyrdrun","Cernis","Eirathen"
  ];
 
  function dateText(D){
    // D: 1..479
    if(D <= 7){
      return "Fortnight of Renewal (Dawning), day " + (D + 7);
    }
    if(D >= 473){
      return "Fortnight of Renewal (Fading), day " + (D - 472);
    }
    var idx = D - 7; // 1-based inside the 465-day span
    var mIx = Math.ceil(idx / 31) - 1; // 0..14
    var dIn = ((idx - 1) % 31) + 1;    // 1..31
    return months[mIx] + " " + dIn;
  }
 
  // inclination model
  // Day 1 => +2.5° (max), midsummer => -2.5°.
  var TWO_PI = Math.PI * 2;
  function relIncl(D){ // degrees
    return 2.5 * Math.cos(TWO_PI * ( (D-1) / 479 ));
  }
  function barIncl(D){ // inverted sign (lowest at midwinter when rel=+2.5)
    return -relIncl(D);
  }
  function openingOrClosing(D){
    var cur = Math.abs(relIncl(D));
    var nxt = Math.abs(relIncl(D === 479 ? 1 : D+1));
    return (nxt < cur) ? "Closing" : "Opening";
  }
 
  // stage placement
  // Base anchor for the pair (roughly upper right sky)
  var anchor = {
    x: Math.round(SIZE * 0.68),
    y: Math.round(SIZE * 0.22)
  };
  // Horizontal separation cue (~constant small separation to suggest 2.5°)
  var sepX = Math.round(SIZE * 0.10); // tweakable; ~10% width
  // Vertical wobble scale (px per degree), makes Δ±2.5° visible but subtle
  var pxPerDeg = Math.max(6, Math.round(SIZE * 0.03 / 2.5)); // scales with size
 
  function placeSuns(D){
    var rel = relIncl(D); // ±2.5°
    // split the relative Δ: Solara +Δ/2, Vaelus -Δ/2
    var dY = (rel * pxPerDeg) / 2;
 
    var sX = anchor.x - Math.round(sepX/2);
    var vX = anchor.x + Math.round(sepX/2);
    var sY = anchor.y - Math.round(dY);
    var vY = anchor.y + Math.round(dY);
 
    el.s.style.left = sX + "px";
    el.s.style.top  = sY + "px";
    el.v.style.left = vX + "px";
    el.v.style.top  = vY + "px";
  }
 
  function fmtDeg(x){
    var sign = (x >= 0) ? "+" : "−";
    return sign + Math.abs(x).toFixed(2) + "°";
  }
 
  function update(){
    var D = parseInt(el.x.value,10) || 1;
    el.day.textContent = D;
    el.date.textContent = dateText(D);
 
    var r = relIncl(D);
    var b = barIncl(D);
    el.rel.textContent = fmtDeg(r);
    el.bar.textContent = fmtDeg(b);
    el.st.textContent  = openingOrClosing(D);
 
    placeSuns(D);
  }
 
  // Slider input throttled by rAF
  var raf = null;
  el.x.addEventListener("input", function(){
    if(raf) return;
    raf = requestAnimationFrame(function(){ raf=null; update(); });
  });
 
  function step(){
    var v = parseInt(el.x.value,10) || 1;
    v = (v >= 479) ? 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 paint
  update();
})();
</script>
</includeonly>

Revision as of 20:06, 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)
Sky Solara Vaelus
Relative Solar Inclination (Δ): +2.50° (Closing)
Seasonal Equatorial Inclination (barycenter): -8.00°