Skip to content

feat(studio): motion assets — video intro, tightened pack gate, ning-hongye - #9

Merged
Wangnov merged 8 commits into
mainfrom
feat/studio-motion-intro
Jul 18, 2026
Merged

feat(studio): motion assets — video intro, tightened pack gate, ning-hongye#9
Wangnov merged 8 commits into
mainfrom
feat/studio-motion-intro

Conversation

@Wangnov

@Wangnov Wangnov commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

Three stacked pieces that land the video intro capability end to end:

  1. feat(studio)motionAssets support ported from the design workbench onto the post-fix(studio): adapt Composer across Codex 26.715 builds #6 composer architecture (SPEC 1.1, §2a):
    • videos (mp4/webm) skip CSS variables and ride a dedicated __CTS_MOTION_JSON__ slot into a runtime-mounted muted <video>; static intro art stays as the fallback; prefers-reduced-motion skips entirely; playback failure recovers to static.
    • the pack delivery gate now enforces canonical semver, description/author/license, WebP-only previews & assets within Codex App Manager budgets (1.4MB each / 24MB combined), optional-but-complete codexTheme with codex-theme-v1 round-trip, runtime-consumed motion keys only, intro-video ⇒ static intro required, and the 50MB archive cap post-zip.
    • start --appearance dark|light|system; codex-theme-schema.mjs canonical validator; +6 motion tests (34 total).
  2. fix(skins)rem-rezero modernized for the tightened gate: 28 PNGs → WebP (19.8MB → 6.1MB, all under the 1.4MB budget), delivery metadata lifted out of legacy metadata, bumped to 1.2.1 so existing installs fetch the recompressed pack.
  3. feat(skins)宁红夜 — 赤练无明 (ning-hongye-crimson-night, games): first video-intro skin, 7.1MB opening video + full static fallback, verified on Codex 26.715.21425.

Compatibility

motionAssets is additive: current Codex App Manager imports the pack fine and keeps the full static experience (manifest extraction is lenient; the mp4 is simply unused). Manager-side playback lands separately.

Verification

  • npm run check + npm test: 34/34
  • pack gate over all 28 in-repo skins (incl. reworked rem + ning-hongye): 28/28 OK
  • three codex review rounds; all findings fixed (incl. a pre-existing serpent-orbit class break in the skin and a space-safe test path)

Note

Merging to main auto-publishes to the R2 catalog. If #8 (second-wave skins) merges first, this branch needs a trivial REGISTRY rebase (adjacent-line additions).

@Wangnov
Wangnov marked this pull request as ready for review July 18, 2026 12:50
Wangnov added 8 commits July 18, 2026 20:51
…gate

- theme.json gains an additive motionAssets map (mp4/webm); videos skip
  CSS variables and ride a dedicated __CTS_MOTION_JSON__ slot into a
  runtime-mounted muted <video> with static-intro fallback, honoring
  prefers-reduced-motion and playback-failure recovery.
- pack gate now enforces the delivery contract end to end: canonical
  semver, description/author/license, WebP-only previews and assets
  within Codex App Manager budgets (1.4MB each / 24MB combined), native
  codexTheme validation with codex-theme-v1 round-trip when present,
  runtime-consumed motion keys only, intro-video requiring a static
  intro, and the 50MB archive cap checked post-zip.
- start gains --appearance (dark|light|system) to override the native
  appearanceTheme; codex-theme-schema.mjs ports the canonical validator.
Recompress all 28 PNG assets to WebP (19.8MB -> 6.1MB, every file under
the 1.4MB manager budget), lift delivery metadata out of the legacy
nested metadata block to the top level, and bump to 1.2.1 so existing
installs pick up the recompressed package. REGISTRY now tracks the real
manifest version.
宁红夜 — 赤练无明: dual-appearance Naraka skin and the first user of
motionAssets, shipping a 7.1MB intro video with a static intro fallback
for non-motion hosts. Verified on Codex 26.715.21425.
- ning-hongye chrome.html mounted cts-spirit-orbit while every layout,
  badge and dark-shell rule targets .cts-serpent-orbit — unify on the
  latter so the orbit ring and crest render; the late crimson border
  override is renamed with it and still wins in order.
- motion.test.mjs resolves the runtime template via fileURLToPath so the
  suite survives checkouts under paths containing spaces.
…ailure

- a stamp change now tears down a still-playing intro so theme switches
  never leave the old video running or block the new theme's intro;
  same-stamp re-ensures still leave it untouched.
- every video failure path (error event, play rejection, play throw)
  remounts the intro from scratch so the static fallback restarts its
  animation timeline instead of landing in an expired forwards state.
- the loader rejects motion keys that shadow a static asset — the merged
  data-URL namespace would otherwise silently drop the CSS variable.
- fallbackToStatic now runs at most once and only while it still owns
  the live #cts-intro and the runtime is not disabled — a hot switch or
  off rejects the pending play() with AbortError, and the stale closure
  must not tear down (or resurrect over) the next theme's intro.
- assertInside rejects absolute manifest paths outright: they can
  resolve inside the dev checkout and pack fine, but the manifest ships
  verbatim and the package would fail to load anywhere else.
- applyNativeTheme now inserts appearanceTheme before the first TOML
  table when the key is absent (previously the merge silently no-opped
  on configs that never set it), and restoreNativeTheme deletes the key
  when the pristine baseline had none — apply/restore stay symmetric.
- validateCodexTheme accepts an omitted fonts.code/ui as 'keep the
  Codex default' (same as null), and the share string normalizes the
  omission to an explicit null so both spellings serialize identically.
  loadTheme() calling the validator no longer rejects such themes.
Codex reads appearanceTheme from the [desktop] table; the old top-level
regex kept editing a stale root-level copy on real configs. Backup,
apply and restore now all operate on the [desktop]-scoped key: replace
in place, insert into (or create) the table when absent, and delete on
restore when the pristine baseline had none — stray root-level copies
stay untouched. Null/omitted fonts are skipped by the TOML writer
instead of being written as the literal string "null".
@Wangnov
Wangnov force-pushed the feat/studio-motion-intro branch from 73aab30 to 748b3e6 Compare July 18, 2026 12:54
@Wangnov
Wangnov merged commit db7f07f into main Jul 18, 2026
2 checks passed
@Wangnov
Wangnov deleted the feat/studio-motion-intro branch July 18, 2026 12:55

@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: 73aab30840

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

Comment thread studio/bin/codex-theme.mjs
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