Compare commits
No commits in common. "0ec49a0c3b0b213939079d5b519b97dbea7ebe8e" and "91cf48c5518afb34933f42c6817f9932e8dcde23" have entirely different histories.
0ec49a0c3b
...
91cf48c551
10 changed files with 32 additions and 71 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
# Build output — assembled from index.html + assets/ by build.sh
|
|
||||||
dist/
|
|
||||||
34
README.md
34
README.md
|
|
@ -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 play‑only 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.
|
||||||
per‑step 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, self‑contained `index.html`** — **zero dependencies**:
|
It's a single, self‑contained `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 self‑contained `dist/index.html` (and copies
|
|
||||||
`player.html`). `dist/` is generated, git‑ignored — 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 play‑only hardware‑device 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/` (self‑contained 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 |
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.0.10
|
0.0.9
|
||||||
|
|
|
||||||
|
|
@ -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
24
build.sh
24
build.sh
|
|
@ -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
|
|
||||||
13
deploy.sh
13
deploy.sh
|
|
@ -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),
|
||||||
|
|
|
||||||
24
index.html
24
index.html
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue