@vib3code/sdk 2.0.3-canary.75a3290 → 2.0.3-canary.ef8d292

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,10 +19,10 @@ The codebase is complete. The product isn't. You have 95,000+ lines of working e
19
19
  - Creative Tooling (color presets, transitions, post-processing, timeline) — complete
20
20
  - Platform Integrations (React, Vue, Svelte, Figma, Three.js, TouchDesigner, OBS) — code complete
21
21
  - Advanced Features (WebXR, WebGPU Compute, MIDI, AI Presets, OffscreenWorker) — code complete
22
- - MCP Agentic Control (14 tools) — working
22
+ - MCP Agentic Control (36 tools — 14 core + 22 added in Phases 6.5-8) — working
23
23
  - C++ WASM Core with JS fallback — working
24
24
  - Export System (SVG, CSS, Lottie, Shader, Trading Cards, VIB3Package) — working
25
- - 693+ tests passing, 34 test files
25
+ - 1762 tests passing, 77 test files (as of Feb 15, 2026)
26
26
  - 6 CI/CD workflows active
27
27
 
28
28
  **What's not done**: Everything below.
@@ -31,7 +31,7 @@ The SDK provides 3 active visualization systems with shared 6D rotation mathemat
31
31
  | **Core Warp Types** | 3 (Base, Hypersphere, Hypertetrahedron) |
32
32
  | **Total Geometries** | 24 per system (8 base × 3 cores) |
33
33
  | **Canvas Layers** | 5 per system (background, shadow, content, highlight, accent) |
34
- | **MCP Tools** | 12 agent-accessible tools |
34
+ | **MCP Tools** | 36 agent-accessible tools (14 core + 4 Phase 6.5 + 7 Phase 7 + 5 Phase 7.1 + 5 Phase 8 + 1 reactivity) |
35
35
  | **Spatial Input Sources** | 8 (deviceTilt, mouse, gyroscope, gamepad, perspective, programmatic, audio, MIDI) |
36
36
  | **Spatial Profiles** | 6 built-in (cardTilt, wearablePerspective, gameAsset, vjAudioSpatial, uiElement, immersiveXR) |
37
37
  | **Creative Effects** | 14 post-processing effects, 22 color presets, 14 easing functions |
@@ -245,7 +245,7 @@ All rotation parameters: `-6.28` to `6.28` (radians, ±2π)
245
245
 
246
246
  ## MCP Server & Agent Tools
247
247
 
248
- ### Available Tools (12 total)
248
+ ### Available Tools (36 total — see CLAUDE.md for full breakdown by phase)
249
249
 
250
250
  | Tool | Description | Key Parameters |
251
251
  |------|-------------|----------------|
