@vib3code/sdk 2.0.3-canary.60bc0f0 → 2.0.3-canary.74aebb4

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.
Files changed (44) hide show
  1. package/DOCS/EXPANSION_DESIGN.md +977 -0
  2. package/DOCS/EXPANSION_DESIGN_ULTRA.md +387 -0
  3. package/DOCS/MASTER_PLAN_2026-01-31.md +2 -2
  4. package/DOCS/OPTIMIZATION_PLAN_MATH.md +118 -0
  5. package/DOCS/SYSTEM_INVENTORY.md +2 -2
  6. package/DOCS/WEBGPU_STATUS.md +119 -38
  7. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +38 -0
  8. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +108 -0
  9. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +308 -0
  10. package/docs/webgpu-live.html +1 -1
  11. package/package.json +1 -1
  12. package/src/agent/mcp/MCPServer.js +195 -136
  13. package/src/agent/mcp/tools.js +45 -32
  14. package/src/experimental/GameLoop.js +72 -0
  15. package/src/experimental/LatticePhysics.js +100 -0
  16. package/src/experimental/LiveDirector.js +143 -0
  17. package/src/experimental/PlayerController4D.js +154 -0
  18. package/src/experimental/VIB3Actor.js +138 -0
  19. package/src/experimental/VIB3Compositor.js +117 -0
  20. package/src/experimental/VIB3Link.js +122 -0
  21. package/src/experimental/VIB3Orchestrator.js +146 -0
  22. package/src/experimental/VIB3Universe.js +109 -0
  23. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  24. package/src/faceted/FacetedSystem.js +19 -6
  25. package/src/geometry/generators/Crystal.js +2 -2
  26. package/src/holograms/HolographicVisualizer.js +58 -89
  27. package/src/math/Mat4x4.js +122 -6
  28. package/src/math/Rotor4D.js +93 -39
  29. package/src/math/Vec4.js +119 -78
  30. package/src/quantum/QuantumVisualizer.js +24 -20
  31. package/src/render/ShaderLoader.js +38 -0
  32. package/src/render/ShaderProgram.js +4 -4
  33. package/src/render/UnifiedRenderBridge.js +1 -1
  34. package/src/render/backends/WebGPUBackend.js +8 -4
  35. package/src/shaders/common/geometry24.glsl +65 -0
  36. package/src/shaders/common/geometry24.wgsl +54 -0
  37. package/src/shaders/common/rotation4d.glsl +4 -4
  38. package/src/shaders/common/rotation4d.wgsl +2 -2
  39. package/src/shaders/common/uniforms.wgsl +15 -8
  40. package/src/shaders/faceted/faceted.frag.wgsl +19 -6
  41. package/src/shaders/holographic/holographic.frag.wgsl +7 -5
  42. package/src/shaders/quantum/quantum.frag.wgsl +7 -5
  43. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  44. package/tools/shader-sync-verify.js +6 -4
