diff --git a/deploy/cloudflare/README.md b/deploy/cloudflare/README.md index e345995..a2cea73 100644 --- a/deploy/cloudflare/README.md +++ b/deploy/cloudflare/README.md @@ -1,7 +1,7 @@ # Deploying to benstull.art — Cloudflare Pages + R2 Publishes the simulator as a fully-static site: the frontend on **Cloudflare -Pages** (`benstull.art`, app at `/human-experience-simulator`, apex redirects to +Pages** (`benstull.art`, app at `/human-machine-strata`, apex redirects to it) and the video/audio on **R2** behind `static.benstull.art`. No origin server. Design: `docs/superpowers/specs/2026-06-30-cloudflare-static-publish-design.md`. @@ -48,7 +48,7 @@ as a script): ``` Produces: -- `dist/` — Pages output: `dist/human-experience-simulator/` (frontend + baked +- `dist/` — Pages output: `dist/human-machine-strata/` (frontend + baked `clips.json`/`ring.json`/`media-versions.json` + generated `config.js`) and a root `dist/_redirects` (apex → app path, and no-slash → slashed). - `dist-media/` — R2 upload tree, ~2.3 GB / 604 files, manifest-referenced only @@ -109,7 +109,7 @@ Then **in the dashboard** (Workers & Pages → project → Custom domains) — t no wrangler CLI for Pages custom domains: - Bind **`benstull.art`** to the project. (Allow a few minutes — a fresh bind serves `522` until the cert/routing provisions.) -- The app serves at `benstull.art/human-experience-simulator/`; the shipped +- The app serves at `benstull.art/human-machine-strata/`; the shipped `dist/_redirects` sends `/` and the no-slash form to it. ## 4. Verify before/after going live @@ -121,7 +121,7 @@ curl -sI -H "Origin: https://benstull.art" -H "Range: bytes=0-1" \ ``` Open `https://benstull.art/` → should redirect to -`https://benstull.art/human-experience-simulator/`. Turn the **Feel** knob to max +`https://benstull.art/human-machine-strata/`. Turn the **Feel** knob to max and confirm the dream effect renders (no `SecurityError` in the console — that would mean CORS is misconfigured and the GL texture is tainted). The local static-build E2E (`simulator/e2e/tests/static-build.spec.ts`) exercises this same diff --git a/deploy/cloudflare/deploy.sh b/deploy/cloudflare/deploy.sh index 796f531..53ba457 100755 --- a/deploy/cloudflare/deploy.sh +++ b/deploy/cloudflare/deploy.sh @@ -15,7 +15,7 @@ set -euo pipefail BUCKET="${BUCKET:-human-experience-simulator-media}" PROJECT="${PROJECT:-human-experience-simulator}" MEDIA_BASE="${MEDIA_BASE:-https://static.benstull.art/}" -APP_PATH="${APP_PATH:-/human-experience-simulator}" +APP_PATH="${APP_PATH:-/human-machine-strata}" BRANCH="${BRANCH:-main}" JOBS="${JOBS:-10}" diff --git a/simulator/e2e/tests/static-build.spec.ts b/simulator/e2e/tests/static-build.spec.ts index 83ef31e..face8c1 100644 --- a/simulator/e2e/tests/static-build.spec.ts +++ b/simulator/e2e/tests/static-build.spec.ts @@ -3,7 +3,7 @@ import { test, expect, Page } from "@playwright/test"; // Runs against the BUILT static site: dist/ served on :8077, media (CORS) on :8078 // by serve-static.mjs. Build with `--media-base http://localhost:8078/` so config.js // points media cross-origin — the production CORS path, locally. See README.md. -const APP = "http://localhost:8077/human-experience-simulator/"; +const APP = "http://localhost:8077/human-machine-strata/"; // Enter the simulation via the welcome screen (Video defaults on → media plays). async function enter(page: Page) { diff --git a/tests/test_build_static.py b/tests/test_build_static.py index f3dfd5a..b798044 100644 --- a/tests/test_build_static.py +++ b/tests/test_build_static.py @@ -9,9 +9,9 @@ def test_build_emits_frontend_baked_json_and_only_referenced_media(tmp_path): result = build_static( out, media, media_base="https://static.benstull.art/", - app_path="/human-experience-simulator", + app_path="/human-machine-strata", ) - app_dir = out / "human-experience-simulator" + app_dir = out / "human-machine-strata" # frontend present under the app path; dev/author surfaces excluded assert (app_dir / "index.html").exists() @@ -25,10 +25,11 @@ def test_build_emits_frontend_baked_json_and_only_referenced_media(tmp_path): assert not (app_dir / "author.html").exists() assert not list(app_dir.glob("review*.html")) - # apex + no-slash redirect rules + # apex + no-slash redirect rules, plus the permanent legacy-path redirect redirects = (out / "_redirects").read_text() - assert "/ /human-experience-simulator/ 308" in redirects - assert "/human-experience-simulator /human-experience-simulator/ 308" in redirects + assert "/ /human-machine-strata/ 308" in redirects + assert "/human-machine-strata /human-machine-strata/ 308" in redirects + assert "/human-experience-simulator/* /human-machine-strata/:splat 301" in redirects # baked JSON matches the API shape clips = json.loads((app_dir / "clips.json").read_text()) diff --git a/tools/build_static.py b/tools/build_static.py index 89cb1c6..4c8065b 100644 --- a/tools/build_static.py +++ b/tools/build_static.py @@ -59,13 +59,23 @@ def _write_config(app_dir: Path, media_base: str) -> None: ) +# The app's original deploy path, kept as a permanent redirect so old links to +# /human-experience-simulator/… still land on the renamed /human-machine-strata/…. +LEGACY_APP_PATH = "human-experience-simulator" + + def _write_redirects(out: Path, seg: str) -> None: # Apex → app path, and the no-trailing-slash form → slashed (so RELATIVE asset - # urls resolve under the prefix). Cloudflare Pages `_redirects` syntax. - (out / "_redirects").write_text( - f"/ /{seg}/ 308\n" - f"/{seg} /{seg}/ 308\n" - ) + # urls resolve under the prefix). Plus a permanent (301) redirect from the legacy + # path to the current one. Cloudflare Pages `_redirects` syntax. + lines = [ + f"/ /{seg}/ 308\n", + f"/{seg} /{seg}/ 308\n", + ] + if LEGACY_APP_PATH and LEGACY_APP_PATH != seg: + lines.append(f"/{LEGACY_APP_PATH}/* /{seg}/:splat 301\n") + lines.append(f"/{LEGACY_APP_PATH} /{seg}/ 301\n") + (out / "_redirects").write_text("".join(lines)) def _write_headers(out: Path, seg: str) -> None: @@ -158,7 +168,7 @@ if __name__ == "__main__": ap.add_argument("--out", default="dist") ap.add_argument("--media-out", default="dist-media") ap.add_argument("--media-base", default="https://static.benstull.art/") - ap.add_argument("--app-path", default="/human-experience-simulator") + ap.add_argument("--app-path", default="/human-machine-strata") a = ap.parse_args() r = build_static(a.out, a.media_out, media_base=a.media_base, app_path=a.app_path) print(json.dumps(r, indent=2))