@@ -1,38 +1,119 @@
1
- # WebGPU status and testing requirements
2
-
3
- This document records the current WebGPU backend state, what is implemented, and what is required
4
- to validate it in local development or CI.
5
-
6
- ## Current status
7
- - **Backend scaffold:** `WebGPUBackend` initializes adapter/device, configures the canvas, manages
8
- resize, and supports a clear-pass `renderFrame()` path.
9
- - **Async context creation:** `createRenderContextAsync()` can instantiate WebGPU contexts using
10
- `{ backend: 'webgpu' }`.
11
- - **Resource tracking:** depth textures are registered in the shared `RenderResourceRegistry`.
12
-
13
- ## What is still needed
14
- 1. **Pipeline parity:** implement basic shader pipelines (vertex/fragment) and buffer binding that
15
- match the WebGL backend command flow.
16
- 2. **Command buffer bridge:** map existing render commands to WebGPU render passes.
17
- 3. **Feature gating:** add host-app controls to toggle WebGPU via feature flags.
18
- 4. **Diagnostics:** add per-frame stats and resource delta reporting for WebGPU.
19
-
20
- ## Testing requirements
21
- ### Local smoke test
22
- Prerequisites:
23
- - A browser with WebGPU enabled (Chrome/Edge with `chrome://flags/#enable-unsafe-webgpu`, or a
24
- Chromium build with WebGPU support).
25
- - A device with WebGPU-capable GPU drivers.
26
-
27
- Suggested smoke flow:
28
- 1. Create a canvas and call `createRenderContextAsync(canvas, { backend: 'webgpu' })`.
29
- 2. Call `backend.renderFrame({ clearColor: [0.1, 0.1, 0.2, 1] })` and confirm the canvas clears.
30
- 3. Resize the canvas and ensure the clear pass still succeeds.
31
-
32
- ### CI validation
33
- - WebGPU cannot be reliably validated in headless CI without GPU support.
34
- - CI should instead run WebGL tests and lint/static checks; keep a manual WebGPU smoke checklist.
35
-
36
- ## File locations
37
- - `src/render/backends/WebGPUBackend.js`
38
- - `src/render/index.js` (`createRenderContextAsync`)
1
+ # WebGPU Backend Status
2
+
3
+ **Last updated**: 2026-02-15
4
+
5
+ > Previous version archived at `DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md`.
6
+
7
+ ## Current State: Functional but Not Validated End-to-End
8
+
9
+ The WebGPU backend is **architecturally complete** — real device init, shader compilation, pipeline creation, uniform buffers, render passes. It is not a stub. However, no end-to-end browser validation has confirmed correct pixel output through the WebGPU path.
10
+
11
+ ## What Is Implemented
12
+
13
+ | Component | Status | File |
14
+ |-----------|--------|------|
15
+ | Device/adapter/context init | Done | `src/render/backends/WebGPUBackend.js` (1410 lines) |
16
+ | Canvas configuration + resize | Done | WebGPUBackend.js |
17
+ | WGSL shader module compilation | Done | WebGPUBackend.js `compileShader()` |
18
+ | Fullscreen quad pipeline | Done | WebGPUBackend.js `createFullscreenPipeline()` |
19
+ | Custom geometry pipeline | Done | WebGPUBackend.js `createPipeline()` |
20
+ | Uniform buffer management | Done | WebGPUBackend.js `createCustomUniformBuffer()` / `updateCustomUniforms()` |
21
+ | Fullscreen quad rendering | Done | WebGPUBackend.js `renderFullscreenQuad()` |
22
+ | Geometry rendering | Done | WebGPUBackend.js `renderGeometry()` / `renderWithPipeline()` |
23
+ | Manual render pass control | Done | WebGPUBackend.js `beginRenderPass()` / `endRenderPass()` |
24
+ | Vertex/index buffer creation | Done | WebGPUBackend.js |
25
+ | Texture + sampler creation | Done | WebGPUBackend.js |
26
+ | Resource cleanup | Done | WebGPUBackend.js `dispose()` |
27
+ | WebGL/WebGPU bridge abstraction | Done | `src/render/UnifiedRenderBridge.js` |
28
+ | Uniform packing (JS GPU) | Done | `packVIB3Uniforms()` in UnifiedRenderBridge.js |
29
+ | FacetedSystem WebGPU path | Done | `src/faceted/FacetedSystem.js` `initWithBridge()` |
30
+
31
+ ## WGSL Shader Files
32
+
33
+ All seven WGSL files are real, substantive shaders (not stubs):
34
+
35
+ | File | Lines | Content |
36
+ |------|-------|---------|
37
+ | `src/shaders/common/fullscreen.vert.wgsl` | 18 | Fullscreen triangle vertex shader |
38
+ | `src/shaders/common/uniforms.wgsl` | 49 | Canonical VIB3Uniforms struct definition |
39
+ | `src/shaders/common/rotation4d.wgsl` | 87 | All six 4D rotation matrices + projection |
40
+ | `src/shaders/common/geometry24.wgsl` | 55 | All 24 geometry SDFs |
41
+ | `src/shaders/faceted/faceted.frag.wgsl` | 206 | Complete faceted fragment shader |
42
+ | `src/shaders/quantum/quantum.frag.wgsl` | 362 | Complete quantum fragment shader |
43
+ | `src/shaders/holographic/holographic.frag.wgsl` | 255 | Complete holographic fragment shader |
44
+
45
+ ## Canonical Uniform Struct Layout
46
+
47
+ All WGSL uniform structs **must** match `packVIB3Uniforms()` in `UnifiedRenderBridge.js`. The canonical layout uses only `f32` scalars and one `vec2<f32>` to avoid WGSL alignment surprises:
48
+
49
+ ```wgsl
50
+ struct VIB3Uniforms {
51
+ time: f32, // index 0
52
+ _pad0: f32, // index 1
53
+ resolution: vec2<f32>, // index 2-3
54
+ geometry: f32, // index 4
55
+ rot4dXY: f32, // index 5
56
+ rot4dXZ: f32, // index 6
57
+ rot4dYZ: f32, // index 7
58
+ rot4dXW: f32, // index 8
59
+ rot4dYW: f32, // index 9
60
+ rot4dZW: f32, // index 10
61
+ dimension: f32, // index 11
62
+ gridDensity: f32, // index 12
63
+ morphFactor: f32, // index 13
64
+ chaos: f32, // index 14
65
+ speed: f32, // index 15
66
+ hue: f32, // index 16
67
+ intensity: f32, // index 17
68
+ saturation: f32, // index 18
69
+ mouseIntensity: f32, // index 19
70
+ clickIntensity: f32, // index 20
71
+ bass: f32, // index 21
72
+ mid: f32, // index 22
73
+ high: f32, // index 23
74
+ layerScale: f32, // index 24
75
+ layerOpacity: f32, // index 25
76
+ _pad1: f32, // index 26
77
+ layerColorR: f32, // index 27
78
+ layerColorG: f32, // index 28
79
+ layerColorB: f32, // index 29
80
+ densityMult: f32, // index 30
81
+ speedMult: f32, // index 31
82
+ breath: f32, // index 32
83
+ };
84
+ ```
85
+
86
+ **Rule**: Do NOT use `vec3<f32>` for layerColor — it triggers 16-byte alignment padding that breaks the flat Float32Array packing. Always use three separate f32 fields.
87
+
88
+ ## System Integration
89
+
90
+ | System | WebGPU Path | Notes |
91
+ |--------|-------------|-------|
92
+ | **Faceted** | Single-canvas via UnifiedRenderBridge | Inline WGSL matches canonical layout. Only system with a complete WebGPU path wired in the demo page. |
93
+ | **Quantum** | Multi-canvas via MultiCanvasBridge | Requires 5 separate canvas DOM elements. Falls back to WebGL on `docs/webgpu-live.html` (single canvas). |
94
+ | **Holographic** | Multi-canvas via MultiCanvasBridge | Same 5-canvas requirement. Falls back to WebGL on demo page. |
95
+
96
+ ## Remaining Work
97
+
98
+ 1. **End-to-end browser validation** — Run FacetedSystem through WebGPU in a Chrome/Edge browser with WebGPU enabled and confirm correct visual output matches WebGL.
99
+ 2. **Quantum/Holographic single-canvas path** — Either provide a single-canvas WebGPU fallback or create a demo page with the required 5-canvas DOM structure.
100
+ 3. **Automated smoke test** — A Playwright test (with WebGPU-capable browser) that initializes the bridge, renders one frame, and confirms no errors.
101
+ 4. **Shader sync verification** — Extend `tools/shader-sync-verify.js` to also verify WGSL struct layouts match `packVIB3Uniforms()`.
102
+
103
+ ## Demo Page
104
+
105
+ `docs/webgpu-live.html` — Tries WebGPU for FacetedSystem, always WebGL for Quantum/Holographic. Shows green "WEBGPU" or yellow "WEBGL" badge.
106
+
107
+ ## Testing
108
+
109
+ WebGPU cannot be validated in headless CI without GPU support. Strategy:
110
+ - CI: Run WebGL tests + shader lint + struct layout checks
111
+ - Manual: Smoke test in Chrome/Edge with `chrome://flags/#enable-unsafe-webgpu`
112
+
113
+ ## File Locations
114
+
115
+ - Backend: `src/render/backends/WebGPUBackend.js`
116
+ - Bridge: `src/render/UnifiedRenderBridge.js`
117
+ - Packing: `packVIB3Uniforms()` in UnifiedRenderBridge.js
118
+ - WGSL shaders: `src/shaders/`
119
+ - Demo: `docs/webgpu-live.html`
@@ -0,0 +1,38 @@
1
+ # WebGPU status and testing requirements
2
+
3
+ This document records the current WebGPU backend state, what is implemented, and what is required
4
+ to validate it in local development or CI.
5
+
6
+ ## Current status
7
+ - **Backend scaffold:** `WebGPUBackend` initializes adapter/device, configures the canvas, manages
8
+ resize, and supports a clear-pass `renderFrame()` path.
9
+ - **Async context creation:** `createRenderContextAsync()` can instantiate WebGPU contexts using
10
+ `{ backend: 'webgpu' }`.
11
+ - **Resource tracking:** depth textures are registered in the shared `RenderResourceRegistry`.
12
+
13
+ ## What is still needed
14
+ 1. **Pipeline parity:** implement basic shader pipelines (vertex/fragment) and buffer binding that
15
+ match the WebGL backend command flow.
16
+ 2. **Command buffer bridge:** map existing render commands to WebGPU render passes.
17
+ 3. **Feature gating:** add host-app controls to toggle WebGPU via feature flags.
18
+ 4. **Diagnostics:** add per-frame stats and resource delta reporting for WebGPU.
19
+
20
+ ## Testing requirements
21
+ ### Local smoke test
22
+ Prerequisites:
23
+ - A browser with WebGPU enabled (Chrome/Edge with `chrome://flags/#enable-unsafe-webgpu`, or a
24
+ Chromium build with WebGPU support).
25
+ - A device with WebGPU-capable GPU drivers.
26
+
27
+ Suggested smoke flow:
28
+ 1. Create a canvas and call `createRenderContextAsync(canvas, { backend: 'webgpu' })`.
29
+ 2. Call `backend.renderFrame({ clearColor: [0.1, 0.1, 0.2, 1] })` and confirm the canvas clears.
30
+ 3. Resize the canvas and ensure the clear pass still succeeds.
31
+
32
+ ### CI validation
33
+ - WebGPU cannot be reliably validated in headless CI without GPU support.
34
+ - CI should instead run WebGL tests and lint/static checks; keep a manual WebGPU smoke checklist.
35
+
36
+ ## File locations
37
+ - `src/render/backends/WebGPUBackend.js`
38
+ - `src/render/index.js` (`createRenderContextAsync`)
@@ -0,0 +1,108 @@
1
+ # Development Session — 2026-02-16
2
+
3
+ **Session type**: Architecture Bug Fixes, Shader Consistency, Documentation Sweep
4
+ **Branch**: `claude/vib3-sdk-handoff-p00R8`
5
+ **Operator**: Claude Code (Opus 4.6)
6
+ **Parent work**: Continues from Feb 15 layer architecture + codebase audit
7
+
8
+ ---
9
+
10
+ ## Session Overview
11
+
12
+ ### Phase 1 — Bug Fixes & Geometry Differentiation (committed in `7debad8`)
13
+
14
+ - Fixed QuantumVisualizer `canvasId` reference error — 6 sites used undefined variable, replaced with `this._canvasLabel`
15
+ - Differentiated tetrahedron lattice (geometry 0) from hypercube (geometry 1) using tetrahedral symmetry planes in GLSL + WGSL
16
+ - Updated CLAUDE.md geometry docs: "24 geometries" → "24 geometry variants (8 base shapes × 3 warp modes)"
17
+
18
+ ### Phase 2 — Shader Module Infrastructure (committed in `7debad8`)
19
+
20
+ - Added `resolveIncludes()` and `loadAndResolve()` to `src/render/ShaderLoader.js` for `#include` / `// @include` directive resolution
21
+ - Added warp functions (`warpHypersphereCore`, `warpHypertetraCore`, `applyCoreWarp`) to external `geometry24.glsl` and `geometry24.wgsl`
22
+
23
+ ### Phase 3.1 — Holographic Uniform Standardization (committed in `7debad8`)
24
+
25
+ - Renamed shader uniforms: `u_density` → `u_gridDensity`, `u_morph` → `u_morphFactor`, `u_geometryType` → `u_geometry`
26
+ - Updated JS uniform location lookups to match
27
+
28
+ ### Phase 3.3 — Quantum Layer Detection Bug Fix (committed in `5e1b4c5`)
29
+
30
+ - **Bug**: Shader float comparison values didn't match JS `roleIntensities`. Only background (fallthrough) and content (1.0) worked; shadow, highlight, accent were broken.
31
+ - **Fix**: Aligned shader values to match JS (0.6, 1.0, 1.3, 1.6), added epsilon comparison (`abs() < 0.05`), moved roleIntensities to module-scope `ROLE_INTENSITIES` constant.
32
+
33
+ ### Phase 3.2 — Remove mapParameterName() (committed in `9d73627`)
34
+
35
+ - Renamed `generateVariantParams()` return keys: `geometryType`→`geometry`, `density`→`gridDensity`, `morph`→`morphFactor`
36
+ - Renamed `geometryConfigs` object keys to match
37
+ - Updated `generateRoleParams()` to use `vp.gridDensity`
38
+ - Updated uniform location map keys to match SDK names directly
39
+ - Consolidated duplicate geometry uniform set in render()
40
+ - Deleted `mapParameterName()` method
41
+ - Removed debug `console.log` from density scaling
42
+
43
+ ### Phase 2.3 — rotateXZ Sign Convention Alignment (committed in `3198645`)
44
+
45
+ - **Discovery**: External shader files (ShaderLib, rotation4d.glsl/wgsl, WebGPUBackend, WebGPURenderer.ts) had opposite sign convention for `rotateXZ` compared to all 3 inline system shaders
46
+ - **Fix**: Aligned all external/shared sources to match the inline (working) convention: `col0=(c,0,s,0)`, `col2=(-s,0,c,0)`
47
+ - 7 files fixed: ShaderProgram.js, WebGPUBackend.js, rotation4d.glsl, rotation4d.wgsl, quantum.frag.wgsl, holographic.frag.wgsl, WebGPURenderer.ts
48
+
49
+ ### Phase 5 — Documentation Updates
50
+
51
+ - SYSTEM_INVENTORY.md: "12 MCP tools" → "36 agent-accessible tools"
52
+ - MASTER_PLAN: "14 tools" → "36 tools", "693+ tests" → "1762 tests"
53
+ - CLAUDE.md: Updated doc map staleness notes, added Feb 16 shipped items, added session work section
54
+
55
+ ---
56
+
57
+ ## Files Modified
58
+
59
+ | File | Changes |
60
+ |---|---|
61
+ | `src/quantum/QuantumVisualizer.js` | canvasId bug fix, layer detection epsilon fix, ROLE_INTENSITIES constant |
62
+ | `src/faceted/FacetedSystem.js` | Tetrahedron lattice differentiation (GLSL + WGSL) |
63
+ | `src/holograms/HolographicVisualizer.js` | Uniform rename, mapParameterName removal, variantParams key rename |
64
+ | `src/render/ShaderLoader.js` | resolveIncludes(), loadAndResolve() |
65
+ | `src/render/ShaderProgram.js` | ShaderLib rotateXZ sign fix |
66
+ | `src/render/backends/WebGPUBackend.js` | rotateXZ sign fix |
67
+ | `src/shaders/common/rotation4d.glsl` | rotateXZ sign fix |
68
+ | `src/shaders/common/rotation4d.wgsl` | rotateXZ sign fix |
69
+ | `src/shaders/common/geometry24.glsl` | Added warp functions |
70
+ | `src/shaders/common/geometry24.wgsl` | Added warp functions |
71
+ | `src/shaders/faceted/faceted.frag.wgsl` | Tetrahedron differentiation, struct fixes |
72
+ | `src/shaders/quantum/quantum.frag.wgsl` | rotateXZ sign fix |
73
+ | `src/shaders/holographic/holographic.frag.wgsl` | rotateXZ sign fix |
74
+ | `src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts` | rotateXZ sign fix |
75
+ | `CLAUDE.md` | Geometry docs, shipped items, session work, doc map notes |
76
+ | `DOCS/SYSTEM_INVENTORY.md` | Tool count 12 → 36 |
77
+ | `DOCS/MASTER_PLAN_2026-01-31.md` | Tool count 14 → 36, test count 693 → 1762 |
78
+ | `tools/shader-sync-verify.js` | Fixed stale Holographic uniforms (u_density→u_gridDensity, removed u_geometryType, u_morph→u_morphFactor), added missing Faceted uniforms (u_mouse, u_roleIntensity), updated comments |
79
+
80
+ ---
81
+
82
+ ## Commits
83
+
84
+ | Hash | Message |
85
+ |---|---|
86
+ | `7debad8` | refactor: Phase 1-3 architecture fixes — bugs, shader modules, uniform standardization |
87
+ | `5e1b4c5` | fix(quantum): align layer detection values with JS roleIntensities |
88
+ | `9d73627` | refactor(holographic): remove mapParameterName() translation layer |
89
+ | `3198645` | fix(shaders): align rotateXZ sign convention across all shader sources |
90
+ | `2ce407d` | docs: update stale tool/test counts, add Feb 16 dev track |
91
+ | (pending) | fix(tools): update stale embedded shaders in shader-sync-verify.js |
92
+
93
+ ---
94
+
95
+ ## Test Results
96
+
97
+ - **Before**: 1762 tests, 77 files (all passing)
98
+ - **After**: 1762 tests, 77 files (all passing)
99
+ - No new tests added this session (bug fixes and refactoring of existing code)
100
+
101
+ ## Decisions Made
102
+
103
+ 1. **Keep per-system color personality** — Quantum's hue normalization (0-1 in JS) is intentional, not a bug
104
+ 2. **Keep role-intensity layer detection** — User wants layer relations to follow 4D rotation principles; used epsilon comparison instead of integer indices
105
+ 3. **Dropped GeometryPresets phase** — VariationManager already implements 100-slot preset system
106
+ 4. **Dropped FrameBudget phase** — Adaptive rendering infrastructure exists in `src/ui/adaptive/`
107
+ 5. **Dropped context loss recovery phase** — Already properly implemented in both QuantumVisualizer and HolographicVisualizer
108
+ 6. **rotateXZ convention** — Aligned all external files to match inline (working) convention rather than vice versa
@@ -477,7 +477,7 @@
477
477
 
