From 1faf9cad413fa82fa9c328a573cbaa6f3c329723 Mon Sep 17 00:00:00 2001 From: Me Here Date: Thu, 28 May 2026 11:55:12 -0500 Subject: [PATCH] Embed version dropdown; Display weight static/behind lights; Practice beat flash; move Philosophy up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Embed page: a form-factor dropdown that rewrites every snippet (drop-in + plain iframe), the live demo, and the name for the chosen version; variant table completed to all six. - Display (Showcase): the tempo weight no longer flashes and is drawn BEHIND the pendulum lights so it never hides a beat flash. - Practice (Micro): a beat/sub-beat flash — the whole 14-seg display washes amber on each step (subtle on sub-beats, brighter on the beat, full on the "1"), latency-compensated like the other devices. - Landing: Philosophy section moved above "Pick a form factor". Co-Authored-By: Claude Opus 4.7 (1M context) --- embed.html | 64 +++++++++++++++++++++++++++++++++++++++++---------- index.html | 32 +++++++++++++------------- micro.html | 30 ++++++++++++++++++++++-- showcase.html | 21 ++++++++--------- 4 files changed, 106 insertions(+), 41 deletions(-) diff --git a/embed.html b/embed.html index f043c0d..af48772 100644 --- a/embed.html +++ b/embed.html @@ -33,6 +33,10 @@ th{ color:var(--muted); font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:.04em; } td.k{ white-space:nowrap; color:var(--cyan); font-family:"Courier New",monospace; } .demo{ background:var(--panel-bg); border:1px solid var(--panel-bd); border-radius:14px; padding:14px; margin-top:8px; } + .pick{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:14px; } + .pick label{ font-size:13px; color:var(--txt); } + .pick select{ background:var(--field-bg); color:var(--txt); border:1px solid var(--panel-bd); border-radius:8px; padding:7px 10px; font-size:13px; } + .ff-name{ color:var(--cyan); font-weight:600; font-size:13px; } .site-foot{ max-width:760px; margin:40px auto 0; font-size:12px; color:var(--muted); } @@ -46,27 +50,35 @@ a placeholder + one script tag — no build step, no dependencies. It loads in an iframe and is preloaded with whatever program / settings string you give it.

+

+ +

+

Drop-in (recommended)

-
<div data-varasys-metronome="micro"
-     data-patch="v1;t120;kick:4;snare:4=.X.X;hatClosed:4/2"></div>
-<script src="https://metronome.varasys.io/embed.js"></script>
-

The script replaces the <div> with an auto-sizing iframe. Here it is, live on this page:

-
-
-
+

+  

The script replaces the <div> with an auto-sizing iframe. Here's the , live on this page:

+

Or a plain iframe

-
<iframe src="https://metronome.varasys.io/micro.html?embed=1#p=v1;t120;kick:4"
-        width="360" height="300" style="border:0"></iframe>
+

 
   

Form factors — data-varasys-metronome

- - + + + +
valuewidget
editorPM_E‑1 PolyMeter Editor (full app)
initialPM_C‑1 Concept (idealized device)
editorPM_E‑1 PolyMeter Editor (full web app)
teacherPM_T‑1 Teacher (studio / lesson console)
stagePM_S‑1 Stage (foot‑pedal stompbox)
microPM_P‑1 Practice (inline practice bar)
showcasePM_D‑1 Display (RGB pendulum showpiece)
initialPM_C‑1 Concept (idealized render)
@@ -86,9 +98,37 @@ - /*@BUILD:include:src/footer.html@*/ diff --git a/index.html b/index.html index ecc4b05..b8385c0 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,22 @@ below — or pick any form factor to load and play the same groove on it.

+
+ +
+
+

🛠️ Program on the web, play on any device

+

The website is the workbench: design in the editor, and the same + program string loads into whichever form factor fits the moment. One engine, one language.

+
+
+

🔌 USB‑C power everywhere — no batteries

+

Every device runs over a single USB‑C port (the larger ones add a pass‑through to daisy‑chain). + No internal battery to wear out; bring a power bank. One connector keeps it all future‑proof.

+
+
+
+
@@ -107,22 +123,6 @@
The current program, decoded (not base64). Paste a patch or a base64 set‑list code; it's checked, then loaded. Conventions: GM names or numbers (kick / 36), =X.x- steps, /2 subdivision, (3,8) euclidean, @-3 dB, ~ polymeter.
- -
- -
-
-

🛠️ Program on the web, play on any device

-

The website is the workbench: design in the editor, and the same - program string loads into whichever form factor fits the moment. One engine, one language.

-
-
-

🔌 USB‑C power everywhere — no batteries

-

Every device runs over a single USB‑C port (the larger ones add a pass‑through to daisy‑chain). - No internal battery to wear out; bring a power bank. One connector keeps it all future‑proof.

