metronome/embed.html
Me Here eecea625d3 Add PM_K-1 "Kit" — buildable Pico touchscreen unit + MicroPython firmware
A new, first-actually-buildable form factor for the 52Pi EP-0172 "Pico Breadboard
Kit Plus" (Raspberry Pi Pico; 3.5" ST7796 320x480 cap-touch via GT911, PSP
joystick on ADC0/1, WS2812 RGB on GP12, buzzer GP13, buttons GP14/15):

  - pico/main.py — one self-contained MicroPython file: ST7796 direct-draw driver,
    GT911 touch (16-bit register addressing), WS2812 RGB (neopixel), PWM buzzer,
    ADC joystick, buttons. It parses the project's own program-string language
    (verified against the web engine's semantics) and runs a non-blocking
    ticks_us scheduler with an on-screen touch UI. CONFIG flags cover panel /
    colour / touch / joystick calibration. pico/README.md has flashing +
    calibration steps.
  - kit.html — lean widget that mirrors the firmware's on-screen UI (portrait
    320x480 canvas) plus a joystick / RGB / buzzer / A-B buttons; plays via the
    shared engine. info-kit.html — the real EP-0172 pinout, a parts list
    (~$45 incl. Pico) and the firmware to flash (downloads /pico-main.py, links
    the README + source).
  - Landing + embed page list the Kit; build.sh/deploy.sh build the two pages and
    serve pico/main.py as /pico-main.py for download.

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

