diff --git a/README.md b/README.md index 40286f1..996a042 100644 --- a/README.md +++ b/README.md @@ -158,11 +158,20 @@ disturbing what's playing, then commit on a musical boundary — no audible gap. ## 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. +`index.html` (the editor) and `player.html` (the hardware‑player mockup) are both +sources that share code through `@BUILD:*` markers, so the two stay in sync: + +- `/*@BUILD:include:src/…@*/` inlines a **shared partial** — the audio/scheduler + engine (`src/engine.js`), the seed set lists (`src/setlists.js`, so the player + ships the **same default set lists** as the editor), and base styling + (`src/base.css`: reset + brand palette + type). +- `@BUILD:favicon@`, `@BUILD:logo-*@`, `/*@BUILD:samples@*/{}` inline the base64 + assets from `assets/`. + +`./build.sh` resolves every marker into a self‑contained `dist/index.html` + +`dist/player.html` (the editor inlines the CC0 samples; the player passes an empty +`SAMPLES` for pure synth). `dist/` is generated, git‑ignored — don't edit it by hand. +`deploy.sh` runs the build first, so a deploy always serves freshly assembled pages. ## Versioning @@ -179,10 +188,11 @@ Push the tag, then deploy. | File | Purpose | |------|---------| -| `index.html` | the whole app (source, with `@BUILD:*` asset markers) | +| `index.html` | the editor app (source, with `@BUILD:*` markers) | | `player.html` | the play‑only hardware‑device mockup (`/player.html`) | +| `src/` | shared partials inlined into both: `engine.js`, `setlists.js`, `base.css` | | `assets/` | base64 blobs inlined at build (samples, logos, favicon) | -| `build.sh` | inline `assets/` into `dist/` (self‑contained pages) | +| `build.sh` | resolve markers → self‑contained `dist/` pages | | `deploy.sh` | build, then publish to the Caddy web root | | `release.sh` | tag a formal version | | `VERSION` | formal version string | diff --git a/build.sh b/build.sh index 6a44277..ffab6d6 100755 --- a/build.sh +++ b/build.sh @@ -1,24 +1,35 @@ #!/usr/bin/env bash -# Assemble the deployed single-file pages from source + assets/. +# Assemble the deployed single-file pages from source + shared partials + 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. +# Both index.html and player.html are sources that share code via markers: +# /*@BUILD:include:src/@*/ inlines a shared partial (engine, seed lists, base CSS) +# @BUILD:favicon@ / @BUILD:logo-*@ / /*@BUILD:samples@*/{} inline base64 assets +# This resolves them so each 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 +import json, os, pathlib, re 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)) +SAMPLES = json.dumps(json.load(open(A / "samples.json"))) + +def build(name): + src = pathlib.Path(name).read_text() + # 1) inline shared partials (function-replacement: no backslash/group interpretation) + src = re.sub(r"/\*@BUILD:include:([^@]+)@\*/", + lambda m: pathlib.Path(m.group(1)).read_text().rstrip("\n"), src) + # 2) inline base64 assets + 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@*/{}", SAMPLES) + assert "@BUILD:" not in src, f"unresolved build marker(s) remain in {name}" + out = pathlib.Path("dist") / name + out.write_text(src) + return out.stat().st_size + +i = build("index.html"); p = build("player.html") +print("built dist/index.html (%dKB) + dist/player.html (%dKB)" % (i // 1024, p // 1024)) PY diff --git a/index.html b/index.html index c3211d7..927e51d 100644 --- a/index.html +++ b/index.html @@ -45,6 +45,7 @@ Web Audio's look-ahead scheduler stands in for the hardware timer. -->