metronome/concepts.html
Me Here 17053719f1 New Stage (foot-pedal) + Showcase (RGB pendulum); fix audio/visual sync
Sync: the visual playhead now advances on a latency-compensated clock
(currentTime − outputLatency||baseLatency) so the on-screen pulse lands when the
click is HEARD, not when it's queued — previously the visual could lead the audio
by the output buffer / Bluetooth latency (up to ~a subdivision). Applied to
editor, player, teacher, and the new pages; also bound the visual queue (vq trim).
No data races: single-threaded; only the rAF draw touches vqPtr/currentStep, and
each vq entry carries the exact scheduled time of its sound.

stage.html — foot-pedal stompbox: two heavy footswitches (Tap=tempo / hold=start-
stop, Next=item / hold=prev), 1/4" expression-pedal input → tempo sweep, big
floor-readable RGB beat light + angled TFT, analog instrument pass-through.
showcase.html — pyramid display piece: an RGB-light pendulum easing to each beat
plus per-lane segment rows showing subdivisions/accents/mutes (canvas).
Both: dual USB-C (data+power and power-thru) to daisy-chain off one source.

Wired into embed.js (stage, showcase variants), build.sh, deploy.sh, the
concepts gallery + landing cards, info-stage.html (~$52) + info-showcase.html
(~$39) with BOMs, and the README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:40:20 -05:00

