@vib3code/sdk 2.0.3-canary.6f35b4c → 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.
- package/DOCS/EXPANSION_DESIGN.md +977 -0
- package/DOCS/EXPANSION_DESIGN_ULTRA.md +387 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +2 -2
- package/DOCS/OPTIMIZATION_PLAN_MATH.md +118 -0
- 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-15.md +142 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +108 -0
- package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +308 -0
- package/docs/webgpu-live.html +1 -1
- package/package.json +10 -1
- package/src/agent/index.js +1 -3
- package/src/agent/mcp/MCPServer.js +542 -188
- package/src/agent/mcp/index.js +1 -1
- package/src/agent/mcp/tools.js +132 -32
- package/src/cli/index.js +374 -44
- package/src/core/VIB3Engine.js +55 -3
- package/src/core/index.js +18 -0
- package/src/core/renderers/FacetedRendererAdapter.js +10 -9
- package/src/core/renderers/HolographicRendererAdapter.js +11 -7
- package/src/core/renderers/QuantumRendererAdapter.js +11 -7
- package/src/creative/index.js +11 -0
- package/src/experimental/GameLoop.js +72 -0
- package/src/experimental/LatticePhysics.js +100 -0
- package/src/experimental/LiveDirector.js +143 -0
- package/src/experimental/PlayerController4D.js +154 -0
- package/src/experimental/VIB3Actor.js +138 -0
- package/src/experimental/VIB3Compositor.js +117 -0
- package/src/experimental/VIB3Link.js +122 -0
- package/src/experimental/VIB3Orchestrator.js +146 -0
- package/src/experimental/VIB3Universe.js +109 -0
- package/src/experimental/demos/CrystalLabyrinth.js +202 -0
- package/src/export/index.js +11 -1
- package/src/faceted/FacetedSystem.js +27 -10
- package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
- package/src/geometry/generators/Crystal.js +2 -2
- package/src/holograms/HolographicVisualizer.js +58 -89
- package/src/holograms/RealHolographicSystem.js +126 -31
- package/src/math/Mat4x4.js +192 -19
- package/src/math/Rotor4D.js +93 -39
- package/src/math/Vec4.js +119 -78
- package/src/math/index.js +7 -7
- package/src/quantum/QuantumVisualizer.js +24 -20
- package/src/reactivity/index.js +3 -5
- package/src/render/LayerPresetManager.js +372 -0
- package/src/render/LayerReactivityBridge.js +344 -0
- package/src/render/LayerRelationshipGraph.js +610 -0
- package/src/render/MultiCanvasBridge.js +148 -25
- 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/render/index.js +27 -2
- package/src/scene/index.js +4 -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/testing/ParallelTestFramework.js +2 -2
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
- package/src/viewer/GalleryUI.js +17 -0
- package/src/viewer/ViewerPortal.js +2 -2
- package/tools/shader-sync-verify.js +6 -4
- package/types/adaptive-sdk.d.ts +204 -5
- package/types/agent/cli.d.ts +78 -0
- package/types/agent/index.d.ts +18 -0
- package/types/agent/mcp.d.ts +87 -0
- package/types/agent/telemetry.d.ts +190 -0
- package/types/core/VIB3Engine.d.ts +26 -0
- package/types/core/index.d.ts +261 -0
- package/types/creative/AestheticMapper.d.ts +72 -0
- package/types/creative/ChoreographyPlayer.d.ts +96 -0
- package/types/creative/index.d.ts +17 -0
- package/types/export/index.d.ts +243 -0
- package/types/geometry/index.d.ts +164 -0
- package/types/math/index.d.ts +214 -0
- package/types/render/LayerPresetManager.d.ts +78 -0
- package/types/render/LayerReactivityBridge.d.ts +85 -0
- package/types/render/LayerRelationshipGraph.d.ts +174 -0
- package/types/render/index.d.ts +3 -0
- package/types/scene/index.d.ts +204 -0
- package/types/systems/index.d.ts +244 -0
- package/types/variations/index.d.ts +62 -0
- package/types/viewer/index.d.ts +225 -0
|
@@ -9,6 +9,9 @@ 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';
|
|
14
|
+
import { PRESET_REGISTRY } from '../../render/LayerRelationshipGraph.js';
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Generate unique IDs
|
|
@@ -41,6 +44,36 @@ export class MCPServer {
|
|
|
41
44
|
this.engine = engine;
|
|
42
45
|
this.sceneId = null;
|
|
43
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;
|
|
44
77
|
}
|
|
45
78
|
|
|
46
79
|
buildResponse(operation, data, options = {}) {
|
|
@@ -140,10 +173,13 @@ export class MCPServer {
|
|
|
140
173
|
result = this.getParameterSchema();
|
|
141
174
|
break;
|
|
142
175
|
case 'get_sdk_context':
|
|
143
|
-
result = this.getSDKContext();
|
|
176
|
+
result = this.getSDKContext(args);
|
|
144
177
|
break;
|
|
145
|
-
case '
|
|
146
|
-
result = this.
|
|
178
|
+
case 'inspect_layers':
|
|
179
|
+
result = this.inspectLayers(args);
|
|
180
|
+
break;
|
|
181
|
+
case 'set_holographic_layer':
|
|
182
|
+
result = this.setHolographicLayer(args);
|
|
147
183
|
break;
|
|
148
184
|
// Reactivity tools (Phase 6.5)
|
|
149
185
|
case 'set_reactivity_config':
|
|
@@ -204,6 +240,22 @@ export class MCPServer {
|
|
|
204
240
|
case 'control_timeline':
|
|
205
241
|
result = this.controlTimeline(args);
|
|
206
242
|
break;
|
|
243
|
+
// Layer relationship tools (Phase 8)
|
|
244
|
+
case 'set_layer_profile':
|
|
245
|
+
result = this.setLayerProfile(args);
|
|
246
|
+
break;
|
|
247
|
+
case 'set_layer_relationship':
|
|
248
|
+
result = this.setLayerRelationship(args);
|
|
249
|
+
break;
|
|
250
|
+
case 'set_layer_keystone':
|
|
251
|
+
result = this.setLayerKeystone(args);
|
|
252
|
+
break;
|
|
253
|
+
case 'get_layer_config':
|
|
254
|
+
result = this.getLayerConfig();
|
|
255
|
+
break;
|
|
256
|
+
case 'tune_layer_relationship':
|
|
257
|
+
result = this.tuneLayerRelationship(args);
|
|
258
|
+
break;
|
|
207
259
|
default:
|
|
208
260
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
209
261
|
}
|
|
@@ -467,32 +519,68 @@ export class MCPServer {
|
|
|
467
519
|
|
|
468
520
|
telemetry.recordEvent(EventType.GALLERY_SAVE, { slot });
|
|
469
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
|
+
|
|
470
532
|
return {
|
|
471
533
|
slot,
|
|
472
534
|
name: name || `Variation ${slot}`,
|
|
473
535
|
saved_at: new Date().toISOString(),
|
|
536
|
+
persisted: !!this.engine,
|
|
537
|
+
gallery_size: this._gallerySlots.size,
|
|
474
538
|
suggested_next_actions: ['load_from_gallery', 'randomize_parameters']
|
|
475
539
|
};
|
|
476
540
|
}
|
|
477
541
|
|
|
478
542
|
/**
|
|
479
|
-
* Load from gallery
|
|
543
|
+
* Load from gallery — restores previously saved state
|
|
480
544
|
*/
|
|
481
545
|
loadFromGallery(args) {
|
|
482
546
|
const { slot } = args;
|
|
483
547
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
+
};
|
|
488
562
|
}
|
|
489
563
|
|
|
490
|
-
|
|
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
|
+
}
|
|
491
578
|
|
|
492
579
|
return {
|
|
493
580
|
slot,
|
|
494
581
|
loaded_at: new Date().toISOString(),
|
|
495
|
-
|
|
582
|
+
restored: false,
|
|
583
|
+
note: 'Engine not initialized — cannot apply state'
|
|
496
584
|
};
|
|
497
585
|
}
|
|
498
586
|
|
|
@@ -565,162 +653,218 @@ export class MCPServer {
|
|
|
565
653
|
/**
|
|
566
654
|
* Get SDK context for agent onboarding
|
|
567
655
|
*/
|
|
568
|
-
getSDKContext() {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
+
}
|
|
593
685
|
},
|
|
594
686
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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 }
|
|
600
700
|
},
|
|
601
701
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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'
|
|
607
709
|
},
|
|
608
710
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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
|
+
};
|
|
613
719
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
'Q1: How many rotation planes? a)3 b)4 c)6 d)8',
|
|
618
|
-
'Q2: Geometry encoding formula? a)base*3+core b)core*8+base c)base+core d)core*base',
|
|
619
|
-
'Q3: Canvas layers per system? a)3 b)4 c)5 d)6',
|
|
620
|
-
'Q4: Which are the 3 ACTIVE systems? a)quantum,faceted,holographic b)quantum,faceted,polychora c)all four d)none',
|
|
621
|
-
'Q5: How many base geometry types? a)6 b)8 c)10 d)24',
|
|
622
|
-
'Q6: Core warp types? a)base,sphere,cube b)base,hypersphere,hypertetrahedron c)2D,3D,4D d)none'
|
|
623
|
-
]
|
|
624
|
-
},
|
|
720
|
+
if (include_state) {
|
|
721
|
+
context.current_state = this.getState();
|
|
722
|
+
}
|
|
625
723
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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
|
+
}
|
|
632
730
|
|
|
633
|
-
|
|
634
|
-
};
|
|
731
|
+
return context;
|
|
635
732
|
}
|
|
636
733
|
|
|
637
734
|
/**
|
|
638
|
-
*
|
|
735
|
+
* Inspect holographic layer state — returns per-layer metadata in JSON format.
|
|
736
|
+
* This replaces the old verify_knowledge quiz with something actually useful.
|
|
639
737
|
*/
|
|
640
|
-
|
|
641
|
-
const
|
|
642
|
-
q1_rotation_planes: 'c', // 6 rotation planes
|
|
643
|
-
q2_geometry_formula: 'b', // core*8+base
|
|
644
|
-
q3_canvas_layers: 'c', // 5 layers
|
|
645
|
-
q4_active_systems: 'a', // quantum, faceted, holographic (polychora is TBD)
|
|
646
|
-
q5_base_geometries: 'b', // 8 base geometries
|
|
647
|
-
q6_core_types: 'b' // base, hypersphere, hypertetrahedron
|
|
648
|
-
};
|
|
738
|
+
inspectLayers(args = {}) {
|
|
739
|
+
const { layer = 'all' } = args;
|
|
649
740
|
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
},
|
|
676
|
-
|
|
677
|
-
topic: 'CORE WARP TYPES',
|
|
678
|
-
doc: '24-GEOMETRY-6D-ROTATION-SUMMARY.md',
|
|
679
|
-
reason: '3 cores: base (no warp), hypersphere, hypertetrahedron'
|
|
680
|
-
}
|
|
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 }
|
|
681
768
|
};
|
|
682
769
|
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
+
};
|
|
688
787
|
};
|
|
689
788
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
correct_answer: correct
|
|
702
|
-
});
|
|
703
|
-
results.REVIEW_REQUIRED.push(docReferences[question]);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
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
|
+
}
|
|
706
800
|
|
|
707
|
-
|
|
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;
|
|
708
807
|
|
|
709
|
-
|
|
710
|
-
if (
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
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
|
+
};
|
|
719
818
|
}
|
|
720
819
|
|
|
721
|
-
|
|
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
|
+
}
|
|
722
861
|
|
|
723
|
-
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
|
+
};
|
|
724
868
|
}
|
|
725
869
|
|
|
726
870
|
/**
|
|
@@ -1200,8 +1344,17 @@ export class MCPServer {
|
|
|
1200
1344
|
(sum, step) => sum + step.duration + step.delay, 0
|
|
1201
1345
|
);
|
|
1202
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
|
+
|
|
1203
1355
|
return {
|
|
1204
1356
|
transition_id: transitionId,
|
|
1357
|
+
executing,
|
|
1205
1358
|
step_count: normalizedSequence.length,
|
|
1206
1359
|
total_duration_ms: totalDuration,
|
|
1207
1360
|
steps: normalizedSequence.map((step, i) => ({
|
|
@@ -1211,7 +1364,7 @@ export class MCPServer {
|
|
|
1211
1364
|
easing: step.easing,
|
|
1212
1365
|
delay: step.delay
|
|
1213
1366
|
})),
|
|
1214
|
-
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)});`,
|
|
1215
1368
|
suggested_next_actions: ['describe_visual_state', 'create_timeline', 'save_to_gallery']
|
|
1216
1369
|
};
|
|
1217
1370
|
}
|
|
@@ -1220,55 +1373,41 @@ export class MCPServer {
|
|
|
1220
1373
|
* Apply a named color preset
|
|
1221
1374
|
*/
|
|
1222
1375
|
applyColorPreset(args) {
|
|
1223
|
-
const { preset } = args;
|
|
1376
|
+
const { preset, transition = true, duration = 800 } = args;
|
|
1224
1377
|
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
Midnight: { hue: 240, saturation: 0.6, intensity: 0.3 },
|
|
1244
|
-
Tropical: { hue: 160, saturation: 0.8, intensity: 0.7 },
|
|
1245
|
-
Ethereal: { hue: 220, saturation: 0.4, intensity: 0.7 },
|
|
1246
|
-
Volcanic: { hue: 5, saturation: 0.95, intensity: 0.6 },
|
|
1247
|
-
Holographic: { hue: 180, saturation: 0.6, intensity: 0.8 },
|
|
1248
|
-
Vaporwave: { hue: 310, saturation: 0.7, intensity: 0.7 }
|
|
1249
|
-
};
|
|
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);
|
|
1250
1396
|
|
|
1251
|
-
const presetData = COLOR_PRESETS[preset];
|
|
1252
|
-
if (!presetData) {
|
|
1253
1397
|
return {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
}
|
|
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']
|
|
1260
1403
|
};
|
|
1261
1404
|
}
|
|
1262
1405
|
|
|
1263
|
-
|
|
1264
|
-
this.engine.setParameter('hue', presetData.hue);
|
|
1265
|
-
this.engine.setParameter('saturation', presetData.saturation);
|
|
1266
|
-
this.engine.setParameter('intensity', presetData.intensity);
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1406
|
+
// Fallback: no engine, return preset metadata for artifact mode
|
|
1269
1407
|
return {
|
|
1270
1408
|
preset,
|
|
1271
|
-
applied:
|
|
1409
|
+
applied: null,
|
|
1410
|
+
load_code: `const colors = new ColorPresetsSystem((n, v) => engine.setParameter(n, v));\ncolors.applyPreset('${preset}', ${transition}, ${duration});`,
|
|
1272
1411
|
suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
|
|
1273
1412
|
};
|
|
1274
1413
|
}
|
|
@@ -1279,14 +1418,50 @@ export class MCPServer {
|
|
|
1279
1418
|
setPostProcessing(args) {
|
|
1280
1419
|
const { effects, chain_preset, clear_first = true } = args;
|
|
1281
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
|
+
|
|
1282
1456
|
return {
|
|
1283
1457
|
applied: true,
|
|
1458
|
+
executing,
|
|
1284
1459
|
effects: effects || [],
|
|
1285
1460
|
chain_preset: chain_preset || null,
|
|
1286
1461
|
cleared_previous: clear_first,
|
|
1287
|
-
load_code: effects ?
|
|
1288
|
-
`const pipeline = new PostProcessingPipeline(
|
|
1289
|
-
`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();`),
|
|
1290
1465
|
suggested_next_actions: ['describe_visual_state', 'apply_color_preset', 'create_choreography']
|
|
1291
1466
|
};
|
|
1292
1467
|
}
|
|
@@ -1665,6 +1840,185 @@ export class MCPServer {
|
|
|
1665
1840
|
suggested_next_actions: ['control_timeline', 'describe_visual_state', 'capture_screenshot']
|
|
1666
1841
|
};
|
|
1667
1842
|
}
|
|
1843
|
+
|
|
1844
|
+
// ====================================================================
|
|
1845
|
+
// Layer Relationship Tools (Phase 8)
|
|
1846
|
+
// ====================================================================
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* Get the holographic system's layer graph (if available).
|
|
1850
|
+
* @private
|
|
1851
|
+
* @returns {import('../../render/LayerRelationshipGraph.js').LayerRelationshipGraph|null}
|
|
1852
|
+
*/
|
|
1853
|
+
_getLayerGraph() {
|
|
1854
|
+
if (!this.engine) return null;
|
|
1855
|
+
// Try to access the current system's layer graph
|
|
1856
|
+
const system = this.engine.currentSystem || this.engine._activeSystem;
|
|
1857
|
+
if (system && system.layerGraph) {
|
|
1858
|
+
return system.layerGraph;
|
|
1859
|
+
}
|
|
1860
|
+
if (system && system._layerGraph) {
|
|
1861
|
+
return system._layerGraph;
|
|
1862
|
+
}
|
|
1863
|
+
return null;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* Load a named layer relationship profile.
|
|
1868
|
+
*/
|
|
1869
|
+
setLayerProfile(args) {
|
|
1870
|
+
const { profile } = args;
|
|
1871
|
+
const graph = this._getLayerGraph();
|
|
1872
|
+
|
|
1873
|
+
if (!graph) {
|
|
1874
|
+
return {
|
|
1875
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1876
|
+
suggested_next_actions: ['switch_system']
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
graph.loadProfile(profile);
|
|
1881
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, { type: 'layer_profile', profile });
|
|
1882
|
+
|
|
1883
|
+
return {
|
|
1884
|
+
profile,
|
|
1885
|
+
keystone: graph.keystone,
|
|
1886
|
+
active_profile: graph.activeProfile,
|
|
1887
|
+
available_profiles: ['holographic', 'symmetry', 'chord', 'storm', 'legacy'],
|
|
1888
|
+
suggested_next_actions: ['get_layer_config', 'set_layer_relationship', 'tune_layer_relationship']
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
/**
|
|
1893
|
+
* Set relationship for a specific layer.
|
|
1894
|
+
*/
|
|
1895
|
+
setLayerRelationship(args) {
|
|
1896
|
+
const { layer, relationship, config } = args;
|
|
1897
|
+
const graph = this._getLayerGraph();
|
|
1898
|
+
|
|
1899
|
+
if (!graph) {
|
|
1900
|
+
return {
|
|
1901
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1902
|
+
suggested_next_actions: ['switch_system']
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
if (config) {
|
|
1907
|
+
graph.setRelationship(layer, { preset: relationship, config });
|
|
1908
|
+
} else {
|
|
1909
|
+
graph.setRelationship(layer, relationship);
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, {
|
|
1913
|
+
type: 'layer_relationship', layer, relationship
|
|
1914
|
+
});
|
|
1915
|
+
|
|
1916
|
+
return {
|
|
1917
|
+
layer,
|
|
1918
|
+
relationship,
|
|
1919
|
+
config: config || {},
|
|
1920
|
+
keystone: graph.keystone,
|
|
1921
|
+
suggested_next_actions: ['get_layer_config', 'tune_layer_relationship', 'describe_visual_state']
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
/**
|
|
1926
|
+
* Change the keystone (driver) layer.
|
|
1927
|
+
*/
|
|
1928
|
+
setLayerKeystone(args) {
|
|
1929
|
+
const { layer } = args;
|
|
1930
|
+
const graph = this._getLayerGraph();
|
|
1931
|
+
|
|
1932
|
+
if (!graph) {
|
|
1933
|
+
return {
|
|
1934
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1935
|
+
suggested_next_actions: ['switch_system']
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
graph.setKeystone(layer);
|
|
1940
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, { type: 'layer_keystone', layer });
|
|
1941
|
+
|
|
1942
|
+
return {
|
|
1943
|
+
keystone: layer,
|
|
1944
|
+
note: 'Other layers\' relationships are preserved. Set new relationships for the old keystone if needed.',
|
|
1945
|
+
suggested_next_actions: ['set_layer_relationship', 'get_layer_config']
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
/**
|
|
1950
|
+
* Get current layer configuration.
|
|
1951
|
+
*/
|
|
1952
|
+
getLayerConfig() {
|
|
1953
|
+
const graph = this._getLayerGraph();
|
|
1954
|
+
|
|
1955
|
+
if (!graph) {
|
|
1956
|
+
return {
|
|
1957
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1958
|
+
suggested_next_actions: ['switch_system']
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
const config = graph.exportConfig();
|
|
1963
|
+
|
|
1964
|
+
return {
|
|
1965
|
+
keystone: config.keystone,
|
|
1966
|
+
active_profile: config.profile,
|
|
1967
|
+
relationships: config.relationships,
|
|
1968
|
+
shaders: config.shaders,
|
|
1969
|
+
available_profiles: ['holographic', 'symmetry', 'chord', 'storm', 'legacy'],
|
|
1970
|
+
available_presets: ['echo', 'mirror', 'complement', 'harmonic', 'reactive', 'chase'],
|
|
1971
|
+
suggested_next_actions: ['set_layer_profile', 'set_layer_relationship', 'tune_layer_relationship']
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
/**
|
|
1976
|
+
* Tune a layer's relationship config.
|
|
1977
|
+
*/
|
|
1978
|
+
tuneLayerRelationship(args) {
|
|
1979
|
+
const { layer, config: configOverrides } = args;
|
|
1980
|
+
const graph = this._getLayerGraph();
|
|
1981
|
+
|
|
1982
|
+
if (!graph) {
|
|
1983
|
+
return {
|
|
1984
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1985
|
+
suggested_next_actions: ['switch_system']
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
const graphConfig = graph.exportConfig();
|
|
1990
|
+
const currentRel = graphConfig.relationships[layer];
|
|
1991
|
+
|
|
1992
|
+
if (!currentRel || !currentRel.preset) {
|
|
1993
|
+
return {
|
|
1994
|
+
error: `Layer "${layer}" has no tunable preset relationship. Set one first with set_layer_relationship.`,
|
|
1995
|
+
suggested_next_actions: ['set_layer_relationship']
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
const factory = PRESET_REGISTRY[currentRel.preset];
|
|
2000
|
+
if (!factory) {
|
|
2001
|
+
return {
|
|
2002
|
+
error: `Unknown preset "${currentRel.preset}" on layer "${layer}".`,
|
|
2003
|
+
suggested_next_actions: ['set_layer_relationship']
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
const newConfig = { ...(currentRel.config || {}), ...configOverrides };
|
|
2008
|
+
graph.setRelationship(layer, { preset: currentRel.preset, config: newConfig });
|
|
2009
|
+
|
|
2010
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, {
|
|
2011
|
+
type: 'layer_tune', layer, tuned_keys: Object.keys(configOverrides)
|
|
2012
|
+
});
|
|
2013
|
+
|
|
2014
|
+
return {
|
|
2015
|
+
layer,
|
|
2016
|
+
preset: currentRel.preset,
|
|
2017
|
+
previous_config: currentRel.config,
|
|
2018
|
+
new_config: newConfig,
|
|
2019
|
+
suggested_next_actions: ['get_layer_config', 'describe_visual_state', 'capture_screenshot']
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
1668
2022
|
}
|
|
1669
2023
|
|
|
1670
2024
|
// Singleton instance
|