@@ -0,0 +1,977 @@
1
+ # VIB3+ Premium Tier — Expansion Design Document
2
+
3
+ **Purpose**: Technical specification for `@vib3code/premium`, a separate npm package that extends the free `@vib3code/sdk` with fine-grained shader control, axis locking, per-layer geometry, event-triggered state changes, and live CSS/framework integration.
4
+
5
+ **Status**: Design document. No code implemented yet.
6
+ **Date**: Feb 16, 2026
7
+ **Based on**: Deep analysis of all shader GLSL, layer system, event architecture, and licensing model in the free SDK.
8
+
9
+ ---
10
+
11
+ ## Architecture Overview
12
+
13
+ ### Package Relationship
14
+
15
+ ```
16
+ @vib3code/sdk (free, MIT) @vib3code/premium (paid)
17
+ ┌──────────────────────────┐ ┌──────────────────────────┐
18
+ │ VIB3Engine │◄──────│ enablePremium(engine) │
19
+ │ 3 visualization systems │ │ │
20
+ │ 24 geometries │ │ ShaderParameterSurface │
21
+ │ LayerRelationshipGraph │ │ RotationLockSystem │
22
+ │ ChoreographyPlayer │ │ LayerGeometryMixer │
23
+ │ TransitionAnimator │ │ VisualEventSystem │
24
+ │ ColorPresetsSystem │ │ CSSBridge │
25
+ │ AestheticMapper │ │ ChoreographyExtensions │
26
+ │ 14 core MCP tools │ │ FrameworkSync │
27
+ │ ReactivityManager │ │ 8+ premium MCP tools │
28
+ │ SpatialInputSystem │ │ │
29
+ │ onParameterChange() │ │ PremiumMCPServer │
30
+ └──────────────────────────┘ └──────────────────────────┘
31
+ ```
32
+
33
+ Premium imports from free SDK as a **peer dependency**. Free SDK never imports from premium. One-directional dependency.
34
+
35
+ ### How Premium Wraps the Engine
36
+
37
+ ```javascript
38
+ import { VIB3Engine } from '@vib3code/sdk';
39
+ import { enablePremium } from '@vib3code/premium';
40
+
41
+ const engine = new VIB3Engine({ system: 'holographic' });
42
+ await engine.initialize(container);
43
+
44
+ const premium = enablePremium(engine, {
45
+ licenseKey: 'VIB3-PRO-xxxx-xxxx',
46
+ features: ['all'] // or specific: ['shaderSurface', 'rotationLock', 'events']
47
+ });
48
+
49
+ // Premium modules are now active
50
+ premium.shaderSurface.setParameter('projectionType', 1);
51
+ premium.rotationLock.setFlightMode(true);
52
+ premium.events.addTrigger('bass_drop', { ... });
53
+ premium.cssBridge.start({ target: document.documentElement });
54
+ ```
55
+
56
+ ### Public API Surface
57
+
58
+ ```javascript
59
+ // enablePremium() returns:
60
+ {
61
+ shaderSurface: ShaderParameterSurface,
62
+ rotationLock: RotationLockSystem,
63
+ layerGeometry: LayerGeometryMixer,
64
+ events: VisualEventSystem,
65
+ cssBridge: CSSBridge,
66
+ choreography: ChoreographyExtensions,
67
+ frameworkSync: FrameworkSync,
68
+ mcp: PremiumMCPServer,
69
+ destroy(): void
70
+ }
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Module 1: ShaderParameterSurface
76
+
77
+ **File**: `src/ShaderParameterSurface.js`
78
+ **Purpose**: Exposes 8 hardcoded shader values as controllable parameters.
79
+
80
+ ### What's Currently Hardcoded (from shader analysis)
81
+
82
+ | Value | Where in GLSL | Current Value | Why It Should Be a Parameter |
83
+ |-------|--------------|---------------|------------------------------|
84
+ | Projection distance | `float w = 2.5 / (2.5 + p.w)` | 2.5 | `u_dimension` is supposed to control this but doesn't. This fix alone unlocks the `dimension` parameter |
85
+ | Projection type | Only perspective exists | 0 | Stereographic (`xyz / (1-w)`) and orthographic (`xyz`) are documented in CLAUDE.md but never implemented |
86
+ | UV scale | `uv * 3.0` | 3.0 | Controls zoom into 4D space. Different scales reveal different pattern features |
87
+ | Smoothstep threshold | `smoothstep(0.03, 0.04, ...)` | ~0.03 | Controls wireframe line thickness. Dramatic visual difference between 0.005 and 0.15 |
88
+ | Chaos noise frequencies | `sin(x*7)*cos(y*11)*sin(z*13)` | (7, 11, 13) | Different prime triples create different noise textures |
89
+ | Breath modulation strength | `1.0 + breath * 0.3` / `0.4` / `0.5` | Varies per system | Should be unified and controllable |
90
+ | Holographic auto-rotation speeds | `time * 0.1`, `0.12`, `0.08`, `0.2`, `0.15`, `0.25` | Per-axis | Currently only Holographic has auto-rotation; these speeds are hardcoded |
91
+ | Quantum particle size | `step(0.2, ...)` / `step(0.1, ...)` | 0.2 / 0.1 per layer | Controls particle dot size in Quantum system |
92
+
93
+ ### API
94
+
95
+ ```javascript
96
+ class ShaderParameterSurface {
97
+ constructor(engine) { }
98
+
99
+ // Set a shader parameter (validates range, forwards to active system)
100
+ setParameter(name, value): void
101
+ getParameter(name): number | number[]
102
+ getParameterSchema(): Object // JSON Schema for all shader params
103
+
104
+ // Batch set
105
+ setParameters(params: Object): void
106
+
107
+ // Reset to defaults
108
+ reset(): void
109
+
110
+ // Supported parameters:
111
+ // 'projectionType' - int 0-2 (perspective/stereographic/orthographic)
112
+ // 'uvScale' - float 1.0-8.0
113
+ // 'lineThickness' - float 0.005-0.15
114
+ // 'noiseFrequency' - [float, float, float] each 1-50
115
+ // 'breathStrength' - float 0-1
116
+ // 'autoRotationSpeed' - [float x6] each 0-0.5 (XY,XZ,YZ,XW,YW,ZW)
117
+ // 'particleSize' - float 0.02-0.5
118
+ // 'layerAlpha' - { background, shadow, content, highlight, accent } each 0-1
119
+ }
120
+ ```
121
+
122
+ ### Implementation Strategy
123
+
124
+ This module wraps `engine.onParameterChange()` to intercept render updates. When a shader parameter is set, it modifies the GLSL shader strings dynamically (replacing hardcoded values with the new values) or — more practically — patches the system's `_buildUniforms()` method to include the new uniforms.
125
+
126
+ **Approach A (preferred)**: Add uniform declarations to each system's shader source. The shader code already has `#define`-like patterns we can augment. Add `uniform float u_uvScale;`, etc. and change `uv * 3.0` to `uv * u_uvScale`. This requires modifying the free SDK's shader strings — we'd submit PRs upstream for the uniform declarations (keeping defaults identical) and the premium module sends the actual values.
127
+
128
+ **Approach B (no-upstream-change)**: Use WebGL `uniform` injection post-compilation. After the free SDK compiles its shader, premium locates the uniform locations and sets them. This only works for uniforms already declared — so it doesn't help with adding NEW uniforms. Less clean but zero upstream changes.
129
+
130
+ **Recommended**: Approach A. Submit a PR to the free SDK that adds the uniform declarations with default values matching the current hardcoded values. This is a **no-behavior-change** PR. Then the premium module sends the actual configurable values.
131
+
132
+ ### MCP Tool
133
+
134
+ ```javascript
135
+ {
136
+ name: 'set_shader_parameter',
137
+ description: 'Set fine-grained shader parameters (premium)',
138
+ inputSchema: {
139
+ type: 'object',
140
+ properties: {
141
+ projectionType: { type: 'integer', minimum: 0, maximum: 2 },
142
+ uvScale: { type: 'number', minimum: 1.0, maximum: 8.0 },
143
+ lineThickness: { type: 'number', minimum: 0.005, maximum: 0.15 },
144
+ noiseFrequency: { type: 'array', items: { type: 'number' }, minItems: 3, maxItems: 3 },
145
+ breathStrength: { type: 'number', minimum: 0, maximum: 1 },
146
+ autoRotationSpeed: { type: 'array', items: { type: 'number' }, minItems: 6, maxItems: 6 },
147
+ particleSize: { type: 'number', minimum: 0.02, maximum: 0.5 },
148
+ layerAlpha: { type: 'object' }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Module 2: RotationLockSystem
157
+
158
+ **File**: `src/RotationLockSystem.js`
159
+ **Purpose**: Lock rotation axes at fixed values and provide "flight mode" — stable screen orientation while 4D content streams past.
160
+
161
+ ### Why This Matters
162
+
163
+ When an agent animates `rot4dXW` to create a "portal" effect, other inputs (audio reactivity, spatial input, user interaction) can also change `rot4dXY`/`rot4dXZ`/`rot4dYZ`, causing the screen-plane orientation to drift. Axis locking prevents this — the portal effect stays clean.
164
+
165
+ "Flight mode" is a preset: lock all 3D rotations (XY/XZ/YZ) at their current values, leaving 4D rotations (XW/YW/ZW) free. The result: the viewport is stable, and 4D geometry "flies through" it as hyperspace rotations are animated.
166
+
167
+ ### API
168
+
169
+ ```javascript
170
+ class RotationLockSystem {
171
+ constructor(engine) { }
172
+
173
+ // Lock a specific axis at current value or specified value
174
+ lockAxis(axisName: string, value?: number): void
175
+ // axisName: 'rot4dXY' | 'rot4dXZ' | 'rot4dYZ' | 'rot4dXW' | 'rot4dYW' | 'rot4dZW'
176
+
177
+ // Unlock a specific axis
178
+ unlockAxis(axisName: string): void
179
+
180
+ // Lock all 3D rotations, free all 4D rotations
181
+ setFlightMode(enabled: boolean): void
182
+
183
+ // Get lock state
184
+ isLocked(axisName: string): boolean
185
+ getLockedValue(axisName: string): number | null
186
+ getLockedAxes(): string[]
187
+
188
+ // Convenience: lock all axes
189
+ lockAll(values?: Object): void
190
+ unlockAll(): void
191
+
192
+ destroy(): void
193
+ }
194
+ ```
195
+
196
+ ### Implementation
197
+
198
+ Intercepts `engine.setParameter()` by wrapping it:
199
+
200
+ ```javascript
201
+ const originalSetParameter = engine.setParameter.bind(engine);
202
+ engine.setParameter = (name, value) => {
203
+ if (this._locks.has(name)) {
204
+ // Silently ignore — axis is locked
205
+ return;
206
+ }
207
+ originalSetParameter(name, value);
208
+ };
209
+ ```
210
+
211
+ Also intercepts `engine.updateCurrentSystemParameters()` to enforce locked values:
212
+
213
+ ```javascript
214
+ const originalUpdate = engine.updateCurrentSystemParameters.bind(engine);
215
+ engine.updateCurrentSystemParameters = () => {
216
+ // Override locked axes in the parameter manager before update
217
+ for (const [axis, lockedValue] of this._locks) {
218
+ engine.parameters.setParameter(axis, lockedValue);
219
+ }
220
+ originalUpdate();
221
+ };
222
+ ```
223
+
224
+ ### MCP Tool
225
+
226
+ ```javascript
227
+ {
228
+ name: 'set_rotation_lock',
229
+ description: 'Lock or unlock rotation axes. Use flight mode to lock 3D rotations while 4D rotates freely (premium)',
230
+ inputSchema: {
231
+ type: 'object',
232
+ properties: {
233
+ axes: { type: 'array', items: { type: 'string' } },
234
+ locked: { type: 'boolean' },
235
+ values: { type: 'array', items: { type: 'number' } },
236
+ flightMode: { type: 'boolean' }
237
+ }
238
+ }
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Module 3: LayerGeometryMixer
245
+
246
+ **File**: `src/LayerGeometryMixer.js`
247
+ **Purpose**: Allow each of the 5 layers to render a different geometry.
248
+
249
+ ### Current Limitation
250
+
251
+ Geometry is global: `engine.setParameter('geometry', 16)` sets all layers to geometry 16. The LayerRelationshipGraph relationship functions pass `geometry` through unchanged — none of the 6 preset relationship types (echo, mirror, complement, harmonic, reactive, chase) modify the `geometry` key.
252
+
253
+ ### How It Works
254
+
255
+ The shader uniform `u_geometry` (float) is already sent per-visualizer-instance. Each HolographicVisualizer/QuantumVisualizer instance has its own WebGL context with its own uniform state. So geometrically, per-layer geometry IS possible — we just need to get different geometry values into each layer's resolved parameters.
256
+
257
+ **Approach**: Register custom relationship functions on the LayerRelationshipGraph that override the `geometry` key:
258
+
259
+ ```javascript
260
+ // Custom relationship that offsets geometry
261
+ engine.activeSystem.layerGraph.setRelationship('shadow', (kp, time) => ({
262
+ ...kp,
263
+ geometry: (kp.geometry + 8) % 24 // Same base shape, next warp type
264
+ }));
265
+ ```
266
+
267
+ The LayerGeometryMixer wraps this into a clean API.
268
+
269
+ ### Verification Needed
270
+
271
+ Before implementation, verify that `RealHolographicSystem.updateParameters()` doesn't override per-layer geometry with the global value. The research suggests it builds a single `currentVariant` and calls `generateVariantParams(variant)` for all layers — this may need patching.
272
+
273
+ ### API
274
+
275
+ ```javascript
276
+ class LayerGeometryMixer {
277
+ constructor(engine) { }
278
+
279
+ // Set explicit geometry for a layer
280
+ setLayerGeometry(layerName: string, geometry: number): void
281
+
282
+ // Use geometry offset from keystone (same base, different warp)
283
+ setGeometryOffset(layerName: string, offset: number): void
284
+
285
+ // Clear per-layer geometry (revert to keystone geometry)
286
+ clearLayerGeometry(layerName: string): void
287
+
288
+ // Get current per-layer geometries
289
+ getLayerGeometries(): { background: number, shadow: number, content: number, highlight: number, accent: number }
290
+
291
+ destroy(): void
292
+ }
293
+ ```
294
+
295
+ ### New Relationship Presets
296
+
297
+ ```javascript
298
+ // Added to LayerRelationshipGraph preset library:
299
+ function geometryOffset(config = {}) {
300
+ const { offset = 8, ...echoConfig } = config;
301
+ const echoFn = echo(echoConfig);
302
+ return (kp, time) => ({
303
+ ...echoFn(kp, time),
304
+ geometry: ((kp.geometry || 0) + offset) % 24
305
+ });
306
+ }
307
+
308
+ function geometrySplit(config = {}) {
309
+ // Explicit per-layer geometry assignment
310
+ return (kp, time) => ({
311
+ ...kp,
312
+ geometry: config.geometry ?? kp.geometry
313
+ });
314
+ }
315
+ ```
316
+
317
+ ### MCP Tool
318
+
319
+ ```javascript
320
+ {
321
+ name: 'set_layer_geometry',
322
+ description: 'Set geometry per layer. Each layer can render a different geometry variant (premium)',
323
+ inputSchema: {
324
+ type: 'object',
325
+ properties: {
326
+ layer: { type: 'string', enum: ['background', 'shadow', 'content', 'highlight', 'accent'] },
327
+ geometry: { type: 'integer', minimum: 0, maximum: 23 },
328
+ offset: { type: 'integer', minimum: -23, maximum: 23 }
329
+ }
330
+ }
331
+ }
332
+ ```
333
+
334
+ ---
335
+
336
+ ## Module 4: VisualEventSystem
337
+
338
+ **File**: `src/VisualEventSystem.js`
339
+ **Purpose**: Threshold-based triggers that fire discrete state changes — not continuous parameter mappings. "When X happens, DO Y."
340
+
341
+ ### Why This Matters
342
+
343
+ The free SDK has continuous reactivity (audio→parameter mapping via ReactivityManager) and timed animation (TransitionAnimator, ParameterTimeline, ChoreographyPlayer). But there's no way to say "when bass exceeds 0.8, switch to storm profile for 3 seconds." That's an EVENT — a discrete state change with a trigger, an action, and optionally a revert.
344
+
345
+ This is what makes VIB3+ feel intentional rather than random. Without events, audio reactivity just produces continuous wobble. WITH events, a bass drop can trigger a dramatic visual state change.
346
+
347
+ ### API
348
+
349
+ ```javascript
350
+ class VisualEventSystem {
351
+ constructor(engine, premium) { }
352
+
353
+ // Add a trigger
354
+ addTrigger(id: string, config: TriggerConfig): void
355
+
356
+ // Remove a trigger
357
+ removeTrigger(id: string): void
358
+
359
+ // List all triggers
360
+ listTriggers(): TriggerConfig[]
361
+
362
+ // Emit a custom event (for external code to trigger actions)
363
+ emit(eventName: string, data?: Object): void
364
+
365
+ // Subscribe to trigger fires
366
+ on(eventName: string, callback: Function): () => void // returns unsubscribe
367
+
368
+ // Enable/disable
369
+ setEnabled(enabled: boolean): void
370
+
371
+ destroy(): void
372
+ }
373
+
374
+ // TriggerConfig:
375
+ {
376
+ source: string, // 'parameter.chaos' | 'audio.bass' | 'audio.mid' | 'audio.high' | 'audio.energy' | 'custom.eventName'
377
+ condition: string, // 'exceeds' | 'drops_below' | 'crosses' | 'equals'
378
+ threshold: number,
379
+ cooldown: number, // ms before trigger can fire again (default: 1000)
380
+ action: {
381
+ type: string, // 'layer_profile' | 'color_preset' | 'set_parameters' | 'transition' | 'custom'
382
+ value: any, // profile name, preset name, params object, or custom handler
383
+ duration?: number, // ms to hold the action state (optional)
384
+ revertTo?: any, // what to revert to after duration (optional)
385
+ easing?: string, // for transitions
386
+ transition?: boolean // smooth transition to the new state
387
+ }
388
+ }
389
+ ```
390
+
391
+ ### Implementation
392
+
393
+ Uses `engine.onParameterChange()` to watch parameter sources. Uses audio input via `engine.reactivity` events or direct audio polling for audio sources.
394
+
395
+ Each frame:
396
+ 1. Read current values for all watched sources
397
+ 2. Evaluate trigger conditions against thresholds
398
+ 3. Check cooldown timers
399
+ 4. Fire actions for triggered events
400
+ 5. Check duration timers for active timed actions
401
+ 6. Revert expired timed actions
402
+
403
+ ### Example Patterns
404
+
405
+ ```javascript
406
+ // Bass drop triggers storm mode
407
+ events.addTrigger('bass_storm', {
408
+ source: 'audio.bass',
409
+ condition: 'exceeds',
410
+ threshold: 0.8,
411
+ cooldown: 3000,
412
+ action: {
413
+ type: 'layer_profile',
414
+ value: 'storm',
415
+ duration: 2000,
416
+ revertTo: 'holographic'
417
+ }
418
+ });
419
+
420
+ // High chaos triggers red alert color
421
+ events.addTrigger('chaos_alert', {
422
+ source: 'parameter.chaos',
423
+ condition: 'exceeds',
424
+ threshold: 0.7,
425
+ cooldown: 5000,
426
+ action: {
427
+ type: 'set_parameters',
428
+ value: { hue: 0, saturation: 1, intensity: 1 },
429
+ duration: 1500,
430
+ easing: 'elastic',
431
+ transition: true
432
+ }
433
+ });
434
+
435
+ // Geometry reaches hypertetra range → cosmic color preset
436
+ events.addTrigger('hypertetra_cosmic', {
437
+ source: 'parameter.geometry',
438
+ condition: 'exceeds',
439
+ threshold: 15.5, // entering 16+ range
440
+ cooldown: 0, // fires every time
441
+ action: {
442
+ type: 'color_preset',
443
+ value: 'Cosmic Nebula',
444
+ transition: true
445
+ }
446
+ });
447
+
448
+ // Custom event from external code
449
+ events.addTrigger('card_flip', {
450
+ source: 'custom.card_flip',
451
+ condition: 'equals',
452
+ threshold: 1,
453
+ cooldown: 500,
454
+ action: {
455
+ type: 'transition',
456
+ value: { rot4dXW: 0.9, gridDensity: 12 },
457
+ easing: 'easeOutQuad',
458
+ duration: 800
459
+ }
460
+ });
461
+ ```
462
+
463
+ ### MCP Tools
464
+
465
+ ```javascript
466
+ // add_visual_trigger
467
+ {
468
+ name: 'add_visual_trigger',
469
+ description: 'Add a threshold-based event trigger (premium)',
470
+ inputSchema: {
471
+ type: 'object',
472
+ required: ['id', 'source', 'condition', 'threshold', 'action'],
473
+ properties: {
474
+ id: { type: 'string' },
475
+ source: { type: 'string' },
476
+ condition: { type: 'string', enum: ['exceeds', 'drops_below', 'crosses', 'equals'] },
477
+ threshold: { type: 'number' },
478
+ cooldown: { type: 'number' },
479
+ action: { type: 'object' }
480
+ }
481
+ }
482
+ }
483
+
484
+ // remove_visual_trigger
485
+ {
486
+ name: 'remove_visual_trigger',
487
+ description: 'Remove a visual event trigger by ID (premium)',
488
+ inputSchema: { type: 'object', required: ['id'], properties: { id: { type: 'string' } } }
489
+ }
490
+
491
+ // list_visual_triggers
492
+ {
493
+ name: 'list_visual_triggers',
494
+ description: 'List all active visual event triggers (premium)',
495
+ inputSchema: { type: 'object', properties: {} }
496
+ }
497
+ ```
498
+
499
+ ---
500
+
501
+ ## Module 5: CSSBridge
502
+
503
+ **File**: `src/CSSBridge.js`
504
+ **Purpose**: Live bidirectional binding between VIB3+ parameters and CSS custom properties.
505
+
506
+ ### Why This Matters
507
+
508
+ CSS animations, transforms, and layout properties can express things WebGL cannot: text, DOM elements, box shadows, blur filters, clip paths. When VIB3+ parameter state drives CSS custom properties in real-time, the ENTIRE page becomes part of the visualization — not just the canvas rectangles.
509
+
510
+ Conversely, CSS animations (scroll position, hover states, transition values) can drive VIB3+ parameters, creating page interactions that directly control the 4D visualization.
511
+
512
+ ### API
513
+
514
+ ```javascript
515
+ class CSSBridge {
516
+ constructor(engine) { }
517
+
518
+ // Start the bridge
519
+ start(options?: CSSBridgeOptions): void
520
+
521
+ // Stop the bridge
522
+ stop(): void
523
+
524
+ // Manually push a parameter value to CSS
525
+ pushToCSS(name: string, value: number): void
526
+
527
+ // Manually read a CSS custom property and push to engine
528
+ pullFromCSS(name: string): number
529
+
530
+ // Check if running
531
+ isActive(): boolean
532
+
533
+ destroy(): void
534
+ }
535
+
536
+ // CSSBridgeOptions:
537
+ {
538
+ target: HTMLElement, // default: document.documentElement
539
+ prefix: string, // default: 'vib3' (produces --vib3-hue, etc.)
540
+ outbound: boolean, // default: true (engine → CSS)
541
+ inbound: boolean, // default: false (CSS → engine)
542
+ throttle: number, // default: 16 (ms, ~60fps)
543
+ parameters: string[], // which params to bridge. default: all
544
+ inboundParameters: string[], // which CSS vars to watch for inbound. default: none
545
+ normalize: boolean // default: true (normalize ranges to 0-1 for CSS)
546
+ }
547
+ ```
548
+
549
+ ### Outbound (VIB3+ → CSS)
550
+
551
+ Subscribes to `engine.onParameterChange()`. On each update (throttled):
552
+
553
+ ```javascript
554
+ for (const param of this.parameters) {
555
+ const value = params[param];
556
+ const cssName = `--${this.prefix}-${this.kebabCase(param)}`;
557
+
558
+ if (this.normalize) {
559
+ // Normalize to 0-1 range for easier CSS calc()
560
+ const { min, max } = this.paramRanges[param];
561
+ const normalized = (value - min) / (max - min);
562
+ this.target.style.setProperty(cssName, normalized);
563
+ this.target.style.setProperty(`${cssName}-raw`, value);
564
+ } else {
565
+ this.target.style.setProperty(cssName, value);
566
+ }
567
+ }
568
+ ```
569
+
570
+ **CSS output example** (with `normalize: true`):
571
+ ```css
572
+ :root {
573
+ --vib3-hue: 0.611; /* 220/360 normalized */
574
+ --vib3-hue-raw: 220; /* raw value */
575
+ --vib3-grid-density: 0.375; /* (40-4)/(100-4) normalized */
576
+ --vib3-grid-density-raw: 40;
577
+ --vib3-rot4d-xw: 0.225; /* (0.9-(-2))/(2-(-2)) normalized */
578
+ --vib3-rot4d-xw-raw: 0.9;
579
+ --vib3-chaos: 0.1; /* already 0-1 range */
580
+ --vib3-chaos-raw: 0.1;
581
+ --vib3-intensity: 0.7;
582
+ --vib3-intensity-raw: 0.7;
583
+ }
584
+ ```
585
+
586
+ **CSS usage examples:**
587
+ ```css
588
+ /* Card tilt follows 4D rotation */
589
+ .card {
590
+ transform: perspective(800px)
591
+ rotateY(calc(var(--vib3-rot4d-xw) * 30deg - 15deg));
592
+ }
593
+
594
+ /* Shadow grows with grid density decrease (lower density = more shadow) */
595
+ .card-shadow {
596
+ box-shadow: 0
597
+ calc((1 - var(--vib3-grid-density)) * 24px)
598
+ calc((1 - var(--vib3-grid-density)) * 40px)
599
+ rgba(0, 0, 0, calc(0.1 + var(--vib3-intensity) * 0.3));
600
+ }
601
+
602
+ /* Background blur follows chaos */
603
+ .background {
604
+ filter: blur(calc(var(--vib3-chaos) * 20px));
605
+ }
606
+
607
+ /* Text color from VIB3+ hue */
608
+ .title {
609
+ color: hsl(calc(var(--vib3-hue-raw) * 1deg), 80%, 65%);
610
+ }
611
+
612
+ /* Clip path deforms with chaos */
613
+ .blob {
614
+ border-radius: calc(30% + var(--vib3-chaos) * 20%);
615
+ }
616
+ ```
617
+
618
+ ### Inbound (CSS → VIB3+)
619
+
620
+ Uses `requestAnimationFrame` polling (MutationObserver doesn't fire for CSS custom property changes from animations):
621
+
622
+ ```javascript
623
+ function pollCSSProperties() {
624
+ for (const cssParam of this.inboundParameters) {
625
+ const cssName = `--${this.prefix}-input-${this.kebabCase(cssParam)}`;
626
+ const raw = getComputedStyle(this.target).getPropertyValue(cssName);
627
+ const value = parseFloat(raw);
628
+ if (!isNaN(value) && value !== this._lastInbound[cssParam]) {
629
+ this._lastInbound[cssParam] = value;
630
+ engine.setParameter(cssParam, this.denormalize(cssParam, value));
631
+ }
632
+ }
633
+ if (this._active) requestAnimationFrame(pollCSSProperties);
634
+ }
635
+ ```
636
+
637
+ **CSS input example:**
638
+ ```css
639
+ /* Scroll drives 4D rotation via CSS custom property */
640
+ :root {
641
+ --vib3-input-rot4d-xw: 0;
642
+ }
643
+ @keyframes scroll-drive {
644
+ from { --vib3-input-rot4d-xw: 0; }
645
+ to { --vib3-input-rot4d-xw: 1; }
646
+ }
647
+ html {
648
+ animation: scroll-drive linear;
649
+ animation-timeline: scroll(root);
650
+ }
651
+ ```
652
+
653
+ ### MCP Tool
654
+
655
+ ```javascript
656
+ {
657
+ name: 'configure_css_bridge',
658
+ description: 'Configure live CSS custom property binding (premium)',
659
+ inputSchema: {
660
+ type: 'object',
661
+ properties: {
662
+ enabled: { type: 'boolean' },
663
+ outbound: { type: 'boolean' },
664
+ inbound: { type: 'boolean' },
665
+ parameters: { type: 'array', items: { type: 'string' } },
666
+ throttle: { type: 'number' },
667
+ normalize: { type: 'boolean' }
668
+ }
669
+ }
670
+ }
671
+ ```
672
+
673
+ ---
674
+
675
+ ## Module 6: ChoreographyExtensions
676
+
677
+ **File**: `src/ChoreographyExtensions.js`
678
+ **Purpose**: Extend ChoreographyPlayer scenes with `layer_profile` and `layer_overrides` fields.
679
+
680
+ ### Current Limitation
681
+
682
+ `ChoreographyScene` in the free SDK supports: `system`, `geometry`, `transition_in`, `tracks`, `color_preset`, `post_processing`, `audio`. It does NOT support: `layer_profile`, `layer_overrides`, `triggers`.
683
+
684
+ ### Extended Scene Format
685
+
686
+ ```javascript
687
+ {
688
+ // Existing fields (free SDK):
689
+ system: 'holographic',
690
+ geometry: 16,
691
+ transition_in: { type: 'smooth', duration: 800 },
692
+ tracks: {
693
+ gridDensity: [
694
+ { time: 0, value: 40 },
695
+ { time: 0.5, value: 14, easing: 'easeOutQuad' },
696
+ { time: 1, value: 28, easing: 'easeOut' }
697
+ ]
698
+ },
699
+ color_preset: 'Cosmic Nebula',
700
+
701
+ // NEW premium fields:
702
+ layer_profile: 'storm',
703
+ layer_overrides: {
704
+ shadow: { type: 'echo', config: { densityScale: 1.5 } },
705
+ accent: { type: 'reactive', config: { gain: 4.0, decay: 0.85 } }
706
+ },
707
+ triggers: [
708
+ {
709
+ source: 'audio.bass',
710
+ condition: 'exceeds',
711
+ threshold: 0.8,
712
+ action: { type: 'layer_profile', value: 'storm', duration: 2000, revertTo: 'holographic' }
713
+ }
714
+ ],
715
+ rotation_locks: {
716
+ rot4dXY: 0,
717
+ rot4dXZ: 0,
718
+ rot4dYZ: 0
719
+ }
720
+ }
721
+ ```
722
+
723
+ ### Implementation
724
+
725
+ Wraps `ChoreographyPlayer._enterScene()` by monkey-patching or using the `onSceneChange` callback:
726
+
727
+ ```javascript
728
+ class ChoreographyExtensions {
729
+ constructor(engine, premium, choreographyPlayer) {
730
+ choreographyPlayer.onSceneChange = (index, scene) => {
731
+ // Apply layer profile
732
+ if (scene.layer_profile && engine.activeSystem?.loadRelationshipProfile) {
733
+ engine.activeSystem.loadRelationshipProfile(scene.layer_profile);
734
+ }
735
+
736
+ // Apply layer overrides
737
+ if (scene.layer_overrides && engine.activeSystem?.layerGraph) {
738
+ for (const [layer, config] of Object.entries(scene.layer_overrides)) {
739
+ engine.activeSystem.layerGraph.setRelationship(layer, config.type, config.config);
740
+ }
741
+ }
742
+
743
+ // Register scene triggers
744
+ if (scene.triggers && premium.events) {
745
+ // Clear previous scene's triggers
746
+ premium.events.clearSceneTriggers();
747
+ for (const trigger of scene.triggers) {
748
+ premium.events.addTrigger(`scene_${index}_${trigger.source}`, trigger);
749
+ }
750
+ }
751
+
752
+ // Apply rotation locks
753
+ if (scene.rotation_locks && premium.rotationLock) {
754
+ premium.rotationLock.unlockAll();
755
+ for (const [axis, value] of Object.entries(scene.rotation_locks)) {
756
+ premium.rotationLock.lockAxis(axis, value);
757
+ }
758
+ }
759
+ };
760
+ }
761
+ }
762
+ ```
763
+
764
+ ---
765
+
766
+ ## Module 7: FrameworkSync
767
+
768
+ **File**: `src/FrameworkSync.js`
769
+ **Purpose**: Bidirectional state sync between VIB3+ engine and React/Vue/Svelte frameworks.
770
+
771
+ ### Current Limitation
772
+
773
+ The free SDK's framework integrations (Vib3React.js, Vib3Vue.js, Vib3Svelte.js) generate code that pushes props→engine but never subscribes to engine→framework state. If audio reactivity or spatial input changes a parameter, the framework state goes stale.
774
+
775
+ ### Implementation
776
+
777
+ Generates enhanced framework code that includes `onParameterChange()` subscription:
778
+
779
+ **React (enhanced `useVib3()`):**
780
+ ```javascript
781
+ useEffect(() => {
782
+ if (!engine) return;
783
+ const unsubscribe = engine.onParameterChange((params) => {
784
+ setParameters(prev => {
785
+ // Only update if values actually changed (avoid infinite loops)
786
+ const changed = Object.keys(params).some(k => prev[k] !== params[k]);
787
+ return changed ? { ...prev, ...params } : prev;
788
+ });
789
+ });
790
+ return unsubscribe;
791
+ }, [engine]);
792
+ ```
793
+
794
+ **Vue (enhanced composable):**
795
+ ```javascript
796
+ watch(engine, (eng) => {
797
+ if (!eng) return;
798
+ eng.onParameterChange((params) => {
799
+ Object.assign(parameters, params);
800
+ });
801
+ });
802
+ ```
803
+
804
+ **Svelte (enhanced store):**
805
+ ```javascript
806
+ // In vib3Actions.initialize():
807
+ engine.onParameterChange((params) => {
808
+ vib3Store.update(state => ({
809
+ ...state,
810
+ parameters: { ...state.parameters, ...params }
811
+ }));
812
+ });
813
+ ```
814
+
815
+ ---
816
+
817
+ ## Module 8: PremiumMCPServer
818
+
819
+ **File**: `src/mcp/PremiumMCPServer.js`
820
+ **Purpose**: Wraps the free SDK's MCPServer, adding premium tool handling with license validation.
821
+
822
+ ### Tool List
823
+
824
+ | Tool | Module | Description |
825
+ |------|--------|-------------|
826
+ | `set_shader_parameter` | ShaderParameterSurface | Set fine-grained shader params |
827
+ | `set_rotation_lock` | RotationLockSystem | Lock/unlock rotation axes, flight mode |
828
+ | `set_layer_geometry` | LayerGeometryMixer | Per-layer geometry assignment |
829
+ | `add_visual_trigger` | VisualEventSystem | Add threshold-based event trigger |
830
+ | `remove_visual_trigger` | VisualEventSystem | Remove trigger by ID |
831
+ | `list_visual_triggers` | VisualEventSystem | List all active triggers |
832
+ | `configure_css_bridge` | CSSBridge | Configure live CSS binding |
833
+ | `create_premium_choreography` | ChoreographyExtensions | Create choreography with layer profiles + triggers |
834
+
835
+ ### License Gating
836
+
837
+ ```javascript
838
+ async handleToolCall(toolName, args) {
839
+ if (PREMIUM_TOOLS.has(toolName)) {
840
+ if (!this.premium || !this.premium.isLicensed()) {
841
+ return {
842
+ content: [{ type: 'text', text: `Tool "${toolName}" requires @vib3code/premium. See https://vib3.dev/premium` }],
843
+ isError: true
844
+ };
845
+ }
846
+ }
847
+ // Route to appropriate module handler
848
+ return this.routeTool(toolName, args);
849
+ }
850
+ ```
851
+
852
+ ---
853
+
854
+ ## New Premium Repo File Structure
855
+
856
+ ```
857
+ vib3-premium/
858
+ ├── CLAUDE.md # Agent context for premium development
859
+ ├── package.json # @vib3code/premium
860
+ ├── vitest.config.js # Test config
861
+ ├── src/
862
+ │ ├── index.js # enablePremium() entry point + license validation
863
+ │ ├── ShaderParameterSurface.js # Module 1
864
+ │ ├── RotationLockSystem.js # Module 2
865
+ │ ├── LayerGeometryMixer.js # Module 3
866
+ │ ├── VisualEventSystem.js # Module 4
867
+ │ ├── CSSBridge.js # Module 5
868
+ │ ├── ChoreographyExtensions.js # Module 6
869
+ │ ├── FrameworkSync.js # Module 7
870
+ │ └── mcp/
871
+ │ ├── premium-tools.js # Tool definitions
872
+ │ └── PremiumMCPServer.js # Module 8
873
+ ├── DOCS/
874
+ │ ├── ARCHITECTURE.md # Extension architecture
875
+ │ ├── SHADER_PARAMETER_REFERENCE.md # Full parameter→shader→visual reference
876
+ │ ├── VISUAL_EVENT_PATTERNS.md # Trigger pattern library
877
+ │ ├── CSS_INTEGRATION_GUIDE.md # CSSBridge usage + CSS examples
878
+ │ └── AGENT_PREMIUM_CONTEXT.md # Agent onboarding for premium
879
+ ├── examples/
880
+ │ ├── card-lift-portal.html # Gold standard: card lift + portal
881
+ │ ├── audio-storm.html # Audio events + layer storms
882
+ │ └── css-synchronized.html # CSSBridge + CSS coordination
883
+ └── tests/
884
+ ├── shader-surface.test.js
885
+ ├── rotation-lock.test.js
886
+ ├── layer-geometry.test.js
887
+ ├── visual-events.test.js
888
+ ├── css-bridge.test.js
889
+ ├── choreography-ext.test.js
890
+ └── framework-sync.test.js
891
+ ```
892
+
893
+ ---
894
+
895
+ ## Free SDK Bug Fixes (Pre-requisites)
896
+
897
+ These bugs should be fixed in `@vib3code/sdk` before premium development starts. They are NOT premium features — they're broken standard behavior.
898
+
899
+ ### Fix 1: `u_dimension` Projection (VERIFY POST-MERGE)
900
+
901
+ **File**: `src/faceted/FacetedSystem.js`, `src/quantum/QuantumVisualizer.js`, `src/holograms/HolographicVisualizer.js`
902
+ **What**: Replace `float w = 2.5 / (2.5 + p.w)` with `float w = u_dimension / (u_dimension + p.w)` in all `project4Dto3D()` functions
903
+ **Impact**: The `dimension` parameter actually controls 4D projection distance. Default 3.5 produces slightly different visual than current 2.5 — may need to adjust the default in `Parameters.js` to 2.5 for visual consistency.
904
+ **Verify**: The 6-commit dev branch (`claude/vib3-sdk-handoff-p00R8`) may have fixed this under "uniform standardization" — check before duplicating work.
905
+
906
+ ### Fix 2: Dead Faceted Audio Code
907
+
908
+ **File**: `src/faceted/FacetedSystem.js`
909
+ **What**: In the fragment shader, `audioDensityMod` and `audioMorphMod` are computed from `u_bass` and `u_mid` but never used in the final value computation. Wire them:
910
+ ```glsl
911
+ // Currently: float value = latticeFunction(...) * u_morphFactor;
912
+ // Should be: float value = latticeFunction(...) * u_morphFactor * audioMorphMod;
913
+ // And: gridSize = u_gridDensity * 0.08 * audioDensityMod;
914
+ ```
915
+ **Impact**: Faceted system becomes audio-reactive (bass pulses density, mid modulates morph).
916
+ **Verify**: This is shader logic, not naming — unlikely to be covered by the dev branch fixes.
917
+
918
+ ### Fix 3: Hue Encoding Inconsistency
919
+
920
+ **File**: `src/quantum/QuantumVisualizer.js` (or `src/faceted/FacetedSystem.js`)
921
+ **What**: Faceted passes hue as 0-360 raw degrees to the shader. Quantum normalizes to 0-1 before sending. Pick one convention.
922
+ **Recommendation**: Standardize to 0-360 in the parameter API (as defined in `Parameters.js`), normalize to 0-1 inside each system's `updateParameters()` if the shader needs it.
923
+ **Verify**: Check if "uniform standardization" commit addressed this.
924
+
925
+ ---
926
+
927
+ ## Upstream PRs to Free SDK (Enabling Premium)
928
+
929
+ These are optional enhancements to the free SDK that make premium integration cleaner:
930
+
931
+ ### PR 1: Shader Uniform Declarations (No Behavior Change)
932
+
933
+ Add `uniform float u_uvScale;`, `uniform int u_projectionType;`, `uniform float u_lineThickness;` etc. to all shader strings, with default values matching current hardcoded values. The free SDK sends these defaults — no visual change. Premium sends configurable values.
934
+
935
+ ### PR 2: Plugin Registration Hook (Optional)
936
+
937
+ ```javascript
938
+ // In VIB3Engine:
939
+ registerPlugin(plugin) {
940
+ plugin.attach(this);
941
+ this._plugins.push(plugin);
942
+ }
943
+ ```
944
+
945
+ This allows premium to attach cleanly without monkey-patching `setParameter()` and `updateCurrentSystemParameters()`.
946
+
947
+ ### PR 3: Parameter Change Event Enhancement
948
+
949
+ Enhance `onParameterChange()` to include the parameter name that changed (not just the full state):
950
+ ```javascript
951
+ // Current: listener(params)
952
+ // Enhanced: listener(params, { changed: ['hue', 'chaos'] })
953
+ ```
954
+
955
+ This allows premium modules and framework sync to efficiently detect what changed without full-state diffing.
956
+
957
+ ---
958
+
959
+ ## Implementation Order
960
+
961
+ 1. **Free SDK bug fixes** (PR to main) — u_dimension, dead audio, hue encoding
962
+ 2. **Free SDK uniform declarations** (PR) — add new uniforms with defaults
963
+ 3. **Create premium repo** — scaffold, CLAUDE.md, package.json
964
+ 4. **ShaderParameterSurface** — most independent module, validates the architecture
965
+ 5. **RotationLockSystem** — simple, high impact
966
+ 6. **CSSBridge** — high demo value
967
+ 7. **VisualEventSystem** — depends on having a working engine to test triggers
968
+ 8. **LayerGeometryMixer** — may need upstream verification
969
+ 9. **ChoreographyExtensions** — integrates multiple modules
970
+ 10. **FrameworkSync** — lowest priority, clean enhancement
971
+ 11. **PremiumMCPServer** — wraps everything, last to build
972
+ 12. **Gold standard demos** — card-lift-portal.html, audio-storm.html, css-synchronized.html
973
+
974
+ ---
975
+
976
+ *VIB3+ SDK — Clear Seas Solutions LLC*
977
+ *Expansion Design v1.0 — Feb 16, 2026*