-
-
-
/*@BUILD:include:src/footer.html@*/ diff --git a/micro.html b/micro.html index 2aef2e1..25dc1f9 100644 --- a/micro.html +++ b/micro.html @@ -201,7 +201,7 @@ function startAudio(){ ensureAudio(); audioCtx.resume(); state.running=true; const t0=audioCtx.currentTime+0.08; for(const m of meters){ m.tick=0; m.nextTime=t0; m.vq=[]; m.vqPtr=0; } - muteWindows=[]; schedulerTimer=setInterval(scheduler,LOOKAHEAD_MS); scheduler(); render(); + muteWindows=[]; beatFlash=0; schedulerTimer=setInterval(scheduler,LOOKAHEAD_MS); scheduler(); render(); } function stopAudio(){ state.running=false; clearInterval(schedulerTimer); schedulerTimer=null; render(); } function toggle(){ state.running ? stopAudio() : startAudio(); } @@ -262,11 +262,36 @@ function drawChar(dx,dy,w,h,ch){ diag(11, dx+t+1, dy+h-t-1, cx-t*0.6, midY+t*0.6); // K bottom-left diag(13, dx+w-t-1, dy+h-t-1, cx+t*0.6, midY+t*0.6); // M bottom-right } -function drawLED(){ +function drawLED(flash, level){ + flash = flash || 0; level = level || 0; lc.fillStyle=LED_BG; lc.fillRect(0,0,LW,LH); + // whole-display beat flash: a wash over the window — subtle on sub-beats, bright on the "1" + if(flash>0){ const a = flash * (level>=3 ? 0.55 : level>=2 ? 0.30 : 0.13); + lc.fillStyle = (level>=3 ? "rgba(255,184,74," : "rgba(255,138,30,") + a.toFixed(3) + ")"; lc.fillRect(0,0,LW,LH); } const txt=ledText(), pad=10, gap=9, n=NCH, dw=(LW-2*pad-(n-1)*gap)/n, dh=LH-2*pad; for(let i=0;i512){ m.vq=m.vq.slice(m.vqPtr); m.vqPtr=0; } + } + beatFlash = Math.max(0, beatFlash - 0.10); + drawLED(beatFlash, beatLevel); + } + requestAnimationFrame(frame); +} function render(){ drawLED(); $("indBpm").classList.toggle("on", displayMode==="bpm"); @@ -315,6 +340,7 @@ addEventListener("keydown",(e)=>{ { const ht=tracksFromHash(); if(ht) tracks=ht; } // a #p=/#sl= link (or embed config) overrides the built-ins loadTrack(0); render(); +requestAnimationFrame(frame); window.currentProgramString = function(){ var t=tracks[trackIdx]||{}; return setupToPatch({bpm:state.bpm, volume:state.volume, lanes:t.lanes||[]}); }; window.loadProgramString = function(plain){ var s=patchToSetup(plain); tracks=[{name:"Program", ...s}]; trackIdx=0; loadTrack(0); }; /*@BUILD:include:src/progbox.js@*/ diff --git a/showcase.html b/showcase.html index 994bbb5..8f19ab1 100644 --- a/showcase.html +++ b/showcase.html @@ -240,7 +240,16 @@ function drawPendulum(){ [40,60,80,100,120,160,200,240].forEach(function(b){ const y=-bpmToFrac(b)*ROD; g.strokeStyle="rgba(180,190,205,.5)"; g.lineWidth=1; g.beginPath(); g.moveTo(4,y); g.lineTo(10,y); g.stroke(); g.fillStyle="rgba(180,190,205,.6)"; g.fillText(String(b), 2, y+3); }); - // combined-meter LEDs: each lane is a moving point of light along the bar (its current step position) + // fixed bob (drives the swing) near the bottom of the rod + g.fillStyle="#2a2f37"; roundRectP(-9,-58,18,30,4); g.fill(); + g.fillStyle="rgba(255,255,255,.06)"; roundRectP(-9,-58,18,5,2); g.fill(); + // sliding WEIGHT = tempo — STATIC (no flash) and drawn BEHIND the lights so it never hides a beat flash + const wy=-bpmToFrac(state.bpm)*ROD; + g.fillStyle="#3a4049"; roundRectP(-15,wy-11,30,22,4); g.fill(); + g.fillStyle="rgba(150,160,176,.5)"; roundRectP(-13,wy-3.5,26,7,2); g.fill(); // index mark (static) + g.fillStyle="rgba(255,255,255,.10)"; roundRectP(-15,wy-11,30,5,2); g.fill(); // top sheen + // combined-meter LEDs: each lane is a moving point of light along the bar (its current step position). + // Drawn LAST so the flashes sit on top of the weight. for(const m of meters){ if(m.currentStep<0 || !state.running) continue; const steps=m.beatsPerBar*m.stepsPerBeat, fr=steps?((m.currentStep%steps)/steps):0; const y=-(0.16 + fr*(0.96-0.16))*ROD, lvl=m.beatsOn[m.currentStep]|0; if(lvl===0) continue; @@ -248,16 +257,6 @@ function drawPendulum(){ g.shadowColor=rgb; g.shadowBlur=14; g.fillStyle=rgb; g.beginPath(); g.arc(0,y, lvl>=2?6:4.5, 0,7); g.fill(); g.shadowBlur=0; } - // fixed bob (drives the swing) near the bottom of the rod - g.fillStyle="#2a2f37"; roundRectP(-9,-58,18,30,4); g.fill(); - g.fillStyle="rgba(255,255,255,.06)"; roundRectP(-9,-58,18,5,2); g.fill(); - // sliding WEIGHT = tempo; glows on the beat - const wy=-bpmToFrac(state.bpm)*ROD, lit=Math.max(0,flash); - const wc = flashAccent ? "rgb(255,155,46)" : "rgb(51,208,255)"; - g.shadowColor=wc; g.shadowBlur=8+22*lit; - g.fillStyle="#3a4049"; roundRectP(-15,wy-11,30,22,4); g.fill(); g.shadowBlur=0; - g.fillStyle=wc; g.globalAlpha=.30+0.7*lit; roundRectP(-13,wy-3.5,26,7,2); g.fill(); g.globalAlpha=1; - g.fillStyle="rgba(255,255,255,.10)"; roundRectP(-15,wy-11,30,5,2); g.fill(); // pivot hub g.restore(); g.beginPath(); g.arc(PIVX,PIVY,6,0,7); g.fillStyle="#2a2f37"; g.fill();