Compare commits

..

No commits in common. "0ec49a0c3b0b213939079d5b519b97dbea7ebe8e" and "91cf48c5518afb34933f42c6817f9932e8dcde23" have entirely different histories.

10 changed files with 32 additions and 71 deletions

2
.gitignore vendored
View file

@ -1,2 +0,0 @@
# Build output — assembled from index.html + assets/ by build.sh
dist/

View file

@ -1,18 +1,15 @@
# Stackable Metronome # Stackable Metronome
A browser **polymetric groove trainer / metronome** — a full web app, and the A browser **polymetric groove trainer / metronome** — and the design mockup for a
reference design for a Raspberry Pi Pico hardware build (whose playonly device is Raspberry Pi Pico hardware build. Stack as many "meter lanes" as you like; each is
mocked up at [`player.html`](player.html)). Stack as many "meter lanes" as you like; its own little metronome with a grouping, subdivision, drum voice and a per-step
each is its own little metronome with a grouping, subdivision, drum voice and a pattern with accents. Layering lanes produces polymeter and true ratio polyrhythm.
perstep pattern with accents. Layering lanes produces polymeter and true ratio polyrhythm.
**Live:** https://metronome.varasys.io · **Source:** https://codeberg.org/VARASYS/metronome **Live:** https://metronome.varasys.io · **Source:** https://codeberg.org/VARASYS/metronome
The **deployed page is a single, selfcontained `index.html`****zero dependencies**: It's a single, selfcontained `index.html`**zero dependencies**: no framework,
no framework, no CDN libraries, nothing fetched at runtime. It's assembled by a small no build step, no bundled or CDN libraries, and nothing fetched at runtime. State
build step (`build.sh`) that inlines the audio samples + brand assets (kept in `assets/`) (set lists, the practice log, theme and UI preferences) lives in `localStorage`.
into the HTML, so the source stays lean. State (set lists, the practice log, theme and
UI preferences) lives in `localStorage`.
Because nothing loads from the network, you can save the page (`Ctrl`/`⌘`+`S`) and Because nothing loads from the network, you can save the page (`Ctrl`/`⌘`+`S`) and
open it straight from disk to run fully offline. One catch from a local `file://`: open it straight from disk to run fully offline. One catch from a local `file://`:
@ -156,17 +153,9 @@ disturbing what's playing, then commit on a musical boundary — no audible gap.
- All transitions — manual or auto, beat or bar — keep the clock continuous; the loaded - All transitions — manual or auto, beat or bar — keep the clock continuous; the loaded
item can even live in a set list you're not currently viewing (the player names it). item can even live in a set list you're not currently viewing (the player names it).
## Build
The source `index.html` keeps small `@BUILD:*` markers in place of the large
base64 blobs (audio samples, brand logos, favicon) — those live in `assets/`.
`./build.sh` inlines them into a selfcontained `dist/index.html` (and copies
`player.html`). `dist/` is generated, gitignored — don't edit it by hand.
`deploy.sh` runs the build first, so a deploy always serves a freshly assembled page.
## Versioning ## Versioning
`VERSION` holds the formal version. `deploy.sh` builds, then stamps the served page: `VERSION` holds the formal version. `deploy.sh` stamps the served page:
- **Formal** — a clean commit tagged `v<VERSION>``X.Y.Z`. - **Formal** — a clean commit tagged `v<VERSION>``X.Y.Z`.
- **Dev** — anything else → `X.Y.Z-dev.<utc-timestamp>.<short-sha>[.dirty]`. - **Dev** — anything else → `X.Y.Z-dev.<utc-timestamp>.<short-sha>[.dirty]`.
@ -179,11 +168,8 @@ Push the tag, then deploy.
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `index.html` | the whole app (source, with `@BUILD:*` asset markers) | | `index.html` | the whole app |
| `player.html` | the playonly hardwaredevice mockup (`/player.html`) | | `deploy.sh` | publish to the Caddy web root |
| `assets/` | base64 blobs inlined at build (samples, logos, favicon) |
| `build.sh` | inline `assets/` into `dist/` (selfcontained pages) |
| `deploy.sh` | build, then publish to the Caddy web root |
| `release.sh` | tag a formal version | | `release.sh` | tag a formal version |
| `VERSION` | formal version string | | `VERSION` | formal version string |
| `LICENSE` | GNU AGPL v3 license text | | `LICENSE` | GNU AGPL v3 license text |

View file

@ -1 +1 @@
0.0.10 0.0.9

View file

