Skip to content

Migrate Demoscene integration from API v2 to v3 - #17

Merged
axisrow merged 2 commits into
mainfrom
ao/axisrow.github.io-8/demoscene-v3
Jul 23, 2026
Merged

Migrate Demoscene integration from API v2 to v3#17
axisrow merged 2 commits into
mainfrom
ao/axisrow.github.io-8/demoscene-v3

Conversation

@axisrow

@axisrow axisrow commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Migrates the runtime Demoscene effects integration from API v2 → API v3 (closes #16).

v3 contract (confirmed against the source)

The demoscene_classics dist already serves an apiVersion: 3 manifest.json from the same base URL (/demoscene_classics/dist, the existing <meta name="demoscene-base"> default). The v3 surface is otherwise unchanged for this site:

  • Top-level manifest fields identical: version (string), apiVersion (number, now 3), bundle (string) — plus a new optional effects[].
  • Factory signature unchanged: Demoscene.<name>(target, options).
  • Skin shape unchanged (runtime / render / motion / appearance / camera / algorithm / field).
  • The three required effects (metaballs, plasma, mandelbrot) are all present in the v3 manifest.

So effect-skins.js and the base URL need no changes — the migration is a client-side contract bump plus a cache-buster.

Changes

  • main.js — hard version gate now requires apiVersion === 3; the "expose the required API effects" error string references v3.
  • index.html — cache-busters on effect-skins.js / main.js bumped api-v2-final → api-v3-final.
  • tests/site-smoke.test.mjs — loader tests drive v3 manifests; the incompatible-version case now uses a v2 manifest to exercise the rejection path.

Tests

  • npm test22/22 pass (node --check main.js && node --check effect-skins.js && node --test).
  • python3 -m unittest discover -s profile/tests41/41 pass (unchanged layer, sanity check).

Manual verification (per issue)

Not run in CI (no browser): load the site → animated accents render (no demoscene-fallback), DevTools shows the v3 manifest fetched and libraryReady = true; pointing demoscene-base at an incompatible manifest → graceful static fallback, no uncaught errors. The loader unit tests cover the success, missing-manifest, incompatible-version, bundle-fail, and missing-effects paths.

Risks / follow-ups

  • A v2 manifest served at the configured base would now be rejected with a static fallback — intended behaviour (the source already serves v3).
  • Browser smoke is deferred to the user; the VM-based loader tests assert the contract paths.

🤖 Generated with Claude Code

The demoscene_classics dist already serves an apiVersion: 3 manifest from
the same base URL, and the v3 factory signature (Demoscene.<name>(target,
options)) and skin shape are unchanged, so the migration is a client-side
contract bump:

- main.js: hard version gate now requires apiVersion === 3; the "expose the
  required API effects" error string references v3.
- index.html: cache-busters on effect-skins.js / main.js bumped from
  api-v2-final to api-v3-final.
- tests: loader tests now drive v3 manifests; the incompatible-version case
  uses the prior v2 manifest to exercise the rejection path.

effect-skins.js is untouched: v3 did not change the option objects it
produces, and the <meta name="demoscene-base"> default still points at a
source serving a v3 manifest + bundle.

Closes #16.

Co-Authored-By: Claude <noreply@anthropic.com>
@axisrow

axisrow commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 1/3)

Reviewed locally (/review + Codex companion, model sol / effort xhigh), no bots pinged. Head 4ef986e.

Verdict Reviewer Finding Location
FIX codex API v3 rejects every effect mount — PR passes the legacy v2 flat-options object as the factory argument, but v3 requires a {skin, surface, device, config} descriptor main.js:89
clean claude No critical issues in the version-gate / cache-buster / string bumps main.js, index.html

FIX detail (confirmed empirically against the real demoscene_classics v3 bundle).
Demoscene.<name>(target, descriptor) changed in v3: src/install.js documents the descriptor { skin, surface, device, config }, and src/resolver.js detectLegacy() throws TypeError on any v2 top-level group (runtime/render/motion/appearance/field/camera/algorithm). The PR calls factory(element, definition.options) where definition.options is exactly such a legacy object, so the first mount throws, loadDemoscene() catches it, and all three animated accents fall back to static rendering — directly breaking the goal of issue #16. The existing runLoader tests miss it because their mock factories are no-ops that never call resolveDescriptor.