135 lines
7.3 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>Embed a PolyMeter widget — VARASYS</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,@BUILD:favicon@">
<!-- Docs for the embeddable PolyMeter widget. Dogfoods embed.js with a live example. -->
<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; --field-bg:#0e1116; }
:root[data-theme="light"]{ --bg1:#f5f8fc; --bg2:#dde4ec; --txt:#1e2630; --muted:#5c6776; --link:#1769c4;
--panel-bg:#ffffff; --panel-bd:#d2dae4; --field-bg:#f1f4f8; }
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:760px; margin:26px auto 0; }
h1{ font-size:24px; margin:0 0 4px; } h2{ font-size:16px; margin:26px 0 8px; }
p{ color:var(--muted); font-size:14px; line-height:1.6; } p.lead{ max-width:60ch; }
pre{ background:var(--field-bg); border:1px solid var(--panel-bd); border-radius:9px; padding:12px 14px;
overflow:auto; font-size:12.5px; line-height:1.5; color:var(--txt); }
code{ background:var(--field-bg); border:1px solid var(--panel-bd); border-radius:4px; padding:1px 5px; font-size:12px; }
table{ border-collapse:collapse; font-size:13px; width:100%; }
th,td{ text-align:left; padding:5px 8px; border-bottom:1px solid var(--panel-bd); vertical-align:top; }
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); }
</style>
</head>
<body>
/*@BUILD:include:src/header.html@*/
<main>
<h1>Embed a PolyMeter widget</h1>
<p class="lead">Every PolyMeter form factor doubles as an embeddable widget. Drop one into any page with
a placeholder + one script tag — no build step, no dependencies. It loads in an iframe and is preloaded
with whatever <b>program / settings string</b> you give it.</p>
<p class="pick"><label for="ffSel">Show snippets for:</label>
<select id="ffSel">
<option value="editor">PM_E1 Editor</option>
<option value="teacher">PM_T1 Teacher</option>
<option value="stage">PM_S1 Stage</option>
<option value="micro" selected>PM_P1 Practice</option>
<option value="showcase">PM_D1 Display</option>
<option value="initial">PM_C1 Concept</option>
</select>
<span class="ff-name"></span></p>
<h2>Drop-in (recommended)</h2>
<pre id="snipDrop"></pre>
<p>The script replaces the <code>&lt;div&gt;</code> with an auto-sizing iframe. Here's the <span class="ff-name"></span>, live on this page:</p>
<div class="demo"><iframe id="demoFrame" title="live embed preview" allow="autoplay" style="border:0;display:block;width:100%;height:300px"></iframe></div>
<h2>Or a plain iframe</h2>
<pre id="snipIframe"></pre>
<h2>Form factors — <code>data-varasys-metronome</code></h2>
<table>
<thead><tr><th>value</th><th>widget</th></tr></thead>
<tbody>
<tr><td class="k">editor</td><td>PM_E1 PolyMeter Editor (full web app)</td></tr>
<tr><td class="k">teacher</td><td>PM_T1 Teacher (studio / lesson console)</td></tr>
<tr><td class="k">stage</td><td>PM_S1 Stage (footpedal stompbox)</td></tr>
<tr><td class="k">micro</td><td>PM_P1 Practice (inline practice bar)</td></tr>
<tr><td class="k">showcase</td><td>PM_D1 Display (RGB pendulum showpiece)</td></tr>
<tr><td class="k">initial</td><td>PM_C1 Concept (idealized render)</td></tr>
</tbody>
</table>
<h2>Configuration / settings string</h2>
<table>
<thead><tr><th>attribute</th><th>what</th></tr></thead>
<tbody>
<tr><td class="k">data-patch</td><td>A PolyMeter program string, e.g. <code>v1;t120;kick:4;snare:4=.X.X;hatClosed:4/2</code>. Copy it from the editor's program field.</td></tr>
<tr><td class="k">data-setlist</td><td>A base64url setlist code (a whole set list) — share it from the editor.</td></tr>
<tr><td class="k">data-width / data-height</td><td>iframe size (default <code>100% × 300</code>; height autogrows to the widget).</td></tr>
</tbody>
</table>
<p>Under the hood the loader builds <code>&lt;page&gt;?embed=1#p=&lt;patch&gt;</code>; the page's <code>?embed=1</code> mode strips the
site chrome so only the widget shows. That's the same way our own Concept &amp; Info pages embed it.</p>
</main>
<script>
const APP_VERSION = "v0.0.1-dev";
const $ = (id)=>document.getElementById(id);
/* Form-factor picker: updates every snippet + the live demo for the chosen version. */
const ORIGIN = "https://metronome.varasys.io";
const DEMO_PATCH = "v1;t120;kick:4;snare:4=.X.X;hatClosed:4/2";
const FF = [
{ k:"editor", name:"PM_E1 Editor", file:"editor.html", h:560 },
{ k:"kit", name:"PM_K1 Kit", file:"kit.html", h:560 },
{ k:"teacher", name:"PM_T1 Teacher", file:"teacher.html", h:440 },
{ k:"stage", name:"PM_S1 Stage", file:"stage.html", h:430 },
{ k:"micro", name:"PM_P1 Practice", file:"micro.html", h:240 },
{ k:"showcase", name:"PM_D1 Display", file:"showcase.html",h:540 },
{ k:"initial", name:"PM_C1 Concept", file:"player.html", h:440 },
];
function updateFF(k){
const v = FF.find(x => x.k === k) || FF[0];
$("snipDrop").textContent =
'<div data-varasys-metronome="' + v.k + '"\n data-patch="' + DEMO_PATCH + '"></div>\n' +
'<script src="' + ORIGIN + '/embed.js"><\/script>';
$("snipIframe").textContent =
'<iframe src="' + ORIGIN + '/' + v.file + '?embed=1#p=' + DEMO_PATCH + '"\n' +
' width="360" height="' + v.h + '" style="border:0"><\/iframe>';
const f = $("demoFrame"); f.style.height = v.h + "px"; f.src = "/" + v.file + "?embed=1#p=" + encodeURIComponent(DEMO_PATCH);
document.querySelectorAll(".ff-name").forEach(el => el.textContent = v.name);
}
$("ffSel").addEventListener("change", (e) => updateFF(e.target.value));
addEventListener("message", (e) => {
if (e.data && e.data.type === "varasys-h" && typeof e.data.h === "number" && e.source === $("demoFrame").contentWindow)
$("demoFrame").style.height = e.data.h + "px";
});
updateFF($("ffSel").value || "micro");
/*@BUILD:include:src/chrome.js@*/
</script>
/*@BUILD:include:src/footer.html@*/
</body>
</html>