@ -1 +0,0 @@
PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iNyIgZmlsbD0iIzFDMjgzRiIvPjxwYXRoIGQ9Ik0xMiA2aDhsNCAyMUg4eiIgZmlsbD0iIzBBQjNGNyIvPjxwYXRoIGQ9Ik0xNiAyNEwxOS42IDkiIHN0cm9rZT0iIzFDMjgzRiIgc3Ryb2tlLXdpZHRoPSIxLjgiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgZmlsbD0ibm9uZSIvPjxyZWN0IHg9IjE2LjQiIHk9IjEzLjIiIHdpZHRoPSI0LjQiIGhlaWdodD0iMi44IiByeD0iMC42IiB0cmFuc2Zvcm09InJvdGF0ZSgtMTMgMTguNiAxNC42KSIgZmlsbD0iIzFDMjgzRiIvPjwvc3ZnPgo=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,24 +0,0 @@
#!/usr/bin/env bash
# Assemble the deployed single-file pages from source + assets/.
#
# The source index.html keeps small @BUILD:* markers instead of the large base64
# blobs (audio samples, brand logos, favicon). This inlines those assets so the
# built page in dist/ is one self-contained file (zero deps, works fully offline).
# deploy.sh runs this first. dist/ is generated — don't edit or commit it.
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
mkdir -p dist
python3 - <<'PY'
import json, os, pathlib
A = pathlib.Path("assets")
src = pathlib.Path("index.html").read_text()
src = src.replace("@BUILD:favicon@", (A / "favicon.b64").read_text().strip())
src = src.replace("@BUILD:logo-dark@", (A / "logo-dark.b64").read_text().strip())
src = src.replace("@BUILD:logo-light@", (A / "logo-light.b64").read_text().strip())
src = src.replace("/*@BUILD:samples@*/{}", json.dumps(json.load(open(A / "samples.json"))))
assert "@BUILD:" not in src, "unresolved build marker(s) remain in index.html"
pathlib.Path("dist/index.html").write_text(src)
pathlib.Path("dist/player.html").write_text(pathlib.Path("player.html").read_text()) # no assets to inline
print("built dist/index.html (%dKB) + dist/player.html (%dKB)" %
(os.path.getsize("dist/index.html") // 1024, os.path.getsize("dist/player.html") // 1024))
PY

View file

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Deploy the metronome to the Caddy web root that serves # Deploy the metronome mockup to the Caddy web root that serves
# https://metronome.varasys.io # https://metronome.varasys.io
# #
# Caddy config: /var/lib/caddy/Caddyfile (metronome.varasys.io:8443 block) # Caddy config: /var/lib/caddy/Caddyfile (metronome.varasys.io:8443 block)
@ -12,15 +12,10 @@ set -euo pipefail
SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEST_DIR="/var/lib/caddy/www/metronome" DEST_DIR="/var/lib/caddy/www/metronome"
DIST_DIR="$SRC_DIR/dist"
[[ -f "$SRC_DIR/index.html" ]] || { echo "error: $SRC_DIR/index.html not found" >&2; exit 1; } [[ -f "$SRC_DIR/index.html" ]] || { echo "error: $SRC_DIR/index.html not found" >&2; exit 1; }
[[ -d "$DEST_DIR" ]] || { echo "error: web root $DEST_DIR is missing — is Caddy set up?" >&2; exit 1; } [[ -d "$DEST_DIR" ]] || { echo "error: web root $DEST_DIR is missing — is Caddy set up?" >&2; exit 1; }
# Assemble the self-contained pages (inlines assets/ into dist/). dist/ is git-ignored.
"$SRC_DIR/build.sh"
[[ -f "$DIST_DIR/index.html" ]] || { echo "error: build did not produce $DIST_DIR/index.html" >&2; exit 1; }
# --- compute build version --------------------------------------------------- # --- compute build version ---------------------------------------------------
# Formal build: clean tree on a commit tagged v<VERSION> -> "X.Y.Z" # Formal build: clean tree on a commit tagged v<VERSION> -> "X.Y.Z"
# Dev build: anything else -> "X.Y.Z-dev.<utc-ts>.<sha>[.dirty]" # Dev build: anything else -> "X.Y.Z-dev.<utc-ts>.<sha>[.dirty]"
@ -38,10 +33,10 @@ else
BUILD="$VER-dev.$(date -u +%Y%m%dT%H%M%SZ)" # not a git checkout BUILD="$VER-dev.$(date -u +%Y%m%dT%H%M%SZ)" # not a git checkout
fi fi
# stamp the version into the built copy only (source stays clean) # stamp the version into the deployed copy only (source stays clean)
sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$DIST_DIR/index.html" > "$DEST_DIR/index.html" sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$SRC_DIR/index.html" > "$DEST_DIR/index.html"
echo "deployed v$BUILD ($(stat -c '%s' "$DEST_DIR/index.html") bytes) -> $DEST_DIR" echo "deployed v$BUILD ($(stat -c '%s' "$DEST_DIR/index.html") bytes) -> $DEST_DIR"
sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$DIST_DIR/player.html" > "$DEST_DIR/player.html" sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$SRC_DIR/player.html" > "$DEST_DIR/player.html"
echo "deployed player.html ($(stat -c '%s' "$DEST_DIR/player.html") bytes)" echo "deployed player.html ($(stat -c '%s' "$DEST_DIR/player.html") bytes)"
# If real audio samples are added later (see the plan's GM-sample note), # If real audio samples are added later (see the plan's GM-sample note),

File diff suppressed because one or more lines are too long