@vib3code/sdk 2.0.3-canary.0e9a1ac → 2.0.3-canary.45332e3
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.
- package/DOCS/MASTER_PLAN_2026-01-31.md +2 -2
- package/DOCS/SYSTEM_INVENTORY.md +2 -2
- package/DOCS/WEBGPU_STATUS.md +119 -38
- package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +38 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +108 -0
- package/docs/webgpu-live.html +1 -1
- package/package.json +1 -1
- package/src/agent/mcp/MCPServer.js +346 -188
- package/src/agent/mcp/tools.js +45 -32
- package/src/faceted/FacetedSystem.js +19 -6
- package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
- package/src/holograms/HolographicVisualizer.js +58 -89
- package/src/math/Mat4x4.js +70 -13
- package/src/math/Rotor4D.js +100 -39
- package/src/quantum/QuantumVisualizer.js +24 -20
- package/src/render/ShaderLoader.js +38 -0
- package/src/render/ShaderProgram.js +4 -4
- package/src/render/UnifiedRenderBridge.js +1 -1
- package/src/render/backends/WebGPUBackend.js +8 -4
- package/src/shaders/common/geometry24.glsl +65 -0
- package/src/shaders/common/geometry24.wgsl +54 -0
- package/src/shaders/common/rotation4d.glsl +4 -4
- package/src/shaders/common/rotation4d.wgsl +2 -2
- package/src/shaders/common/uniforms.wgsl +15 -8
- package/src/shaders/faceted/faceted.frag.wgsl +19 -6
- package/src/shaders/holographic/holographic.frag.wgsl +7 -5
- package/src/shaders/quantum/quantum.frag.wgsl +7 -5
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
- package/tools/shader-sync-verify.js +6 -4
|
@@ -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 = {}) {
|
|
@@ -141,10 +173,13 @@ export class MCPServer {
|
|
|
141
173
|
result = this.getParameterSchema();
|
|
142
174
|
break;
|
|
143
175
|
case 'get_sdk_context':
|
|
144
|
-
result = this.getSDKContext();
|
|
176
|
+
result = this.getSDKContext(args);
|
|
177
|
+
break;
|
|
178
|
+
case 'inspect_layers':
|
|
179
|
+
result = this.inspectLayers(args);
|
|
145
180
|
break;
|
|
146
|
-
case '
|
|
147
|
-
result = this.
|
|
181
|
+
case 'set_holographic_layer':
|
|
182
|
+
result = this.setHolographicLayer(args);
|
|
148
183
|
break;
|
|
149
184
|
// Reactivity tools (Phase 6.5)
|
|
150
185
|
case 'set_reactivity_config':
|
|
@@ -484,32 +519,68 @@ export class MCPServer {
|
|
|
484
519
|
|
|
485
520
|
telemetry.recordEvent(EventType.GALLERY_SAVE, { slot });
|
|
486
521
|
|
|
522
|
+
// Persist actual engine state if available
|
|
523
|
+
if (this.engine) {
|
|
524
|
+
const state = this.engine.exportState();
|
|
525
|
+
this._gallerySlots.set(slot, {
|
|
526
|
+
name: name || `Variation ${slot}`,
|
|
527
|
+
saved_at: new Date().toISOString(),
|
|
528
|
+
state
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
487
532
|
return {
|
|
488
533
|
slot,
|
|
489
534
|
name: name || `Variation ${slot}`,
|
|
490
535
|
saved_at: new Date().toISOString(),
|
|
536
|
+
persisted: !!this.engine,
|
|
537
|
+
gallery_size: this._gallerySlots.size,
|
|
491
538
|
suggested_next_actions: ['load_from_gallery', 'randomize_parameters']
|
|
492
539
|
};
|
|
493
540
|
}
|
|
494
541
|
|
|
495
542
|
/**
|
|
496
|
-
* Load from gallery
|
|
543
|
+
* Load from gallery — restores previously saved state
|
|
497
544
|
*/
|
|
498
545
|
loadFromGallery(args) {
|
|
499
546
|
const { slot } = args;
|
|
500
547
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
548
|
+
telemetry.recordEvent(EventType.GALLERY_LOAD, { slot });
|
|
549
|
+
|
|
550
|
+
const saved = this._gallerySlots.get(slot);
|
|
551
|
+
if (saved && this.engine) {
|
|
552
|
+
// Restore saved state
|
|
553
|
+
this.engine.importState(saved.state);
|
|
554
|
+
return {
|
|
555
|
+
slot,
|
|
556
|
+
name: saved.name,
|
|
557
|
+
saved_at: saved.saved_at,
|
|
558
|
+
loaded_at: new Date().toISOString(),
|
|
559
|
+
restored: true,
|
|
560
|
+
...this.getState()
|
|
561
|
+
};
|
|
505
562
|
}
|
|
506
563
|
|
|
507
|
-
|
|
564
|
+
if (!saved) {
|
|
565
|
+
// No saved state — fall back to random variation
|
|
566
|
+
if (this.engine) {
|
|
567
|
+
const params = this.engine.parameters?.generateVariationParameters?.(slot) || {};
|
|
568
|
+
this.engine.setParameters(params);
|
|
569
|
+
}
|
|
570
|
+
return {
|
|
571
|
+
slot,
|
|
572
|
+
loaded_at: new Date().toISOString(),
|
|
573
|
+
restored: false,
|
|
574
|
+
note: 'No saved state in this slot — generated random variation',
|
|
575
|
+
...this.getState()
|
|
576
|
+
};
|
|
577
|
+
}
|
|
508
578
|
|
|
509
579
|
return {
|
|
510
580
|
slot,
|
|
511
581
|
loaded_at: new Date().toISOString(),
|
|
512
|
-
|
|
582
|
+
restored: false,
|
|
583
|
+
note: 'Engine not initialized — cannot apply state'
|
|
513
584
|
};
|
|
514
585
|
}
|
|
515
586
|
|
|
@@ -582,162 +653,218 @@ export class MCPServer {
|
|
|
582
653
|
/**
|
|
583
654
|
* Get SDK context for agent onboarding
|
|
584
655
|
*/
|
|
585
|
-
getSDKContext() {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
656
|
+
getSDKContext(args = {}) {
|
|
657
|
+
const { include_state = true, include_tools = false } = args;
|
|
658
|
+
|
|
659
|
+
const context = {
|
|
660
|
+
sdk: 'VIB3+ 4D Visualization Engine',
|
|
661
|
+
version: '2.0.3',
|
|
662
|
+
|
|
663
|
+
// Capability manifest — what this engine can do
|
|
664
|
+
capabilities: {
|
|
665
|
+
systems: ['quantum', 'faceted', 'holographic'],
|
|
666
|
+
geometries: { count: 24, formula: 'core_type * 8 + base_geometry', base: 8, warps: 3 },
|
|
667
|
+
rotation: { planes: 6, '3D': ['XY', 'XZ', 'YZ'], '4D': ['XW', 'YW', 'ZW'], range: '±6.28 rad' },
|
|
668
|
+
layers: { count: 5, roles: ['background', 'shadow', 'content', 'highlight', 'accent'], addressable: true },
|
|
669
|
+
audio: { bands: ['bass', 'mid', 'high'], modes: ['add', 'multiply', 'replace', 'max', 'min'] },
|
|
670
|
+
input: { sources: ['deviceTilt', 'mousePosition', 'gyroscope', 'gamepad', 'perspective', 'programmatic', 'audio', 'midi'] },
|
|
671
|
+
creative: {
|
|
672
|
+
color_presets: 22,
|
|
673
|
+
easing_functions: 14,
|
|
674
|
+
post_effects: 14,
|
|
675
|
+
aesthetic_keywords: '130+',
|
|
676
|
+
choreography: true,
|
|
677
|
+
timeline_bpm_sync: true
|
|
678
|
+
},
|
|
679
|
+
environment: {
|
|
680
|
+
browser: typeof document !== 'undefined',
|
|
681
|
+
screenshot: typeof document !== 'undefined',
|
|
682
|
+
webgpu: typeof navigator !== 'undefined' && !!navigator.gpu,
|
|
683
|
+
wasm: typeof WebAssembly !== 'undefined'
|
|
684
|
+
}
|
|
610
685
|
},
|
|
611
686
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
687
|
+
// Parameter ranges — the agent needs these to generate valid values
|
|
688
|
+
parameter_ranges: {
|
|
689
|
+
geometry: { min: 0, max: 23, type: 'integer' },
|
|
690
|
+
hue: { min: 0, max: 360, type: 'integer' },
|
|
691
|
+
saturation: { min: 0, max: 1 },
|
|
692
|
+
intensity: { min: 0, max: 1 },
|
|
693
|
+
speed: { min: 0.1, max: 3 },
|
|
694
|
+
chaos: { min: 0, max: 1 },
|
|
695
|
+
morphFactor: { min: 0, max: 2 },
|
|
696
|
+
gridDensity: { min: 4, max: 100 },
|
|
697
|
+
dimension: { min: 3.0, max: 4.5 },
|
|
698
|
+
rot4dXY: { min: -6.28, max: 6.28 },
|
|
699
|
+
rot4dXW: { min: -6.28, max: 6.28 }
|
|
617
700
|
},
|
|
618
701
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
702
|
+
// Workflow hints — what tool sequences accomplish creative goals
|
|
703
|
+
workflows: {
|
|
704
|
+
quick_design: 'design_from_description → describe_visual_state → batch_set_parameters',
|
|
705
|
+
choreography: 'create_choreography → play_choreography → describe_visual_state',
|
|
706
|
+
evolve: 'batch_set_parameters → describe_visual_state → batch_set_parameters (iterate)',
|
|
707
|
+
layer_control: 'inspect_layers → set_holographic_layer → inspect_layers',
|
|
708
|
+
audio_reactive: 'configure_audio_band → apply_behavior_preset → describe_visual_state'
|
|
624
709
|
},
|
|
625
710
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
711
|
+
// Geometry quick-reference
|
|
712
|
+
geometry_map: {
|
|
713
|
+
'sphere': 2, 'hypersphere+sphere': 10, 'hypertetra+sphere': 18,
|
|
714
|
+
'torus': 3, 'hypersphere+torus': 11, 'hypertetra+torus': 19,
|
|
715
|
+
'fractal': 5, 'hypersphere+fractal': 13, 'hypertetra+fractal': 21,
|
|
716
|
+
'crystal': 7, 'wave': 6, 'klein_bottle': 4, 'hypercube': 1, 'tetrahedron': 0
|
|
717
|
+
}
|
|
718
|
+
};
|
|
630
719
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
'Q1: How many rotation planes? a)3 b)4 c)6 d)8',
|
|
635
|
-
'Q2: Geometry encoding formula? a)base*3+core b)core*8+base c)base+core d)core*base',
|
|
636
|
-
'Q3: Canvas layers per system? a)3 b)4 c)5 d)6',
|
|
637
|
-
'Q4: Which are the 3 ACTIVE systems? a)quantum,faceted,holographic b)quantum,faceted,polychora c)all four d)none',
|
|
638
|
-
'Q5: How many base geometry types? a)6 b)8 c)10 d)24',
|
|
639
|
-
'Q6: Core warp types? a)base,sphere,cube b)base,hypersphere,hypertetrahedron c)2D,3D,4D d)none'
|
|
640
|
-
]
|
|
641
|
-
},
|
|
720
|
+
if (include_state) {
|
|
721
|
+
context.current_state = this.getState();
|
|
722
|
+
}
|
|
642
723
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
724
|
+
if (include_tools) {
|
|
725
|
+
context.tool_summary = Object.entries(toolDefinitions).map(([name, def]) => ({
|
|
726
|
+
name,
|
|
727
|
+
description: def.description.split('.')[0] // First sentence only
|
|
728
|
+
}));
|
|
729
|
+
}
|
|
649
730
|
|
|
650
|
-
|
|
651
|
-
};
|
|
731
|
+
return context;
|
|
652
732
|
}
|
|
653
733
|
|
|
654
734
|
/**
|
|
655
|
-
*
|
|
735
|
+
* Inspect holographic layer state — returns per-layer metadata in JSON format.
|
|
736
|
+
* This replaces the old verify_knowledge quiz with something actually useful.
|
|
656
737
|
*/
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
q1_rotation_planes: 'c', // 6 rotation planes
|
|
660
|
-
q2_geometry_formula: 'b', // core*8+base
|
|
661
|
-
q3_canvas_layers: 'c', // 5 layers
|
|
662
|
-
q4_active_systems: 'a', // quantum, faceted, holographic (polychora is TBD)
|
|
663
|
-
q5_base_geometries: 'b', // 8 base geometries
|
|
664
|
-
q6_core_types: 'b' // base, hypersphere, hypertetrahedron
|
|
665
|
-
};
|
|
738
|
+
inspectLayers(args = {}) {
|
|
739
|
+
const { layer = 'all' } = args;
|
|
666
740
|
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
},
|
|
693
|
-
|
|
694
|
-
topic: 'CORE WARP TYPES',
|
|
695
|
-
doc: '24-GEOMETRY-6D-ROTATION-SUMMARY.md',
|
|
696
|
-
reason: '3 cores: base (no warp), hypersphere, hypertetrahedron'
|
|
697
|
-
}
|
|
741
|
+
const systemName = this.engine?.currentSystemName || 'unknown';
|
|
742
|
+
const isHolographic = systemName === 'holographic';
|
|
743
|
+
|
|
744
|
+
if (!isHolographic) {
|
|
745
|
+
return {
|
|
746
|
+
system: systemName,
|
|
747
|
+
note: 'Layer inspection is most detailed for the holographic system (5 independent canvas layers). Switch with switch_system("holographic").',
|
|
748
|
+
layers: [{
|
|
749
|
+
role: 'main',
|
|
750
|
+
system: systemName,
|
|
751
|
+
opacity: 1.0,
|
|
752
|
+
enabled: true,
|
|
753
|
+
description: `Single canvas for ${systemName} system`
|
|
754
|
+
}],
|
|
755
|
+
suggested_next_actions: ['switch_system', 'describe_visual_state']
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Build layer metadata from the holographic system
|
|
760
|
+
const system = this.engine?.currentSystem;
|
|
761
|
+
const layerRoles = ['background', 'shadow', 'content', 'highlight', 'accent'];
|
|
762
|
+
const defaultConfigs = {
|
|
763
|
+
background: { densityMult: 0.4, speedMult: 0.2, colorShift: 0, intensity: 0.2, reactivity: 0.5 },
|
|
764
|
+
shadow: { densityMult: 0.8, speedMult: 0.3, colorShift: 180, intensity: 0.4, reactivity: 0.7 },
|
|
765
|
+
content: { densityMult: 1.0, speedMult: 1.0, colorShift: 0, intensity: 1.0, reactivity: 0.9 },
|
|
766
|
+
highlight: { densityMult: 1.5, speedMult: 0.8, colorShift: 60, intensity: 0.6, reactivity: 1.1 },
|
|
767
|
+
accent: { densityMult: 2.5, speedMult: 0.4, colorShift: 300, intensity: 0.3, reactivity: 1.5 }
|
|
698
768
|
};
|
|
699
769
|
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
770
|
+
const buildLayerInfo = (role) => {
|
|
771
|
+
const config = defaultConfigs[role] || {};
|
|
772
|
+
const visualizer = system?.visualizers?.find?.(v => v?.role === role);
|
|
773
|
+
const overrides = this._layerOverrides?.get(role) || {};
|
|
774
|
+
|
|
775
|
+
return {
|
|
776
|
+
role,
|
|
777
|
+
enabled: overrides.enabled !== undefined ? overrides.enabled : true,
|
|
778
|
+
opacity: overrides.opacity !== undefined ? overrides.opacity : 1.0,
|
|
779
|
+
blendMode: overrides.blendMode || 'normal',
|
|
780
|
+
densityMult: overrides.densityMult ?? config.densityMult,
|
|
781
|
+
speedMult: overrides.speedMult ?? config.speedMult,
|
|
782
|
+
colorShift: overrides.colorShift ?? config.colorShift,
|
|
783
|
+
intensity: overrides.intensity ?? config.intensity,
|
|
784
|
+
reactivity: overrides.reactivity ?? config.reactivity,
|
|
785
|
+
has_visualizer: !!visualizer
|
|
786
|
+
};
|
|
705
787
|
};
|
|
706
788
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
correct_answer: correct
|
|
719
|
-
});
|
|
720
|
-
results.REVIEW_REQUIRED.push(docReferences[question]);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
789
|
+
const layers = layer === 'all'
|
|
790
|
+
? layerRoles.map(buildLayerInfo)
|
|
791
|
+
: [buildLayerInfo(layer)];
|
|
792
|
+
|
|
793
|
+
return {
|
|
794
|
+
system: 'holographic',
|
|
795
|
+
layer_count: layerRoles.length,
|
|
796
|
+
layers,
|
|
797
|
+
suggested_next_actions: ['set_holographic_layer', 'batch_set_parameters', 'describe_visual_state']
|
|
798
|
+
};
|
|
799
|
+
}
|
|
723
800
|
|
|
724
|
-
|
|
801
|
+
/**
|
|
802
|
+
* Set properties on an individual holographic layer.
|
|
803
|
+
* Stores overrides in a layer override map and applies them to the visualizer.
|
|
804
|
+
*/
|
|
805
|
+
setHolographicLayer(args) {
|
|
806
|
+
const { layer, opacity, blendMode, enabled, colorShift, densityMult, speedMult, reactivity } = args;
|
|
725
807
|
|
|
726
|
-
|
|
727
|
-
if (
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
808
|
+
const systemName = this.engine?.currentSystemName || 'unknown';
|
|
809
|
+
if (systemName !== 'holographic') {
|
|
810
|
+
return {
|
|
811
|
+
error: {
|
|
812
|
+
type: 'SystemError',
|
|
813
|
+
code: 'NOT_HOLOGRAPHIC',
|
|
814
|
+
message: `set_holographic_layer requires holographic system (current: ${systemName})`,
|
|
815
|
+
suggestion: 'Call switch_system("holographic") first'
|
|
816
|
+
}
|
|
817
|
+
};
|
|
736
818
|
}
|
|
737
819
|
|
|
738
|
-
|
|
820
|
+
// Initialize layer override storage
|
|
821
|
+
if (!this._layerOverrides) this._layerOverrides = new Map();
|
|
822
|
+
const existing = this._layerOverrides.get(layer) || {};
|
|
823
|
+
const updates = {};
|
|
824
|
+
|
|
825
|
+
if (opacity !== undefined) { existing.opacity = opacity; updates.opacity = opacity; }
|
|
826
|
+
if (blendMode !== undefined) { existing.blendMode = blendMode; updates.blendMode = blendMode; }
|
|
827
|
+
if (enabled !== undefined) { existing.enabled = enabled; updates.enabled = enabled; }
|
|
828
|
+
if (colorShift !== undefined) { existing.colorShift = colorShift; updates.colorShift = colorShift; }
|
|
829
|
+
if (densityMult !== undefined) { existing.densityMult = densityMult; updates.densityMult = densityMult; }
|
|
830
|
+
if (speedMult !== undefined) { existing.speedMult = speedMult; updates.speedMult = speedMult; }
|
|
831
|
+
if (reactivity !== undefined) { existing.reactivity = reactivity; updates.reactivity = reactivity; }
|
|
832
|
+
|
|
833
|
+
this._layerOverrides.set(layer, existing);
|
|
834
|
+
|
|
835
|
+
// Apply to visualizer if available
|
|
836
|
+
const system = this.engine?.currentSystem;
|
|
837
|
+
const visualizer = system?.visualizers?.find?.(v => v?.role === layer);
|
|
838
|
+
if (visualizer) {
|
|
839
|
+
if (opacity !== undefined && visualizer.canvas) {
|
|
840
|
+
visualizer.canvas.style.opacity = String(opacity);
|
|
841
|
+
}
|
|
842
|
+
if (blendMode !== undefined && visualizer.canvas) {
|
|
843
|
+
visualizer.canvas.style.mixBlendMode = blendMode;
|
|
844
|
+
}
|
|
845
|
+
if (enabled !== undefined && visualizer.canvas) {
|
|
846
|
+
visualizer.canvas.style.display = enabled ? '' : 'none';
|
|
847
|
+
}
|
|
848
|
+
if (colorShift !== undefined && visualizer.roleParams) {
|
|
849
|
+
visualizer.roleParams.colorShift = colorShift;
|
|
850
|
+
}
|
|
851
|
+
if (densityMult !== undefined && visualizer.roleParams) {
|
|
852
|
+
visualizer.roleParams.densityMult = densityMult;
|
|
853
|
+
}
|
|
854
|
+
if (speedMult !== undefined && visualizer.roleParams) {
|
|
855
|
+
visualizer.roleParams.speedMult = speedMult;
|
|
856
|
+
}
|
|
857
|
+
if (reactivity !== undefined) {
|
|
858
|
+
visualizer.reactivity = reactivity;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
739
861
|
|
|
740
|
-
return
|
|
862
|
+
return {
|
|
863
|
+
layer,
|
|
864
|
+
applied: updates,
|
|
865
|
+
current_state: this.inspectLayers({ layer }).layers[0],
|
|
866
|
+
suggested_next_actions: ['inspect_layers', 'set_holographic_layer', 'describe_visual_state']
|
|
867
|
+
};
|
|
741
868
|
}
|
|
742
869
|
|
|
743
870
|
/**
|
|
@@ -1217,8 +1344,17 @@ export class MCPServer {
|
|
|
1217
1344
|
(sum, step) => sum + step.duration + step.delay, 0
|
|
1218
1345
|
);
|
|
1219
1346
|
|
|
1347
|
+
// Execute live if engine available
|
|
1348
|
+
let executing = false;
|
|
1349
|
+
const animator = this._getTransitionAnimator();
|
|
1350
|
+
if (animator) {
|
|
1351
|
+
const seqId = animator.sequence(normalizedSequence);
|
|
1352
|
+
executing = !!seqId;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1220
1355
|
return {
|
|
1221
1356
|
transition_id: transitionId,
|
|
1357
|
+
executing,
|
|
1222
1358
|
step_count: normalizedSequence.length,
|
|
1223
1359
|
total_duration_ms: totalDuration,
|
|
1224
1360
|
steps: normalizedSequence.map((step, i) => ({
|
|
@@ -1228,7 +1364,7 @@ export class MCPServer {
|
|
|
1228
1364
|
easing: step.easing,
|
|
1229
1365
|
delay: step.delay
|
|
1230
1366
|
})),
|
|
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)});`,
|
|
1367
|
+
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
1368
|
suggested_next_actions: ['describe_visual_state', 'create_timeline', 'save_to_gallery']
|
|
1233
1369
|
};
|
|
1234
1370
|
}
|
|
@@ -1237,55 +1373,41 @@ export class MCPServer {
|
|
|
1237
1373
|
* Apply a named color preset
|
|
1238
1374
|
*/
|
|
1239
1375
|
applyColorPreset(args) {
|
|
1240
|
-
const { preset } = args;
|
|
1376
|
+
const { preset, transition = true, duration = 800 } = args;
|
|
1241
1377
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
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
|
-
};
|
|
1378
|
+
const colorSystem = this._getColorPresets();
|
|
1379
|
+
|
|
1380
|
+
if (colorSystem) {
|
|
1381
|
+
// Use real ColorPresetsSystem — full preset library with transitions
|
|
1382
|
+
const config = colorSystem.getPreset(preset);
|
|
1383
|
+
if (!config) {
|
|
1384
|
+
const allPresets = colorSystem.getPresets().map(p => p.name);
|
|
1385
|
+
return {
|
|
1386
|
+
error: {
|
|
1387
|
+
type: 'ValidationError',
|
|
1388
|
+
code: 'INVALID_COLOR_PRESET',
|
|
1389
|
+
message: `Unknown color preset: ${preset}`,
|
|
1390
|
+
valid_options: allPresets
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
colorSystem.applyPreset(preset, transition, duration);
|
|
1267
1396
|
|
|
1268
|
-
const presetData = COLOR_PRESETS[preset];
|
|
1269
|
-
if (!presetData) {
|
|
1270
1397
|
return {
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
}
|
|
1398
|
+
preset,
|
|
1399
|
+
applied: { hue: config.hue, saturation: config.saturation, intensity: config.intensity },
|
|
1400
|
+
transition: transition ? { enabled: true, duration } : { enabled: false },
|
|
1401
|
+
full_config: config,
|
|
1402
|
+
suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
|
|
1277
1403
|
};
|
|
1278
1404
|
}
|
|
1279
1405
|
|
|
1280
|
-
|
|
1281
|
-
this.engine.setParameter('hue', presetData.hue);
|
|
1282
|
-
this.engine.setParameter('saturation', presetData.saturation);
|
|
1283
|
-
this.engine.setParameter('intensity', presetData.intensity);
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1406
|
+
// Fallback: no engine, return preset metadata for artifact mode
|
|
1286
1407
|
return {
|
|
1287
1408
|
preset,
|
|
1288
|
-
applied:
|
|
1409
|
+
applied: null,
|
|
1410
|
+
load_code: `const colors = new ColorPresetsSystem((n, v) => engine.setParameter(n, v));\ncolors.applyPreset('${preset}', ${transition}, ${duration});`,
|
|
1289
1411
|
suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
|
|
1290
1412
|
};
|
|
1291
1413
|
}
|
|
@@ -1296,14 +1418,50 @@ export class MCPServer {
|
|
|
1296
1418
|
setPostProcessing(args) {
|
|
1297
1419
|
const { effects, chain_preset, clear_first = true } = args;
|
|
1298
1420
|
|
|
1421
|
+
// Try to execute live in browser context
|
|
1422
|
+
let executing = false;
|
|
1423
|
+
if (typeof document !== 'undefined') {
|
|
1424
|
+
try {
|
|
1425
|
+
const target = document.getElementById('viz-container')
|
|
1426
|
+
|| document.querySelector('.vib3-container')
|
|
1427
|
+
|| document.querySelector('canvas')?.parentElement;
|
|
1428
|
+
|
|
1429
|
+
if (target) {
|
|
1430
|
+
// Lazy-init pipeline, importing dynamically to avoid Node.js issues
|
|
1431
|
+
if (!this._postPipeline) {
|
|
1432
|
+
// PostProcessingPipeline imported statically would fail in Node;
|
|
1433
|
+
// it's already a known browser-only module, so guard at runtime
|
|
1434
|
+
const { PostProcessingPipeline: PPP } = { PostProcessingPipeline: globalThis.PostProcessingPipeline };
|
|
1435
|
+
if (PPP) {
|
|
1436
|
+
this._postPipeline = new PPP(target);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
if (this._postPipeline) {
|
|
1441
|
+
if (clear_first) this._postPipeline.clearChain?.();
|
|
1442
|
+
if (chain_preset) {
|
|
1443
|
+
this._postPipeline.loadPresetChain(chain_preset);
|
|
1444
|
+
} else if (effects) {
|
|
1445
|
+
for (const e of effects) {
|
|
1446
|
+
this._postPipeline.addEffect(e.name, { intensity: e.intensity || 0.5, ...e });
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
this._postPipeline.apply();
|
|
1450
|
+
executing = true;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
} catch { /* fall through to code generation */ }
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1299
1456
|
return {
|
|
1300
1457
|
applied: true,
|
|
1458
|
+
executing,
|
|
1301
1459
|
effects: effects || [],
|
|
1302
1460
|
chain_preset: chain_preset || null,
|
|
1303
1461
|
cleared_previous: clear_first,
|
|
1304
|
-
load_code: effects ?
|
|
1305
|
-
`const pipeline = new PostProcessingPipeline(
|
|
1306
|
-
`pipeline.
|
|
1462
|
+
load_code: executing ? null : (effects ?
|
|
1463
|
+
`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();` :
|
|
1464
|
+
`const pipeline = new PostProcessingPipeline(document.getElementById('viz-container'));\npipeline.loadPresetChain('${chain_preset}');\npipeline.apply();`),
|
|
1307
1465
|
suggested_next_actions: ['describe_visual_state', 'apply_color_preset', 'create_choreography']
|
|
1308
1466
|
};
|
|
1309
1467
|
}
|