143 lines
7.5 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PolyMeter Concepts — VARASYS</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,@BUILD:favicon@">
<!-- The PolyMeter concept library: an ever-expanding gallery of form factors
(the PE-1 editor + the PM-1/PM-µ hardware mockups + web widgets). Static page. -->
<script>
(function(){ try{
var p = localStorage.getItem("metronome.theme");
if (p!=="light" && p!=="dark" && p!=="system") p = "system";
document.documentElement.dataset.theme = p==="system" ? (matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : p;
} catch(e){ document.documentElement.dataset.theme = "dark"; } })();
</script>
<style>
/*@BUILD:include:src/base.css@*/
:root{ --bg1:#12151c; --bg2:#05070a; --txt:#c7d0db; --muted:#7f8b9a; --link:#6cb6ff;
--panel-bg:#161b22; --panel-bd:#2a313c; }
:root[data-theme="light"]{ --bg1:#f5f8fc; --bg2:#dde4ec; --txt:#1e2630; --muted:#5c6776; --link:#1769c4;
--panel-bg:#ffffff; --panel-bd:#d2dae4; }
body{ margin:0; min-height:100vh; padding:22px 16px 56px; color:var(--txt);
background:radial-gradient(circle at 50% -8%, var(--bg1), var(--bg2)); }
a{ color:var(--link); }
main{ width:100%; max-width:980px; margin:26px auto 0; }
h1{ font-size:24px; margin:0 0 4px; }
.lead{ margin:0 0 22px; color:var(--muted); font-size:14px; line-height:1.55; max-width:62ch; }
.grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)); gap:16px; }
.card{ background:var(--panel-bg); border:1px solid var(--panel-bd); border-radius:14px; padding:16px;
display:flex; flex-direction:column; gap:9px; }
.card h3{ margin:0; font-size:16px; }
.chip{ align-self:flex-start; font-size:10px; text-transform:uppercase; letter-spacing:.08em;
padding:2px 9px; border-radius:999px; border:1px solid var(--panel-bd); color:var(--muted); }
.chip.hw{ color:var(--cyan); border-color:rgba(10,179,247,.45); }
.chip.app{ color:#2fe07a; border-color:rgba(47,224,160,.45); }
.card p{ margin:0; font-size:13px; color:var(--muted); line-height:1.5; flex:1; }
.card .links{ display:flex; gap:16px; margin-top:4px; }
.card .links a{ color:var(--link); text-decoration:none; font-size:13px; font-weight:600; }
.card.soon{ opacity:.65; border-style:dashed; }
.site-foot{ max-width:980px; margin:40px auto 0; font-size:12px; color:var(--muted); }
</style>
</head>
<body>
<header class="site-head">
<div class="head-left">
<a class="brand" href="/" title="VARASYS — Simplifying Complexity">
<img class="brand-logo brand-dark" src="data:image/png;base64,@BUILD:logo-dark@" alt="VARASYS — Simplifying Complexity" />
<img class="brand-logo brand-light" src="data:image/png;base64,@BUILD:logo-light@" alt="VARASYS — Simplifying Complexity" />
</a>
<span class="page-name"><b>PolyMeter</b> · Concepts</span>
</div>
<nav class="site-nav">
<a href="/editor.html">Editor</a>
<span class="here">Concepts</span>
<a href="/embed.html">Embed</a>
<button id="themeBtn" class="tbtn" title="toggle light / dark theme"></button>
</nav>
</header>
<main>
<h1>PolyMeter Concepts</h1>
<p class="lead">One polymeter engine, many form factors. The same firmware/share-language drives the
web editor and every device idea below — an ever-expanding library of concepts, from a full editor to
pocket practice hardware. Open one to try it live.</p>
<div class="grid">
<div class="card">
<span class="chip app">Web app</span>
<h3>PE1 — PolyMeter Editor</h3>
<p>The full editor: stack meter lanes, perstep accents / ghosts / mutes, swing &amp; ratio polyrhythm,
set lists, and shareable links. This is where you design grooves.</p>
<div class="links"><a href="/editor.html">Open ↗</a><a href="/info-editor.html">Info ⓘ</a></div>
</div>
<div class="card">
<span class="chip">Concept</span>
<h3>PM1 — Initial</h3>
<p>The original idealized device mock — full multilane display and setlist navigation. A northstar
concept (more than a single small unit can really show); the buildable take is Teacher.</p>
<div class="links"><a href="/player.html">Open ↗</a><a href="/info-initial.html">Info ⓘ</a></div>
</div>
<div class="card">
<span class="chip hw">Hardware</span>
<h3>PM1 — Teacher</h3>
<p>Fullfeature desktop console for studio &amp; lessons: 2.0″ colour TFT showing every lane, arcade buttons,
thumbroller, 1/4″ instrument passthrough with analog click injection + balancedTRS out, USBC powered.</p>
<div class="links"><a href="/teacher.html">Open ↗</a><a href="/info-teacher.html">Info &amp; BOM ⓘ</a></div>
</div>
<div class="card">
<span class="chip hw">Hardware</span>
<h3>PM1 — Stage</h3>
<p>Footpedal stompbox for live use: two heavy footswitches (tap / next), an expressionpedal input, a
big floorreadable RGB beat light, instrument passthrough with analog click, dualUSBC daisychain.</p>
<div class="links"><a href="/stage.html">Open ↗</a><a href="/info-stage.html">Info &amp; BOM ⓘ</a></div>
</div>
<div class="card">
<span class="chip hw">Hardware</span>
<h3>PMµ — Micro</h3>
<p>Long, narrow inline practice bar: instrument in one end, amp/headphones out the other, click mixed in.
Clickable thumbroller, amber 14segment display, USBC powered.</p>
<div class="links"><a href="/micro.html">Open ↗</a><a href="/info-micro.html">Info &amp; BOM ⓘ</a></div>
</div>
<div class="card">
<span class="chip hw">Hardware</span>
<h3>PMS — Showcase</h3>
<p>A display piece shaped like a classic pyramid windup metronome — the pendulum is RGB light easing to
the beat, with light rows showing every lane's subdivisions, accents &amp; mutes. USBC powered.</p>
<div class="links"><a href="/showcase.html">Open ↗</a><a href="/info-showcase.html">Info &amp; BOM ⓘ</a></div>
</div>
<div class="card soon">
<span class="chip">Coming</span>
<h3>More form factors</h3>
<p>The library keeps growing — desktop, Eurorack, wearable, headless module… each a widget you can
embed. Ideas welcome.</p>
</div>
</div>
</main>
<div class="site-foot">VARASYS · Simplifying Complexity — <span id="appVersion">v0.0.1-dev</span></div>
<script>
const APP_VERSION = "v0.0.1-dev";
const $ = (id)=>document.getElementById(id);
try{ $("appVersion").textContent = "v"+APP_VERSION.replace(/^v/,""); }catch(e){}
const THEMES=["system","light","dark"];
function effectiveTheme(p){ return p==="system" ? (matchMedia("(prefers-color-scheme: light)").matches?"light":"dark") : p; }
function themePref(){ try{ const p=localStorage.getItem("metronome.theme"); return (p==="light"||p==="dark"||p==="system")?p:"system"; }catch(e){ return "system"; } }
function applyTheme(p){ try{ localStorage.setItem("metronome.theme",p); }catch(e){}
document.documentElement.dataset.theme = effectiveTheme(p);
$("themeBtn").textContent = p==="system" ? "◐" : p==="light" ? "☀" : "☾"; $("themeBtn").title="Theme: "+p+" (system → light → dark)"; }
$("themeBtn").onclick = ()=> applyTheme(THEMES[(THEMES.indexOf(themePref())+1)%THEMES.length]);
matchMedia("(prefers-color-scheme: light)").addEventListener("change", ()=>{ if(themePref()==="system") applyTheme("system"); });
applyTheme(themePref());
</script>
</body>
</html>