478
478
  // Render active system
479
479
  if (activeSystem === 'faceted' && faceted) {
480
- faceted.renderFrame();
480
+ faceted.render();
481
481
  } else if (activeSystem === 'quantum' && quantum) {
482
482
  quantum.render();
483
483
  } else if (activeSystem === 'holographic' && holographic) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vib3code/sdk",
3
- "version": "2.0.3-canary.75a3290",
3
+ "version": "2.0.3-canary.ef8d292",
4
4
  "description": "VIB3+ 4D Visualization SDK - Unified engine with 6D rotation, MCP agentic integration, and cross-platform support",
5
5
  "type": "module",
6
6
  "main": "src/core/VIB3Engine.js",
@@ -9,6 +9,8 @@ import { telemetry, EventType, withTelemetry } from '../telemetry/index.js';
9
9
  import { AestheticMapper } from '../../creative/AestheticMapper.js';
10
10
  import { ChoreographyPlayer } from '../../creative/ChoreographyPlayer.js';
11
11
  import { ParameterTimeline } from '../../creative/ParameterTimeline.js';
12
+ import { ColorPresetsSystem } from '../../creative/ColorPresetsSystem.js';
13
+ import { TransitionAnimator } from '../../creative/TransitionAnimator.js';
12
14
  import { PRESET_REGISTRY } from '../../render/LayerRelationshipGraph.js';
