Widget:TwinSuns: Difference between revisions

From WyrdeWiki
No edit summary
No edit summary
 
(One intermediate revision by the same user not shown)
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 ge(s){return document.getElementById(ID + s);}
  // Find and init exactly one instance in a given DOM scope
   function initIn(root){
    var wrap = root.querySelector('.wh-twins');
    if(!wrap) return;


  // Safe init (works even if the widget is placed inside tabs/collapsibles)
    function ge(s){ return document.getElementById(ID + s); }
  function ready(fn){
    if(document.readyState === "complete" || document.readyState === "interactive"){
      setTimeout(fn,0);
    } else {
      document.addEventListener("DOMContentLoaded", fn, {once:true});
    }
  }
 
  ready(function init(){
     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


    // If something failed to render, don't throw—just stop quietly
     var TAU = Math.PI*2;
    for (var k in el){ if(!el[k]) return; }
     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(delta, phase){
       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)       return "Fortnight of Renewal (Dawning), day " + (d+7) + " (FR " + (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];
      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){ return; } // wait for layout
       if(!w) return;
       var base = Math.round(w * 0.08);
       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.8);
       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)) / 8;
        // 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){ return; }
         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){ /* swallow to avoid killing other widgets */ }
       }catch(e){}
     }
     }


    // If the stage hasn't sized yet (e.g., inside tabs), retry until it has
     function ensureSizedThen(fn){
     function ensureSizedThen(fn){
       setStarSizes();
       setStarSizes();
       if(el.stage.clientWidth){ fn(); }
       if(el.stage.clientWidth) fn();
       else { setTimeout(function(){ ensureSizedThen(fn); }, 50); }
       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(); });


     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});
  }


     ensureSizedThen(function(){ update(); });
  // 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)
Sky Solara Vaelus
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