chore(static): Cloudflare deploy artifacts — R2 CORS policy + deploy runbook

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BenStullsBets
2026-06-30 07:45:20 -07:00
parent 77cb04bb8c
commit a93c0d57c8
2 changed files with 98 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
# 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
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`.
Plan: `docs/superpowers/plans/2026-06-30-cloudflare-static-publish.md`.
This project is **exempt from the flotilla/PPE/§9 pipeline** (operator-set) — it
deploys directly to Cloudflare. Safety/hygiene rules still hold.
## Prerequisites (operator gestures — need Cloudflare auth)
`wrangler` is not installed in the dev box; the deploy runs from a machine with
Cloudflare credentials.
```bash
npm i -g wrangler
wrangler login
```
`benstull.art` is already a Cloudflare zone (no nameserver migration).
## 1. Build the artifacts
From the repo root (run as a MODULE — `tools/http.py` shadows stdlib `http` if run
as a script):
```bash
.venv/bin/python -m tools.build_static
```
Produces:
- `dist/` — Pages output: `dist/human-experience-simulator/` (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
(clip bases + 154 transition morphs + 5 per-scale audio). No master/mezzanine
sources.
## 2. R2 — bucket, CORS, custom domain, media
```bash
wrangler r2 bucket create hef-media
wrangler r2 bucket cors put hef-media --rules deploy/cloudflare/r2-cors.json
wrangler r2 bucket sync ./dist-media r2://hef-media
```
Then in the dashboard (R2 → `hef-media` → Settings):
- **Custom domain:** add `static.benstull.art` (this is the `mediaBase` baked into
`config.js`).
- **CORS is load-bearing** — the WebGL dream shader taints without it. The policy
in `r2-cors.json` allows `https://benstull.art` + `Range` (video scrubbing).
- **Caching:** the media URLs are content-hash-versioned (`?v=<hash>`), so set the
objects `Cache-Control: public, max-age=31536000, immutable` (a re-baked clip
gets a new hash → new URL → cache busts cleanly).
If you change the media base, rebuild with `--media-base https://<host>/` so
`config.js` matches.
## 3. Pages — deploy + domain + redirect
```bash
wrangler pages project create human-experience-simulator
wrangler pages deploy dist --project-name human-experience-simulator
```
Then in the dashboard (Pages → project → Custom domains):
- Bind **`benstull.art`** to the project.
- The app serves at `benstull.art/human-experience-simulator/`; the generated
`dist/_redirects` sends `/` and the no-slash form to it. (Alternatively, a
zone-level **Redirect Rule** `benstull.art/``/human-experience-simulator`
is the authoritative equivalent if you prefer not to ship `_redirects`.)
## 4. Verify before/after going live
```bash
# CORS + Range on the media origin (after step 2)
curl -sI -H "Origin: https://benstull.art" -H "Range: bytes=0-1" \
https://static.benstull.art/<some>/base.mp4 | grep -iE "access-control-allow-origin|content-range|accept-ranges"
```
Open `https://benstull.art/` → should redirect to
`https://benstull.art/human-experience-simulator/`. 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
cross-origin path before you ship.