13
15
 
14
16
  /**
@@ -42,6 +44,36 @@ export class MCPServer {
42
44
  this.engine = engine;
43
45
  this.sceneId = null;
44
46
  this.initialized = false;
47
+ this._gallerySlots = new Map();
48
+ }
49
+
50
+ /**
51
+ * Get or lazily create ColorPresetsSystem instance.
52
+ * Requires engine for the parameter update callback.
53
+ * @returns {ColorPresetsSystem|null}
54
+ */
55
+ _getColorPresets() {
56
+ if (this._colorPresets) return this._colorPresets;
57
+ if (!this.engine) return null;
58
+ this._colorPresets = new ColorPresetsSystem(
59
+ (name, value) => this.engine.setParameter(name, value)
60
+ );
61
+ return this._colorPresets;
62
+ }
63
+
64
+ /**
65
+ * Get or lazily create TransitionAnimator instance.
66
+ * Requires engine for the parameter update/get callbacks.
67
+ * @returns {TransitionAnimator|null}
68
+ */
69
+ _getTransitionAnimator() {
70
+ if (this._transitionAnimator) return this._transitionAnimator;
71
+ if (!this.engine) return null;
72
+ this._transitionAnimator = new TransitionAnimator(
73
+ (name, value) => this.engine.setParameter(name, value),
74
+ (name) => this.engine.getParameter(name)
75
+ );
76
+ return this._transitionAnimator;
45
77
  }
