Skip to content

feat(themes): motion-video intros via loopback streaming server#226

Open
Wangnov wants to merge 1 commit into
mainfrom
claude/awesome-taussig-d2e95a
Open

feat(themes): motion-video intros via loopback streaming server#226
Wangnov wants to merge 1 commit into
mainfrom
claude/awesome-taussig-d2e95a

Conversation

@Wangnov

@Wangnov Wangnov commented Jul 18, 2026

Copy link
Copy Markdown
Owner

feat(themes): motion-video intros via a loopback streaming server

Aligns the Rust theme engine with awesome studio's new motionAssets runtime
contract (SPEC §2a) so packages like ning-hongye-crimson-night play their
opening video — but delivers the video over a loopback HTTP streaming
server
instead of the studio's inlined data URLs.

Why not data URLs

Base64-inlining a 7 MB clip means ~9.5 MB of text embedded in the injected
payload, re-Runtime.evaluated over CDP on every renderer reload (the daemon
already frets about "pointless 30 MB evaluates"), SHA1'd into the stamp, and
held in memory several times over — near tungstenite's 64 MB message cap for a
single large asset. It works for a demo and collapses past it.

Approach

  • media_server.rs (new): the daemon binds a 127.0.0.1:0 HTTP server with
    Range/206 support. <video> streams natively; reloads just re-fetch the URL —
    zero video bytes over CDP, scales to any size. Hardened with a per-start random
    path token, a loopback Host check, and resolution restricted to the
    currently applied theme's declared motionAssets (paths from validated
    load_theme) — it cannot serve arbitrary files, and carries no CORS headers.
  • payload.rs: motion assets become loopback URLs on a dedicated
    __CTS_MOTION_JSON__ channel (never CSS variables, never inlined). Without a
    server the map is empty → static-intro fallback. The stamp folds each motion
    file's size+mtime so a swapped video re-injects/replays at a stable URL, with
    the bytes stat'd, never read.
  • theme.rs: motionAssets (mp4/webm) load into a separate motion_assets
    map with an independent 24 MB per-file cap (exempt from the CSS 1.4 MB cap and
    the combined budget, since they never ride the payload). assets/previews
    now reject video mimes so video can't slip into a CSS background.
  • theme-runtime.js: 4-arg IIFE; playIntro mounts a muted, PiP-disabled
    <video> over the static art. prefers-reduced-motion, a missing server, or
    any load/play failure all fall back to the static intro (strictly additive).
  • daemon.rs: starts the media server (bind failure is non-fatal → static
    intro), repoints it at each applied theme before building, uses
    build_payload_with_media. run_daemon's signature is unchanged.

CSP

A codex review pass probed the real renderer: Codex 26.715.31925's app://
page ships media-src 'self' app: blob: data:, which blocks the loopback
<video>. The daemon now lifts CSP (Page.setBypassCSP, best-effort) only
before injecting a payload that has motion
— the engine already injects
arbitrary JS into this page, so it's no new trust boundary, and it's transient
(no DOM residue, restored on reload). If the lift ever fails, the intro falls
back to art rather than breaking.

Tests

53 unit tests incl. ranged streaming (206 + exact bytes), token/Host/unknown-key
rejection, resolution by manifest id (not directory name), motion-URL channel
vs. static fallback, stamp sensitivity to a swapped video, and a .codexskin
import carrying an mp4. cargo clippy -D warnings clean on host +
x86_64-pc-windows-msvc; src-tauri integrates.

Review

codex review --uncommitted raised two issues, both fixed here: the CSP block
above (P1) and a media-server resolve that keyed on directory basename instead
of the manifest id (P2, would 404 motion for explicit dev checkouts). Live
end-to-end playback against a running Codex renderer is the one thing not
exercisable in CI and remains to verify in a clean environment.

Align the theme engine with awesome studio's motionAssets contract (SPEC §2a)
so skins can play an opening video — delivered over a loopback HTTP streaming
server instead of base64 data URLs, which don't scale (a 7 MB clip becomes
~9.5 MB of base64 re-shipped over CDP on every reload, near tungstenite's
message cap).

- media_server.rs: 127.0.0.1 HTTP server with Range/206 streaming, per-start
  path token, loopback Host check; resolves only the currently applied theme's
  declared motionAssets, keyed by manifest id (not directory name).
- payload.rs: motion assets become loopback URLs on the __CTS_MOTION_JSON__
  channel, never inlined; the stamp folds each video's size+mtime so a swapped
  file re-injects at a stable URL; has_motion drives the CSP lift.
- theme.rs: motionAssets (mp4/webm) load into a separate map with an
  independent 24 MB per-file cap; assets/previews reject video mimes.
- theme-runtime.js: 4-arg IIFE; playIntro mounts a muted, PiP-disabled <video>;
  prefers-reduced-motion / missing server / play failure fall back to art.
- cdp.rs + daemon.rs: lift CSP (Page.setBypassCSP, best-effort) before
  injecting a motion payload — Codex's app:// page ships
  `media-src 'self' app: blob: data:`, which blocks the loopback <video>.

53 unit tests (ranged streaming, token/Host/id rejection, URL vs static
fallback, swapped-video re-stamp, mp4 .codexskin import). clippy -D warnings
clean on host + x86_64-pc-windows-msvc; src-tauri integrates.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae0ceed2ad

ℹ️ 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".

// loopback stream — Codex's media-src blocks it otherwise.
// Best-effort: a failure just leaves the static intro.
if payload.has_motion {
let _ = session.bypass_csp().await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enable CSP bypass before page load

In the normal daemon path, sessions are attached to already-loaded Codex targets and probed before this branch runs, so calling Page.setBypassCSP here is too late to affect the document's initialized CSP; Puppeteer's CDP wrapper documents that CSP bypassing happens at CSP initialization and should be set before navigation. For motion themes on an existing renderer, Codex's media-src will still block the loopback <video> URL and the new intro path will always fall back to static art unless the page is reloaded after enabling bypass or the media source is otherwise allowed.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant