Widget:MoonStack: Difference between revisions

From WyrdeWiki
No edit summary
 
(12 intermediate revisions by the same user not shown)
Line 1: Line 1:
<noinclude>__NOTOC__
<noinclude>__NOTOC__
This widget allows you to embed the lunar orbits of WyrdeHaven in your mediaWiki page
This widget allows you to embed the lunar orbits of WyrdeHaven in your mediaWiki page
==Copy to your site==
To use this widget on your site, install [https://www.mediawiki.org/wiki/Extension:Widgets MediaWiki Widgets extension] and copy the [{{fullurl:{{FULLPAGENAME}}|action=edit}} full source code] of this page to your wiki as page '''{{FULLPAGENAME}}'''.


=Usage=
=Usage=
&lcub;&lcub;#widget:MoonStack &#124; basePath=/images/moons/ &#124; size=512&rcub;&rcub;
&lcub;&lcub;#widget:MoonStack &#124; basePath=/images/moons/ &#124; size=512 &#124; id=ms1&rcub;&rcub;


{|
{|
|-
|-
| ''basePath'' || &nbsp; || Location of image files for the orbits || &nbsp; || /
| ''basePath'' || &nbsp; || Location of image files for the orbits || &nbsp; || /images/moons/
|-
|-
| ''size'' || &nbsp; || maximum image size in pixels || &nbsp; || 512
| ''size'' || &nbsp; || maximum image size in pixels || &nbsp; || 512
|-
| ''id'' || &nbsp; || unique id prefix if you embed multiple widgets on one page || &nbsp; || wh
|-
| ''fps'' || &nbsp; || Desired fps for the animation || &nbsp; || 5
|}
|}
</noinclude><includeonly><widget xmlns="http://www.w3.org/1999/xhtml">
</noinclude><includeonly>
 
<div class="wh-moonstack" style="max-width:<!--{$size|default:512|escape:'html'}-->px;margin:1rem 0;">
  <parameters>
  <label for="<!--{$id|default:'wh'|escape:'html'}-->-x"><strong>Days since alignment:</strong>
    <!-- Base path where the PNGs are stored -->
  <span id="<!--{$id|default:'wh'|escape:'html'}-->-xval">1</span> / 6433
    <parameter name="basePath" default="/images/moons/"/>
  </label>
    <!-- Optional width for the visualization -->
    <parameter name="size" default="512"/>
  </parameters>
 
  <content><![CDATA[
    <div class="wh-moonstack" style="max-width:{size}px;margin:1rem 0;">
     
      <label for="wh-x">
        <strong>Alignment step:</strong>
        <span id="wh-xval">1</span> / 6433
      </label>
      <input id="wh-x" type="range" min="1" max="6433" value="1"
            style="width:100%;">
 
      <div style="margin:.5rem 0;">
        <strong>When:</strong>
        <span id="wh-cycles">0</span> Cycles,
        <span id="wh-days">1</span> days
      </div>
 
      <div id="wh-stage"
        style="
          position:relative;
          width:{size}px;
          height:{size}px;
          isolation:isolate;
          border:1px solid #333;
          background:#000;
        ">
       
        <img id="wh-base"
          src="{basePath}WyrdeHaven_center.png"
          alt="WyrdeHaven base"
          style="position:absolute;inset:0;object-fit:contain;z-index:1;"/>


        <img id="wh-tiriel"
  <div style="display:flex;align-items:center;gap:0.5rem;">
          src=""
    <input id="<!--{$id|default:'wh'|escape:'html'}-->-x" type="range" min="1" max="6433" value="1" style="flex-grow:1;">
          alt="Tiriel"
    <button id="<!--{$id|default:'wh'|escape:'html'}-->-play" style="font-size:1rem;padding:0.2rem 0.5rem;cursor:pointer;">▶</button>
          style="position:absolute;inset:0;object-fit:contain;z-index:2;"/>
  </div>


        <img id="wh-rhaen"
  <div style="margin:.5rem 0;">
          src=""
    <strong>When:</strong>
          alt="Rhaen"
    <span id="<!--{$id|default:'wh'|escape:'html'}-->-cycles">0</span> Cycles,
          style="position:absolute;inset:0;object-fit:contain;z-index:3;"/>
    <span id="<!--{$id|default:'wh'|escape:'html'}-->-days">1</span> days
  </div>


        <img id="wh-veyra"
  <div id="<!--{$id|default:'wh'|escape:'html'}-->-stage"
          src=""
      style="position:relative;width:<!--{$size|default:512|escape:'html'}-->px;height:<!--{$size|default:512|escape:'html'}-->px;isolation:isolate;background:#000;border:1px solid #333;">
          alt="Veyra"
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-base"
          style="position:absolute;inset:0;object-fit:contain;z-index:4;"/>
        src="<!--{$basePath|default:'/images/moons/'|escape:'html'}-->WyrdeHaven_center.png?v=2" width="{size}" height="{size}"
      </div>
        alt="WyrdeHaven base"
        decoding="async" fetchpriority="high" draggable="false"
        style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;"/>
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-tiriel" src="" alt="Tiriel" width="{size}" height="{size}"
        style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:2;"/>
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-rhaen"  src="" alt="Rhaen" width="{size}" height="{size}"
        style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:3;"/>
    <img id="<!--{$id|default:'wh'|escape:'html'}-->-veyra"  src="" alt="Veyra" width="{size}" height="{size}"
        style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:4;"/>
  </div>
</div>
<script type="text/javascript">
(function() {
  var ID  = "<!--{$id|default:'wh'|escape:'js'}-->";
  var BASE = "<!--{$basePath|default:'/images/moons/'|escape:'js'}-->";
  function ge(s){return document.getElementById(ID + s);}
  var el = {
    x:    ge("-x"),
    xval: ge("-xval"),
    cyc:  ge("-cycles"),
    day:  ge("-days"),
    t:    ge("-tiriel"),
    r:    ge("-rhaen"),
    v:    ge("-veyra")
  };


    </div>
  function pad2(n){return ("0"+n).slice(-2);}


    <script type="text/javascript">
  // --- NEW: simple preloader & caches ---
      (function() {
  var cache = { T: [], R: [], V: [] };
        const BASE = "{basePath}";
        const SIZE = {size};


        const el = {
  function preloadSet(prefix, count, bucket){
          x:      document.getElementById("wh-x"),
    for(var i=0;i<count;i++){
          xval:  document.getElementById("wh-xval"),
      var img = new Image();
          cyc:    document.getElementById("wh-cycles"),
      img.decoding = "async";
          days:   document.getElementById("wh-days"),
      img.referrerPolicy = "no-referrer";
          tiriel: document.getElementById("wh-tiriel"),
      img.draggable = false;
          rhaen: document.getElementById("wh-rhaen"),
      img.src = BASE + prefix + "_" + pad2(i) + ".png";
          veyra: document.getElementById("wh-veyra")
      bucket[i] = img;
        };
    }
  }
  // Kick off preloads (non-blocking)
   preloadSet("Tiriel", 12, cache.T);
  preloadSet("Rhaen",  32, cache.R);
  preloadSet("Veyra",  67, cache.V);


        function pad2(n) {
  // Track last indices to avoid redundant src swaps while scrubbing
          return ("0" + n).slice(-2);
  var last = { t:-1, r:-1, v:-1 };
        }


        function update() {
  function update(){
          const X = parseInt(el.x.value, 10);
    var X = parseInt(el.x.value,10);
    var Y = Math.floor(X/479);
    var Z = X % 479;


          const Y = Math.floor(X / 479);
    var iT = (X-1) % 12;
          const Z = X % 479;
    var iR = (X-1) % 32;
    var iV = (X-1) % 67;


          const iT = (X - 1) % 12;
    el.xval.textContent = X;
          const iR = (X - 1) % 32;
    el.cyc.textContent  = Y;
          const iV = (X - 1) % 67;
    el.day.textContent  = Z;


          el.xval.textContent = X;
    if(iT !== last.t){ last.t = iT; el.t.src = (cache.T[iT] && cache.T[iT].src) || (BASE + "Tiriel_" + pad2(iT) + ".png"); }
          el.cyc.textContent = Y;
    if(iR !== last.r){ last.r = iR; el.r.src = (cache.R[iR] && cache.R[iR].src) || (BASE + "Rhaen_" + pad2(iR) + ".png"); }
          el.days.textContent = Z;
    if(iV !== last.v){ last.v = iV; el.v.src = (cache.V[iV] && cache.V[iV].src) || (BASE + "Veyra_"  + pad2(iV) + ".png"); }
  }


          el.tiriel.src = BASE + "Tiriel_" + pad2(iT) + ".png";
  // Smooth scrubbing without spamming layout
          el.rhaen.src  = BASE + "Rhaen_"  + pad2(iR) + ".png";
  var raf = null;
          el.veyra.src  = BASE + "Veyra_"  + pad2(iV) + ".png";
  el.x.addEventListener("input", function(){
        }
    if(raf) return;
    raf = requestAnimationFrame(function(){ raf = null; update(); });
  });


        el.x.addEventListener("input", update);
  update();
        update();
var playBtn = document.getElementById(ID + "-play");
      })();
var timer = null;
    </script>
var playing = false;
var interval = 1000/<!--{$fps|default:5|escape:'html'}-->;


   ]]></content>
function stepForward(){
   var v = parseInt(el.x.value, 10);
  if(v >= 6433) v = 1;
  else v++;
  el.x.value = v;
  update();
}


</widget></includeonly>
playBtn.addEventListener("click", function(){
  if(!playing){
    playing = true;
    playBtn.textContent = "■";  // stop icon
    timer = setInterval(stepForward, interval);
  } else {
    playing = false;
    playBtn.textContent = "▶";  // play icon
    clearInterval(timer);
    timer = null;
  }
});
})();
</script></includeonly>

Latest revision as of 16:50, 10 November 2025

This widget allows you to embed the lunar orbits of WyrdeHaven in your mediaWiki page

Usage

{{#widget:MoonStack | basePath=/images/moons/ | size=512 | id=ms1}}

basePath   Location of image files for the orbits   /images/moons/
size   maximum image size in pixels   512
id   unique id prefix if you embed multiple widgets on one page   wh
fps   Desired fps for the animation   5