Verified empirically by loading dist/demoscene.js in a Node VM:

  • legacy flat options → TypeError: the legacy v2 flat options object is no longer supported in API v3 (reproduces the bug);
  • descriptor {skin:'classic', surface, device:'auto', config:{...}} → passes descriptor validation for metaballs/plasma/mandelbrot.

Fix plan: build a v3 descriptor at the call site and rework effect-skins.js so budgets (runtime/render.resolution) move to the library's profile slots (which v3 now owns), while algorithmic identity (field/camera/algorithm), motion, render.backend (mandelbrot) and appearance travel under config. Surfaces: metaballs=fullscreen, plasma/mandelbrot=preview; device: 'auto'.

Cycle-1 review (Codex, sol/xhigh) caught that bumping the version gate to
v3 was insufficient: Demoscene v3 changed the factory signature to
Demoscene.<name>(target, { skin, surface, device, config }), and the
resolver's detectLegacy() throws TypeError on any legacy v2 top-level
group (runtime/render/motion/field/...). The previous commit passed
factory(element, definition.options) with definition.options being exactly
such a legacy object, so the first mount threw, loadDemoscene() caught it,
and all three animated accents fell back to static rendering — the opposite
of what issue #16 asked for. The runLoader mock factories were no-ops that
never invoked resolveDescriptor, so the regression was invisible to tests.

Verified empirically against the real demoscene_classics dist/demoscene.js:
legacy flat options -> "the legacy v2 flat options object is no longer
supported in API v3"; the descriptor built below passes the resolver gate
for metaballs/plasma/mandelbrot across light/dark x mobile/desktop (12/12).

Changes:
- main.js: assemble a v3 descriptor { skin:'classic', surface, device:'auto',
  config: definition.options } at the factory call site. Each effect
  definition carries its surface (metaballs=fullscreen hero, plasma and
  mandelbrot=preview cards).
- effect-skins.js: drop the execution-budget groups (runtime, render
  resolution/smoothing) that v3 now owns via per-(surface, device) profile
  slots. Skins keep only algorithmic identity (field/camera/algorithm),
  motion identity and the mandelbrot render.backend choice; appearance is
  still attached in create(). device:'auto' lets the library pick mobile vs
  desktop, so the mobile flag now only tunes algorithmic identity.
- tests: add a regression test asserting the descriptor main.js builds is
  accepted by a local mirror of the v3 detectLegacy gate (and that the
  pre-v3 flat-options path is rejected); add a test that skins never carry
  library-owned budget groups; update the budget-dependent assertions to
  the v3 config shape.

npm test: 24/24. python3 -m unittest discover -s profile/tests: 41/41.

Co-Authored-By: Claude <noreply@anthropic.com>
@axisrow

axisrow commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

📋 Review summary — all cycles

Reviewed locally (/review + Codex companion sol/xhigh), no bots pinged. PR head reviewed: 6c29e87.

Cycle Reviewer Finding Verdict Resolution
1 codex API v3 rejects every effect mount — legacy v2 flat-options object passed as the factory descriptor; detectLegacy() throws, all accents fall back to static FIX Fixed in 6c29e87
2 codex — (clean) verdict: approve, 0 findings clean n/a
1–2 claude (/review) No critical issues; version-gate/cache-buster/string bumps and the v3 descriptor all correct clean n/a
2 claude (/review) Note (info, non-blocking): mandelbrot preview card now renders at the library's preview profile resolution (~0.2) instead of the site's former full resolution: 1 — intended v3 behaviour, budgets are library-owned SKIP Left as-is (v3 design)

Totals: 1 FIX (resolved in 6c29e87), 1 SKIP (info), 0 UNVERIFIED.

Verification: npm test 24/24, python3 -m unittest discover -s profile/tests 41/41. The v3 descriptor built by main.js was additionally checked against the real demoscene_classics dist/demoscene.js — 12/12 (effect × theme × device) pass the resolver's descriptor gate.

Local review mode does not merge automatically; merge is yours to trigger (CI is not configured for this repo).

@axisrow
axisrow merged commit 10ad960 into main Jul 23, 2026
1 check passed
@axisrow
axisrow deleted the ao/axisrow.github.io-8/demoscene-v3 branch July 23, 2026 16:03
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.

Migrate Demoscene effects integration from API v2 to v3

1 participant