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
|
||||
|
||||
A browser **polymetric groove trainer / metronome** — a full web app, and the
|
||||
reference design for a Raspberry Pi Pico hardware build (whose play‑only device is
|
||||
mocked up at [`player.html`](player.html)). Stack as many "meter lanes" as you like;
|
||||
each is its own little metronome with a grouping, subdivision, drum voice and a
|
||||
per‑step pattern with accents. Layering lanes produces polymeter and true ratio polyrhythm.
|
||||
A browser **polymetric groove trainer / metronome** — and the design mockup for a
|
||||
Raspberry Pi Pico hardware build. Stack as many "meter lanes" as you like; each is
|
||||
its own little metronome with a grouping, subdivision, drum voice and a per-step
|
||||
pattern with accents. Layering lanes produces polymeter and true ratio polyrhythm.
|
||||
|
||||
**Live:** https://metronome.varasys.io · **Source:** https://codeberg.org/VARASYS/metronome
|
||||
|
||||
The **deployed page is a single, self‑contained `index.html`** — **zero dependencies**:
|
||||
no framework, no CDN libraries, nothing fetched at runtime. It's assembled by a small
|
||||
build step (`build.sh`) that inlines the audio samples + brand assets (kept in `assets/`)
|
||||
into the HTML, so the source stays lean. State (set lists, the practice log, theme and
|
||||
UI preferences) lives in `localStorage`.
|
||||
It's a single, self‑contained `index.html` — **zero dependencies**: no framework,
|
||||
no build step, no bundled or CDN libraries, and nothing fetched at runtime. 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
|
||||
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
|
||||
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
|
||||
|
||||
`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`.
|
||||
- **Dev** — anything else → `X.Y.Z-dev.<utc-timestamp>.<short-sha>[.dirty]`.
|
||||
|
|
@ -179,11 +168,8 @@ Push the tag, then deploy.
|
|||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `index.html` | the whole app (source, with `@BUILD:*` asset markers) |
|
||||
| `player.html` | the play‑only hardware‑device mockup (`/player.html`) |
|
||||
| `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 |
|
||||
| `index.html` | the whole app |
|
||||
| `deploy.sh` | publish to the Caddy web root |
|
||||
| `release.sh` | tag a formal version |
|
||||
| `VERSION` | formal version string |
|
||||
| `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
|
||||
# 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
|
||||
#
|
||||
# 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)"
|
||||
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; }
|
||||
[[ -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 ---------------------------------------------------
|
||||
# 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]"
|
||||
|
|
@ -38,10 +33,10 @@ else
|
|||
BUILD="$VER-dev.$(date -u +%Y%m%dT%H%M%SZ)" # not a git checkout
|
||||
fi
|
||||
|
||||
# stamp the version into the built copy only (source stays clean)
|
||||
sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$DIST_DIR/index.html" > "$DEST_DIR/index.html"
|
||||
# stamp the version into the deployed copy only (source stays clean)
|
||||
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"
|
||||
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)"
|
||||
|
||||
# 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