46
78
 
47
79
  buildResponse(operation, data, options = {}) {
@@ -484,32 +516,68 @@ export class MCPServer {
484
516
 
485
517
  telemetry.recordEvent(EventType.GALLERY_SAVE, { slot });
486
518
 
519
+ // Persist actual engine state if available
520
+ if (this.engine) {
521
+ const state = this.engine.exportState();
522
+ this._gallerySlots.set(slot, {
523
+ name: name || `Variation ${slot}`,
524
+ saved_at: new Date().toISOString(),
525
+ state
526
+ });
527
+ }
528
+
487
529
  return {
488
530
  slot,
489
531
  name: name || `Variation ${slot}`,
490
532
  saved_at: new Date().toISOString(),
533
+ persisted: !!this.engine,
534
+ gallery_size: this._gallerySlots.size,
491
535
  suggested_next_actions: ['load_from_gallery', 'randomize_parameters']
492
536
  };
493
537
  }
494
538
 
495
539
  /**
496
- * Load from gallery
540
+ * Load from gallery — restores previously saved state
497
541
  */
498
542
  loadFromGallery(args) {
499
543
  const { slot } = args;
500
544
 
501
- if (this.engine) {
502
- // Apply variation
503
- const params = this.engine.parameters?.generateVariationParameters?.(slot) || {};
504
- this.engine.setParameters(params);
545
+ telemetry.recordEvent(EventType.GALLERY_LOAD, { slot });
546
+
547
+ const saved = this._gallerySlots.get(slot);
548
+ if (saved && this.engine) {
549
+ // Restore saved state
550
+ this.engine.importState(saved.state);
551
+ return {
552
+ slot,
553
+ name: saved.name,
554
+ saved_at: saved.saved_at,
555
+ loaded_at: new Date().toISOString(),
556
+ restored: true,
557
+ ...this.getState()
558
+ };
505
559
  }
506
560
 
507
- telemetry.recordEvent(EventType.GALLERY_LOAD, { slot });
561
+ if (!saved) {
562
+ // No saved state — fall back to random variation
563
+ if (this.engine) {
564
+ const params = this.engine.parameters?.generateVariationParameters?.(slot) || {};
565
+ this.engine.setParameters(params);
566
+ }
567
+ return {
568
+ slot,
569
+ loaded_at: new Date().toISOString(),
570
+ restored: false,
571
+ note: 'No saved state in this slot — generated random variation',
572
+ ...this.getState()
573
+ };
574
+ }
508
575
 
509
576
  return {
510
577
  slot,
511
578
  loaded_at: new Date().toISOString(),
512
- ...this.getState()
579
+ restored: false,
580
+ note: 'Engine not initialized — cannot apply state'
513
581
  };
514
582
  }
515
583
 
@@ -1217,8 +1285,17 @@ export class MCPServer {
1217
1285
  (sum, step) => sum + step.duration + step.delay, 0
1218
1286
  );
1219
1287
 
1288
+ // Execute live if engine available
1289
+ let executing = false;
1290
+ const animator = this._getTransitionAnimator();
1291
+ if (animator) {
1292
+ const seqId = animator.sequence(normalizedSequence);
1293
+ executing = !!seqId;
1294
+ }
1295
+
1220
1296
  return {
1221
1297
  transition_id: transitionId,
1298
+ executing,
1222
1299
  step_count: normalizedSequence.length,
1223
1300
  total_duration_ms: totalDuration,
1224
1301
  steps: normalizedSequence.map((step, i) => ({
@@ -1228,7 +1305,7 @@ export class MCPServer {
1228
1305
  easing: step.easing,
1229
1306
  delay: step.delay
1230
1307
  })),
1231
- load_code: `const animator = new TransitionAnimator(\n (n, v) => engine.setParameter(n, v),\n (n) => engine.getParameter(n)\n);\nanimator.sequence(${JSON.stringify(normalizedSequence)});`,
1308
+ load_code: executing ? null : `const animator = new TransitionAnimator(\n (n, v) => engine.setParameter(n, v),\n (n) => engine.getParameter(n)\n);\nanimator.sequence(${JSON.stringify(normalizedSequence)});`,
1232
1309
  suggested_next_actions: ['describe_visual_state', 'create_timeline', 'save_to_gallery']
1233
1310
  };
1234
1311
  }
@@ -1237,55 +1314,41 @@ export class MCPServer {
1237
1314
  * Apply a named color preset
1238
1315
  */
1239
1316
  applyColorPreset(args) {
1240
- const { preset } = args;
1317
+ const { preset, transition = true, duration = 800 } = args;
1241
1318
 
1242
- // Color preset hue/saturation mappings (subset — full list in ColorPresetsSystem)
1243
- const COLOR_PRESETS = {
1244
- Ocean: { hue: 200, saturation: 0.8, intensity: 0.6 },
1245
- Lava: { hue: 15, saturation: 0.9, intensity: 0.8 },
1246
- Neon: { hue: 300, saturation: 1.0, intensity: 0.9 },
1247
- Monochrome: { hue: 0, saturation: 0.0, intensity: 0.6 },
1248
- Sunset: { hue: 30, saturation: 0.85, intensity: 0.7 },
1249
- Aurora: { hue: 140, saturation: 0.7, intensity: 0.6 },
1250
- Cyberpunk: { hue: 280, saturation: 0.9, intensity: 0.8 },
1251
- Forest: { hue: 120, saturation: 0.6, intensity: 0.5 },
1252
- Desert: { hue: 40, saturation: 0.5, intensity: 0.7 },
1253
- Galaxy: { hue: 260, saturation: 0.8, intensity: 0.4 },
1254
- Ice: { hue: 190, saturation: 0.5, intensity: 0.8 },
1255
- Fire: { hue: 10, saturation: 1.0, intensity: 0.9 },
1256
- Toxic: { hue: 100, saturation: 0.9, intensity: 0.7 },
1257
- Royal: { hue: 270, saturation: 0.7, intensity: 0.5 },
1258
- Pastel: { hue: 330, saturation: 0.3, intensity: 0.8 },
1259
- Retro: { hue: 50, saturation: 0.7, intensity: 0.6 },
1260
- Midnight: { hue: 240, saturation: 0.6, intensity: 0.3 },
1261
- Tropical: { hue: 160, saturation: 0.8, intensity: 0.7 },
1262
- Ethereal: { hue: 220, saturation: 0.4, intensity: 0.7 },
1263
- Volcanic: { hue: 5, saturation: 0.95, intensity: 0.6 },
1264
- Holographic: { hue: 180, saturation: 0.6, intensity: 0.8 },
1265
- Vaporwave: { hue: 310, saturation: 0.7, intensity: 0.7 }
1266
- };
1319
+ const colorSystem = this._getColorPresets();
1320
+
1321
+ if (colorSystem) {
1322
+ // Use real ColorPresetsSystem full preset library with transitions
1323
+ const config = colorSystem.getPreset(preset);
1324
+ if (!config) {
1325
+ const allPresets = colorSystem.getPresets().map(p => p.name);
1326
+ return {
1327
+ error: {
1328
+ type: 'ValidationError',
1329
+ code: 'INVALID_COLOR_PRESET',
1330
+ message: `Unknown color preset: ${preset}`,
1331
+ valid_options: allPresets
1332
+ }
1333
+ };
1334
+ }
1335
+
1336
+ colorSystem.applyPreset(preset, transition, duration);
1267
1337
 
1268
- const presetData = COLOR_PRESETS[preset];
1269
- if (!presetData) {
1270
1338
  return {
1271
- error: {
1272
- type: 'ValidationError',
1273
- code: 'INVALID_COLOR_PRESET',
1274
- message: `Unknown color preset: ${preset}`,
1275
- valid_options: Object.keys(COLOR_PRESETS)
1276
- }
1339
+ preset,
1340
+ applied: { hue: config.hue, saturation: config.saturation, intensity: config.intensity },
1341
+ transition: transition ? { enabled: true, duration } : { enabled: false },
1342
+ full_config: config,
1343
+ suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
1277
1344
  };
1278
1345
  }
1279
1346
 
1280
- if (this.engine) {
1281
- this.engine.setParameter('hue', presetData.hue);
1282
- this.engine.setParameter('saturation', presetData.saturation);
1283
- this.engine.setParameter('intensity', presetData.intensity);
1284
- }
1285
-
1347
+ // Fallback: no engine, return preset metadata for artifact mode
1286
1348
  return {
1287
1349
  preset,
1288
- applied: presetData,
1350
+ applied: null,
1351
+ load_code: `const colors = new ColorPresetsSystem((n, v) => engine.setParameter(n, v));\ncolors.applyPreset('${preset}', ${transition}, ${duration});`,
1289
1352
  suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
1290
1353
  };
1291
1354
  }
@@ -1296,14 +1359,50 @@ export class MCPServer {
1296
1359
  setPostProcessing(args) {
1297
1360
  const { effects, chain_preset, clear_first = true } = args;
1298
1361
 
1362
+ // Try to execute live in browser context
1363
+ let executing = false;
1364
+ if (typeof document !== 'undefined') {
1365
+ try {
1366
+ const target = document.getElementById('viz-container')
1367
+ || document.querySelector('.vib3-container')
1368
+ || document.querySelector('canvas')?.parentElement;
1369
+
1370
+ if (target) {
1371
+ // Lazy-init pipeline, importing dynamically to avoid Node.js issues
1372
+ if (!this._postPipeline) {
1373
+ // PostProcessingPipeline imported statically would fail in Node;
1374
+ // it's already a known browser-only module, so guard at runtime
1375
+ const { PostProcessingPipeline: PPP } = { PostProcessingPipeline: globalThis.PostProcessingPipeline };
1376
+ if (PPP) {
1377
+ this._postPipeline = new PPP(target);
1378
+ }
1379
+ }
1380
+
1381
+ if (this._postPipeline) {
1382
+ if (clear_first) this._postPipeline.clearChain?.();
1383
+ if (chain_preset) {
1384
+ this._postPipeline.loadPresetChain(chain_preset);
1385
+ } else if (effects) {
1386
+ for (const e of effects) {
1387
+ this._postPipeline.addEffect(e.name, { intensity: e.intensity || 0.5, ...e });
1388
+ }
1389
+ }
1390
+ this._postPipeline.apply();
1391
+ executing = true;
1392
+ }
1393
+ }
1394
+ } catch { /* fall through to code generation */ }
1395
+ }
1396
+
1299
1397
  return {
1300
1398
  applied: true,
1399
+ executing,
1301
1400
  effects: effects || [],
1302
1401
  chain_preset: chain_preset || null,
1303
1402
  cleared_previous: clear_first,
1304
- load_code: effects ?
1305
- `const pipeline = new PostProcessingPipeline(gl, canvas);\n${effects.map(e => `pipeline.addEffect('${e.name}', { intensity: ${e.intensity || 0.5} });`).join('\n')}` :
1306
- `pipeline.applyChain('${chain_preset}');`,
1403
+ load_code: executing ? null : (effects ?
1404
+ `const pipeline = new PostProcessingPipeline(document.getElementById('viz-container'));\n${effects.map(e => `pipeline.addEffect('${e.name}', { intensity: ${e.intensity || 0.5} });`).join('\n')}\npipeline.apply();` :
1405
+ `const pipeline = new PostProcessingPipeline(document.getElementById('viz-container'));\npipeline.loadPresetChain('${chain_preset}');\npipeline.apply();`),
1307
1406
  suggested_next_actions: ['describe_visual_state', 'apply_color_preset', 'create_choreography']
1308
1407
  };
1309
1408
  }