v0.6: one-command setup, stage mode for OBS, hold-Space compare, env rename, app.js split - #15
Conversation
…ead fallback Server, Mac runtime, scripts, CI, docs, and the demo page now use SURFACESHIFT_BACKEND / SURFACESHIFT_ACCESS_CODE / SURFACESHIFT_WIDTH etc. Legacy CLAY_SCREEN_* names are still read for one release so existing .env.local files keep working; regression tests cover both directions. The runtime tmp dir moves from clay-screen to surfaceshift.
Moves the 30 fps recording compositor, MediaRecorder lifecycle, and the record-button state machine (~370 lines) into static/recording-studio.js behind a createRecordingStudio(deps) factory; behavior unchanged. app.js drops from 1626 to 1284 lines. The UI-contract test now scans all shipped static JS instead of app.js alone.
Moves source selection and teardown (demo canvas, captured tab, camera, video file) into static/sources.js behind createSourceManager(deps), with session control flowing back through onStopTransform/onStopAll callbacks. Behavior unchanged; verified live (demo session + full record start/stop cycle, no console errors). app.js is now 1146 lines, from 1626 this morning.
…nboarding hint Adds setup.sh (venv, deps, .env.local with a generated access code and a fal-key prompt; non-interactive safe; never touches an existing .env.local), makes run_demo.sh prefer .venv/bin/python so no manual activation is needed, and shows a hint on the demo page pointing at the setup section whenever the server is running in the non-AI preview. Verified cold in a scratch clone: setup.sh -> run_demo.sh -> healthy server with no manual steps.
…adout ?stage=1 strips the page to the generated output on a transparent background with hover-only controls (drive them from OBS's Interact window). Cloud sessions now show a spend-ceiling badge on the frame: elapsed session time at the listed per-compute-second rate, capped at the selected session limit, labeled explicitly as an upper bound. Verified live: stage layout, transparent body, and a running demo session render exactly as an OBS source would capture them.
During any session, holding Space overlays a live render of the current source in the output pane (SOURCE chip, immediate first frame, rAF-paced while held); releasing, blurring the window, or stopping the session ends the comparison. The art-direction A/B the Designer Mirror research called for, verified live in the browser.
Space compare: preventDefault now covers auto-repeat keydowns (held Space no longer scrolls the page) and the Start button blurs after click so Space reaches the compare gesture instead of stopping a paid session. The spend badge hides when leaving cloud mode. run_demo.sh/run_mac.sh parse .env.local line-by-line instead of sourcing it, so dotenv values can never execute as shell (verified with an injection probe). app.py gains TrustedHostMiddleware (DNS-rebinding) and X-Frame-Options/frame-ancestors denial, with tests. setup.sh now tells re-runners where their access code lives (including the legacy variable name), notes the empty-key preview path, and flags terminal scrollback; page/README/CONTRIBUTING updated to match actual behavior.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11e5c3df87
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| [[ "$name" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue | ||
| export "$name=$value" | ||
| done < .env.local | ||
| fi |
There was a problem hiding this comment.
Preserve shell quoting when loading existing dotenv files
Existing .env.local files that use valid shell syntax such as FAL_KEY="...", CLAY_SCREEN_ACCESS_CODE="...", or trailing comments worked when this file was sourced, but this parser exports the quote/comment characters literally. In that common upgrade scenario the quoted FAL key is rejected upstream and an unquoted access code entered in the UI never matches, so cloud mode stops working. Parse standard dotenv quoting/comments or retain a non-executing parser that supports them.
Useful? React with 👍 / 👎.
Implements Steps 0–2 of the v1 roadmap: foundation chores, the flawless first
ten minutes, and the two shareable wedges. Nine commits, each independently
tested; an adversarial 5-agent review panel ran before this PR and its 11
confirmed findings (0 false positives) are fixed in the final commit.
Step 0 — Foundation
0143260):CLAY_SCREEN_*→SURFACESHIFT_*everywhere,with a dual-read fallback so existing
.env.localfiles keep working for onerelease (regression-tested in both directions). Tmp dir renamed too.
d748087,cf3dfc6): the recording studio (~370 lines)and the source manager (~150 lines) are now factory modules with explicit
dependencies; app.js drops 1626 → ~1150 lines with behavior verified live
(demo session, full record start/stop cycle). The cloud-presentation seam is
the remaining extraction, deliberately deferred — it has the highest coupling.
v0.5.0tagged on main before branching.Step 1 — First ten minutes
setup.sh(80bbf6e): venv + deps +.env.localin one command. Itgenerates the local access code itself (the single most confusing step of the
old flow — users no longer invent a password), prompts for the fal key only
in an interactive terminal, never touches an existing
.env.local, and tellsre-runners where their code lives — including under the legacy variable name.
run_demo.shprefers.venv/bin/python, so no manual activation, and bothrun scripts now parse
.env.localline-by-line instead ofsource-ingit — dotenv values can never execute as shell (verified with an injection
probe:
FAL_KEY=abc$(touch PWNED)defboots the server, creates nothing).linking to the on-page instructions. Cold-start verified in a scratch clone:
clone →
./setup.sh→./run_demo.sh→ healthy server, zero manual steps.Step 2 — The wedges
1840001):?stage=1strips the page to the generatedoutput on a transparent background with hover-only controls — paste the URL
into an OBS browser source and drive it from the Interact window. Cloud
sessions show a spend-ceiling badge (elapsed time × listed rate, capped at
the session limit, labeled explicitly as an upper bound).
b8fb8d1): flashes a live render of the untouchedsource over the output with a SOURCE chip — the Designer Mirror A/B gesture.
Hardening (
11e5c3d, from the review panel)the Start button blurs after click, so Space can't silently stop a paid
session via the still-focused button.
TrustedHostMiddleware(DNS-rebinding) andX-Frame-Options: DENY+frame-ancestors 'none'on all responses, with tests.setup.shbehavior everywhere the reviewers caught drift.Plus
CONTRIBUTING.md+ issue templates (a42a707).Test plan
pytest -q— 15 passed (legacy-env regression, security headers, hostallowlist all covered)
npm test— 42 passed;npm run checkcleanextracted modules, stage-mode layout with a running session, compare
overlay show/paint/release, setup hint, security headers, rebinding 400
setup.shexecuted cold and re-run in a scratch clone; injection probebrowser-source capture of
?stage=1Remaining before a v1 tag
Cold-start test by someone who isn't the author; the overlay throttling check
in real Chrome; the 12 source×material sweep; the idle-billing probe (needs a
real key); the local Core ML go/no-go benchmark. None block this PR.
🤖 Generated with Claude Code