Add build step (inline assets at build); drop "mockup" from the main app
The source index.html now keeps small @BUILD:* markers instead of the ~250KB of base64 blobs (audio samples, logos, favicon), which move to assets/. build.sh inlines them into a self-contained dist/index.html (+ dist/player.html); deploy.sh runs the build first and serves dist/. dist/ is git-ignored. Keeps the single-file deploy while stopping the samples from eating the editing budget. Also reframe the main page as the full web app (it is not a mockup — only the play-only player.html device is): drop "Mockup" from the title, the source comment, and the README intro; add Build/Files docs and correct the "no build step" claim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
91cf48c551
commit
632890c812
9 changed files with 70 additions and 31 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Build output — assembled from index.html + assets/ by build.sh
|
||||
dist/
|
||||
34
README.md
34
README.md
|
|
@ -1,15 +1,18 @@
|
|||
# Stackable Metronome
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
**Live:** https://metronome.varasys.io · **Source:** https://codeberg.org/VARASYS/metronome
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
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://`:
|
||||
|
|
@ -153,9 +156,17 @@ 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` stamps the served page:
|
||||
`VERSION` holds the formal version. `deploy.sh` builds, then 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]`.
|
||||
|
|
@ -168,8 +179,11 @@ Push the tag, then deploy.
|
|||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `index.html` | the whole app |
|
||||
| `deploy.sh` | publish to the Caddy web root |
|
||||
| `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 |
|
||||
| `release.sh` | tag a formal version |
|
||||
| `VERSION` | formal version string |
|
||||
| `LICENSE` | GNU AGPL v3 license text |
|
||||
|
|
|
|||
1
assets/favicon.b64
Normal file
1
assets/favicon.b64
Normal file
|
|
@ -0,0 +1 @@
|
|||
PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iNyIgZmlsbD0iIzFDMjgzRiIvPjxwYXRoIGQ9Ik0xMiA2aDhsNCAyMUg4eiIgZmlsbD0iIzBBQjNGNyIvPjxwYXRoIGQ9Ik0xNiAyNEwxOS42IDkiIHN0cm9rZT0iIzFDMjgzRiIgc3Ryb2tlLXdpZHRoPSIxLjgiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgZmlsbD0ibm9uZSIvPjxyZWN0IHg9IjE2LjQiIHk9IjEzLjIiIHdpZHRoPSI0LjQiIGhlaWdodD0iMi44IiByeD0iMC42IiB0cmFuc2Zvcm09InJvdGF0ZSgtMTMgMTguNiAxNC42KSIgZmlsbD0iIzFDMjgzRiIvPjwvc3ZnPgo=
|
||||
1
assets/logo-dark.b64
Normal file
1
assets/logo-dark.b64
Normal file
File diff suppressed because one or more lines are too long
1
assets/logo-light.b64
Normal file
1
assets/logo-light.b64
Normal file
File diff suppressed because one or more lines are too long
1
assets/samples.json
Normal file
1
assets/samples.json
Normal file
File diff suppressed because one or more lines are too long
24
build.sh
Executable file
24
build.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/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 mockup to the Caddy web root that serves
|
||||
# Deploy the metronome to the Caddy web root that serves
|
||||
# https://metronome.varasys.io
|
||||
#
|
||||
# Caddy config: /var/lib/caddy/Caddyfile (metronome.varasys.io:8443 block)
|
||||
|
|
@ -12,10 +12,15 @@ 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]"
|
||||
|
|
@ -33,10 +38,10 @@ else
|
|||
BUILD="$VER-dev.$(date -u +%Y%m%dT%H%M%SZ)" # not a git checkout
|
||||
fi
|
||||
|
||||
# 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"
|
||||
# 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"
|
||||
echo "deployed v$BUILD ($(stat -c '%s' "$DEST_DIR/index.html") bytes) -> $DEST_DIR"
|
||||
sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$SRC_DIR/player.html" > "$DEST_DIR/player.html"
|
||||
sed "s|const APP_VERSION = \"[^\"]*\";|const APP_VERSION = \"$BUILD\";|" "$DIST_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