@vib3code/sdk 2.0.3-canary.91a95f3 → 2.0.3-canary.ef8d292
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-13.md +13 -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/webgpu-live.html +1 -1
- package/package.json +10 -1
- package/src/agent/index.js +1 -3
- package/src/agent/mcp/MCPServer.js +347 -52
- package/src/agent/mcp/index.js +1 -1
- package/src/agent/mcp/tools.js +87 -0
- 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/export/index.js +11 -1
- package/src/faceted/FacetedSystem.js +27 -10
- package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
- package/src/holograms/HolographicVisualizer.js +58 -89
- package/src/holograms/RealHolographicSystem.js +126 -31
- package/src/math/Mat4x4.js +70 -13
- package/src/math/Rotor4D.js +100 -39
- 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 = {}) {
|
|
@@ -204,6 +237,22 @@ export class MCPServer {
|
|
|
204
237
|
case 'control_timeline':
|
|
205
238
|
result = this.controlTimeline(args);
|
|
206
239
|
break;
|
|
240
|
+
// Layer relationship tools (Phase 8)
|
|
241
|
+
case 'set_layer_profile':
|
|
242
|
+
result = this.setLayerProfile(args);
|
|
243
|
+
break;
|
|
244
|
+
case 'set_layer_relationship':
|
|
245
|
+
result = this.setLayerRelationship(args);
|
|
246
|
+
break;
|
|
247
|
+
case 'set_layer_keystone':
|
|
248
|
+
result = this.setLayerKeystone(args);
|
|
249
|
+
break;
|
|
250
|
+
case 'get_layer_config':
|
|
251
|
+
result = this.getLayerConfig();
|
|
252
|
+
break;
|
|
253
|
+
case 'tune_layer_relationship':
|
|
254
|
+
result = this.tuneLayerRelationship(args);
|
|
255
|
+
break;
|
|
207
256
|
default:
|
|
208
257
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
209
258
|
}
|
|
@@ -467,32 +516,68 @@ export class MCPServer {
|
|
|
467
516
|
|
|
468
517
|
telemetry.recordEvent(EventType.GALLERY_SAVE, { slot });
|
|
469
518
|
|
|
519
|
+
// Persist actual engine state if available
|
|
520
|
+
if (this.engine) {
|
|
521
|
+
const state = this.engine.exportState();
|
|
522
|
+
this._gallerySlots.set(slot, {
|
|
523
|
+
name: name || `Variation ${slot}`,
|
|
524
|
+
saved_at: new Date().toISOString(),
|
|
525
|
+
state
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
470
529
|
return {
|
|
471
530
|
slot,
|
|
472
531
|
name: name || `Variation ${slot}`,
|
|
473
532
|
saved_at: new Date().toISOString(),
|
|
533
|
+
persisted: !!this.engine,
|
|
534
|
+
gallery_size: this._gallerySlots.size,
|
|
474
535
|
suggested_next_actions: ['load_from_gallery', 'randomize_parameters']
|
|
475
536
|
};
|
|
476
537
|
}
|
|
477
538
|
|
|
478
539
|
/**
|
|
479
|
-
* Load from gallery
|
|
540
|
+
* Load from gallery — restores previously saved state
|
|
480
541
|
*/
|
|
481
542
|
loadFromGallery(args) {
|
|
482
543
|
const { slot } = args;
|
|
483
544
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
545
|
+
telemetry.recordEvent(EventType.GALLERY_LOAD, { slot });
|
|
546
|
+
|
|
547
|
+
const saved = this._gallerySlots.get(slot);
|
|
548
|
+
if (saved && this.engine) {
|
|
549
|
+
// Restore saved state
|
|
550
|
+
this.engine.importState(saved.state);
|
|
551
|
+
return {
|
|
552
|
+
slot,
|
|
553
|
+
name: saved.name,
|
|
554
|
+
saved_at: saved.saved_at,
|
|
555
|
+
loaded_at: new Date().toISOString(),
|
|
556
|
+
restored: true,
|
|
557
|
+
...this.getState()
|
|
558
|
+
};
|
|
488
559
|
}
|
|
489
560
|
|
|
490
|
-
|
|
561
|
+
if (!saved) {
|
|
562
|
+
// No saved state — fall back to random variation
|
|
563
|
+
if (this.engine) {
|
|
564
|
+
const params = this.engine.parameters?.generateVariationParameters?.(slot) || {};
|
|
565
|
+
this.engine.setParameters(params);
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
slot,
|
|
569
|
+
loaded_at: new Date().toISOString(),
|
|
570
|
+
restored: false,
|
|
571
|
+
note: 'No saved state in this slot — generated random variation',
|
|
572
|
+
...this.getState()
|
|
573
|
+
};
|
|
574
|
+
}
|
|
491
575
|
|
|
492
576
|
return {
|
|
493
577
|
slot,
|
|
494
578
|
loaded_at: new Date().toISOString(),
|
|
495
|
-
|
|
579
|
+
restored: false,
|
|
580
|
+
note: 'Engine not initialized — cannot apply state'
|
|
496
581
|
};
|
|
497
582
|
}
|
|
498
583
|
|
|
@@ -1200,8 +1285,17 @@ export class MCPServer {
|
|
|
1200
1285
|
(sum, step) => sum + step.duration + step.delay, 0
|
|
1201
1286
|
);
|
|
1202
1287
|
|
|
1288
|
+
// Execute live if engine available
|
|
1289
|
+
let executing = false;
|
|
1290
|
+
const animator = this._getTransitionAnimator();
|
|
1291
|
+
if (animator) {
|
|
1292
|
+
const seqId = animator.sequence(normalizedSequence);
|
|
1293
|
+
executing = !!seqId;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1203
1296
|
return {
|
|
1204
1297
|
transition_id: transitionId,
|
|
1298
|
+
executing,
|
|
1205
1299
|
step_count: normalizedSequence.length,
|
|
1206
1300
|
total_duration_ms: totalDuration,
|
|
1207
1301
|
steps: normalizedSequence.map((step, i) => ({
|
|
@@ -1211,7 +1305,7 @@ export class MCPServer {
|
|
|
1211
1305
|
easing: step.easing,
|
|
1212
1306
|
delay: step.delay
|
|
1213
1307
|
})),
|
|
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)});`,
|
|
1308
|
+
load_code: executing ? null : `const animator = new TransitionAnimator(\n (n, v) => engine.setParameter(n, v),\n (n) => engine.getParameter(n)\n);\nanimator.sequence(${JSON.stringify(normalizedSequence)});`,
|
|
1215
1309
|
suggested_next_actions: ['describe_visual_state', 'create_timeline', 'save_to_gallery']
|
|
1216
1310
|
};
|
|
1217
1311
|
}
|
|
@@ -1220,55 +1314,41 @@ export class MCPServer {
|
|
|
1220
1314
|
* Apply a named color preset
|
|
1221
1315
|
*/
|
|
1222
1316
|
applyColorPreset(args) {
|
|
1223
|
-
const { preset } = args;
|
|
1317
|
+
const { preset, transition = true, duration = 800 } = args;
|
|
1224
1318
|
|
|
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
|
-
};
|
|
1319
|
+
const colorSystem = this._getColorPresets();
|
|
1320
|
+
|
|
1321
|
+
if (colorSystem) {
|
|
1322
|
+
// Use real ColorPresetsSystem — full preset library with transitions
|
|
1323
|
+
const config = colorSystem.getPreset(preset);
|
|
1324
|
+
if (!config) {
|
|
1325
|
+
const allPresets = colorSystem.getPresets().map(p => p.name);
|
|
1326
|
+
return {
|
|
1327
|
+
error: {
|
|
1328
|
+
type: 'ValidationError',
|
|
1329
|
+
code: 'INVALID_COLOR_PRESET',
|
|
1330
|
+
message: `Unknown color preset: ${preset}`,
|
|
1331
|
+
valid_options: allPresets
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
colorSystem.applyPreset(preset, transition, duration);
|
|
1250
1337
|
|
|
1251
|
-
const presetData = COLOR_PRESETS[preset];
|
|
1252
|
-
if (!presetData) {
|
|
1253
1338
|
return {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
}
|
|
1339
|
+
preset,
|
|
1340
|
+
applied: { hue: config.hue, saturation: config.saturation, intensity: config.intensity },
|
|
1341
|
+
transition: transition ? { enabled: true, duration } : { enabled: false },
|
|
1342
|
+
full_config: config,
|
|
1343
|
+
suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
|
|
1260
1344
|
};
|
|
1261
1345
|
}
|
|
1262
1346
|
|
|
1263
|
-
|
|
1264
|
-
this.engine.setParameter('hue', presetData.hue);
|
|
1265
|
-
this.engine.setParameter('saturation', presetData.saturation);
|
|
1266
|
-
this.engine.setParameter('intensity', presetData.intensity);
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1347
|
+
// Fallback: no engine, return preset metadata for artifact mode
|
|
1269
1348
|
return {
|
|
1270
1349
|
preset,
|
|
1271
|
-
applied:
|
|
1350
|
+
applied: null,
|
|
1351
|
+
load_code: `const colors = new ColorPresetsSystem((n, v) => engine.setParameter(n, v));\ncolors.applyPreset('${preset}', ${transition}, ${duration});`,
|
|
1272
1352
|
suggested_next_actions: ['set_post_processing', 'describe_visual_state', 'set_visual_parameters']
|
|
1273
1353
|
};
|
|
1274
1354
|
}
|
|
@@ -1279,14 +1359,50 @@ export class MCPServer {
|
|
|
1279
1359
|
setPostProcessing(args) {
|
|
1280
1360
|
const { effects, chain_preset, clear_first = true } = args;
|
|
1281
1361
|
|
|
1362
|
+
// Try to execute live in browser context
|
|
1363
|
+
let executing = false;
|
|
1364
|
+
if (typeof document !== 'undefined') {
|
|
1365
|
+
try {
|
|
1366
|
+
const target = document.getElementById('viz-container')
|
|
1367
|
+
|| document.querySelector('.vib3-container')
|
|
1368
|
+
|| document.querySelector('canvas')?.parentElement;
|
|
1369
|
+
|
|
1370
|
+
if (target) {
|
|
1371
|
+
// Lazy-init pipeline, importing dynamically to avoid Node.js issues
|
|
1372
|
+
if (!this._postPipeline) {
|
|
1373
|
+
// PostProcessingPipeline imported statically would fail in Node;
|
|
1374
|
+
// it's already a known browser-only module, so guard at runtime
|
|
1375
|
+
const { PostProcessingPipeline: PPP } = { PostProcessingPipeline: globalThis.PostProcessingPipeline };
|
|
1376
|
+
if (PPP) {
|
|
1377
|
+
this._postPipeline = new PPP(target);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if (this._postPipeline) {
|
|
1382
|
+
if (clear_first) this._postPipeline.clearChain?.();
|
|
1383
|
+
if (chain_preset) {
|
|
1384
|
+
this._postPipeline.loadPresetChain(chain_preset);
|
|
1385
|
+
} else if (effects) {
|
|
1386
|
+
for (const e of effects) {
|
|
1387
|
+
this._postPipeline.addEffect(e.name, { intensity: e.intensity || 0.5, ...e });
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
this._postPipeline.apply();
|
|
1391
|
+
executing = true;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
} catch { /* fall through to code generation */ }
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1282
1397
|
return {
|
|
1283
1398
|
applied: true,
|
|
1399
|
+
executing,
|
|
1284
1400
|
effects: effects || [],
|
|
1285
1401
|
chain_preset: chain_preset || null,
|
|
1286
1402
|
cleared_previous: clear_first,
|
|
1287
|
-
load_code: effects ?
|
|
1288
|
-
`const pipeline = new PostProcessingPipeline(
|
|
1289
|
-
`pipeline.
|
|
1403
|
+
load_code: executing ? null : (effects ?
|
|
1404
|
+
`const pipeline = new PostProcessingPipeline(document.getElementById('viz-container'));\n${effects.map(e => `pipeline.addEffect('${e.name}', { intensity: ${e.intensity || 0.5} });`).join('\n')}\npipeline.apply();` :
|
|
1405
|
+
`const pipeline = new PostProcessingPipeline(document.getElementById('viz-container'));\npipeline.loadPresetChain('${chain_preset}');\npipeline.apply();`),
|
|
1290
1406
|
suggested_next_actions: ['describe_visual_state', 'apply_color_preset', 'create_choreography']
|
|
1291
1407
|
};
|
|
1292
1408
|
}
|
|
@@ -1665,6 +1781,185 @@ export class MCPServer {
|
|
|
1665
1781
|
suggested_next_actions: ['control_timeline', 'describe_visual_state', 'capture_screenshot']
|
|
1666
1782
|
};
|
|
1667
1783
|
}
|
|
1784
|
+
|
|
1785
|
+
// ====================================================================
|
|
1786
|
+
// Layer Relationship Tools (Phase 8)
|
|
1787
|
+
// ====================================================================
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
* Get the holographic system's layer graph (if available).
|
|
1791
|
+
* @private
|
|
1792
|
+
* @returns {import('../../render/LayerRelationshipGraph.js').LayerRelationshipGraph|null}
|
|
1793
|
+
*/
|
|
1794
|
+
_getLayerGraph() {
|
|
1795
|
+
if (!this.engine) return null;
|
|
1796
|
+
// Try to access the current system's layer graph
|
|
1797
|
+
const system = this.engine.currentSystem || this.engine._activeSystem;
|
|
1798
|
+
if (system && system.layerGraph) {
|
|
1799
|
+
return system.layerGraph;
|
|
1800
|
+
}
|
|
1801
|
+
if (system && system._layerGraph) {
|
|
1802
|
+
return system._layerGraph;
|
|
1803
|
+
}
|
|
1804
|
+
return null;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
/**
|
|
1808
|
+
* Load a named layer relationship profile.
|
|
1809
|
+
*/
|
|
1810
|
+
setLayerProfile(args) {
|
|
1811
|
+
const { profile } = args;
|
|
1812
|
+
const graph = this._getLayerGraph();
|
|
1813
|
+
|
|
1814
|
+
if (!graph) {
|
|
1815
|
+
return {
|
|
1816
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1817
|
+
suggested_next_actions: ['switch_system']
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
graph.loadProfile(profile);
|
|
1822
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, { type: 'layer_profile', profile });
|
|
1823
|
+
|
|
1824
|
+
return {
|
|
1825
|
+
profile,
|
|
1826
|
+
keystone: graph.keystone,
|
|
1827
|
+
active_profile: graph.activeProfile,
|
|
1828
|
+
available_profiles: ['holographic', 'symmetry', 'chord', 'storm', 'legacy'],
|
|
1829
|
+
suggested_next_actions: ['get_layer_config', 'set_layer_relationship', 'tune_layer_relationship']
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
/**
|
|
1834
|
+
* Set relationship for a specific layer.
|
|
1835
|
+
*/
|
|
1836
|
+
setLayerRelationship(args) {
|
|
1837
|
+
const { layer, relationship, config } = args;
|
|
1838
|
+
const graph = this._getLayerGraph();
|
|
1839
|
+
|
|
1840
|
+
if (!graph) {
|
|
1841
|
+
return {
|
|
1842
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1843
|
+
suggested_next_actions: ['switch_system']
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
if (config) {
|
|
1848
|
+
graph.setRelationship(layer, { preset: relationship, config });
|
|
1849
|
+
} else {
|
|
1850
|
+
graph.setRelationship(layer, relationship);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, {
|
|
1854
|
+
type: 'layer_relationship', layer, relationship
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1857
|
+
return {
|
|
1858
|
+
layer,
|
|
1859
|
+
relationship,
|
|
1860
|
+
config: config || {},
|
|
1861
|
+
keystone: graph.keystone,
|
|
1862
|
+
suggested_next_actions: ['get_layer_config', 'tune_layer_relationship', 'describe_visual_state']
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* Change the keystone (driver) layer.
|
|
1868
|
+
*/
|
|
1869
|
+
setLayerKeystone(args) {
|
|
1870
|
+
const { layer } = 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.setKeystone(layer);
|
|
1881
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, { type: 'layer_keystone', layer });
|
|
1882
|
+
|
|
1883
|
+
return {
|
|
1884
|
+
keystone: layer,
|
|
1885
|
+
note: 'Other layers\' relationships are preserved. Set new relationships for the old keystone if needed.',
|
|
1886
|
+
suggested_next_actions: ['set_layer_relationship', 'get_layer_config']
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
/**
|
|
1891
|
+
* Get current layer configuration.
|
|
1892
|
+
*/
|
|
1893
|
+
getLayerConfig() {
|
|
1894
|
+
const graph = this._getLayerGraph();
|
|
1895
|
+
|
|
1896
|
+
if (!graph) {
|
|
1897
|
+
return {
|
|
1898
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1899
|
+
suggested_next_actions: ['switch_system']
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
const config = graph.exportConfig();
|
|
1904
|
+
|
|
1905
|
+
return {
|
|
1906
|
+
keystone: config.keystone,
|
|
1907
|
+
active_profile: config.profile,
|
|
1908
|
+
relationships: config.relationships,
|
|
1909
|
+
shaders: config.shaders,
|
|
1910
|
+
available_profiles: ['holographic', 'symmetry', 'chord', 'storm', 'legacy'],
|
|
1911
|
+
available_presets: ['echo', 'mirror', 'complement', 'harmonic', 'reactive', 'chase'],
|
|
1912
|
+
suggested_next_actions: ['set_layer_profile', 'set_layer_relationship', 'tune_layer_relationship']
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
/**
|
|
1917
|
+
* Tune a layer's relationship config.
|
|
1918
|
+
*/
|
|
1919
|
+
tuneLayerRelationship(args) {
|
|
1920
|
+
const { layer, config: configOverrides } = args;
|
|
1921
|
+
const graph = this._getLayerGraph();
|
|
1922
|
+
|
|
1923
|
+
if (!graph) {
|
|
1924
|
+
return {
|
|
1925
|
+
error: 'Layer relationship graph not available. Switch to holographic system first.',
|
|
1926
|
+
suggested_next_actions: ['switch_system']
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
const graphConfig = graph.exportConfig();
|
|
1931
|
+
const currentRel = graphConfig.relationships[layer];
|
|
1932
|
+
|
|
1933
|
+
if (!currentRel || !currentRel.preset) {
|
|
1934
|
+
return {
|
|
1935
|
+
error: `Layer "${layer}" has no tunable preset relationship. Set one first with set_layer_relationship.`,
|
|
1936
|
+
suggested_next_actions: ['set_layer_relationship']
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
const factory = PRESET_REGISTRY[currentRel.preset];
|
|
1941
|
+
if (!factory) {
|
|
1942
|
+
return {
|
|
1943
|
+
error: `Unknown preset "${currentRel.preset}" on layer "${layer}".`,
|
|
1944
|
+
suggested_next_actions: ['set_layer_relationship']
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
const newConfig = { ...(currentRel.config || {}), ...configOverrides };
|
|
1949
|
+
graph.setRelationship(layer, { preset: currentRel.preset, config: newConfig });
|
|
1950
|
+
|
|
1951
|
+
telemetry.recordEvent(EventType.PARAMETER_CHANGE, {
|
|
1952
|
+
type: 'layer_tune', layer, tuned_keys: Object.keys(configOverrides)
|
|
1953
|
+
});
|
|
1954
|
+
|
|
1955
|
+
return {
|
|
1956
|
+
layer,
|
|
1957
|
+
preset: currentRel.preset,
|
|
1958
|
+
previous_config: currentRel.config,
|
|
1959
|
+
new_config: newConfig,
|
|
1960
|
+
suggested_next_actions: ['get_layer_config', 'describe_visual_state', 'capture_screenshot']
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1668
1963
|
}
|
|
1669
1964
|
|
|
1670
1965
|
// Singleton instance
|
package/src/agent/mcp/index.js
CHANGED
package/src/agent/mcp/tools.js
CHANGED
|
@@ -762,6 +762,93 @@ export const toolDefinitions = {
|
|
|
762
762
|
},
|
|
763
763
|
required: ['timeline_id', 'action']
|
|
764
764
|
}
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
// Layer Relationship Tools (Phase 8)
|
|
768
|
+
set_layer_profile: {
|
|
769
|
+
name: 'set_layer_profile',
|
|
770
|
+
description: 'Loads a named layer relationship profile that configures how the 5 canvas layers relate to each other. Profiles: holographic (default), symmetry, chord, storm, legacy (original static behavior).',
|
|
771
|
+
inputSchema: {
|
|
772
|
+
type: 'object',
|
|
773
|
+
properties: {
|
|
774
|
+
profile: {
|
|
775
|
+
type: 'string',
|
|
776
|
+
enum: ['holographic', 'symmetry', 'chord', 'storm', 'legacy'],
|
|
777
|
+
description: 'Named profile to load'
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
required: ['profile']
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
|
|
784
|
+
set_layer_relationship: {
|
|
785
|
+
name: 'set_layer_relationship',
|
|
786
|
+
description: 'Sets the relationship type for a specific layer relative to the keystone. Available relationships: echo (attenuated follower), mirror (inverted rotation/hue), complement (color opposite), harmonic (musical intervals), reactive (amplifies changes), chase (delayed follower).',
|
|
787
|
+
inputSchema: {
|
|
788
|
+
type: 'object',
|
|
789
|
+
properties: {
|
|
790
|
+
layer: {
|
|
791
|
+
type: 'string',
|
|
792
|
+
enum: ['background', 'shadow', 'content', 'highlight', 'accent'],
|
|
793
|
+
description: 'Target layer name'
|
|
794
|
+
},
|
|
795
|
+
relationship: {
|
|
796
|
+
type: 'string',
|
|
797
|
+
enum: ['echo', 'mirror', 'complement', 'harmonic', 'reactive', 'chase'],
|
|
798
|
+
description: 'Relationship preset name'
|
|
799
|
+
},
|
|
800
|
+
config: {
|
|
801
|
+
type: 'object',
|
|
802
|
+
description: 'Optional config overrides for the relationship (e.g., { opacity: 0.5, gain: 3 })'
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
required: ['layer', 'relationship']
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
|
|
809
|
+
set_layer_keystone: {
|
|
810
|
+
name: 'set_layer_keystone',
|
|
811
|
+
description: 'Changes which layer acts as the keystone (driver) for the layer relationship graph. Other layers derive their parameters from the keystone through relationship functions.',
|
|
812
|
+
inputSchema: {
|
|
813
|
+
type: 'object',
|
|
814
|
+
properties: {
|
|
815
|
+
layer: {
|
|
816
|
+
type: 'string',
|
|
817
|
+
enum: ['background', 'shadow', 'content', 'highlight', 'accent'],
|
|
818
|
+
description: 'Layer to designate as keystone'
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
required: ['layer']
|
|
822
|
+
}
|
|
823
|
+
},
|
|
824
|
+
|
|
825
|
+
get_layer_config: {
|
|
826
|
+
name: 'get_layer_config',
|
|
827
|
+
description: 'Returns the current layer relationship configuration including keystone, profile, and per-layer relationships with their config parameters.',
|
|
828
|
+
inputSchema: {
|
|
829
|
+
type: 'object',
|
|
830
|
+
properties: {}
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
|
|
834
|
+
tune_layer_relationship: {
|
|
835
|
+
name: 'tune_layer_relationship',
|
|
836
|
+
description: 'Hot-patches a layer relationship config without replacing the full graph. Merges provided config values into the existing relationship (e.g., increase reactive gain, shift harmonic hue angle).',
|
|
837
|
+
inputSchema: {
|
|
838
|
+
type: 'object',
|
|
839
|
+
properties: {
|
|
840
|
+
layer: {
|
|
841
|
+
type: 'string',
|
|
842
|
+
enum: ['background', 'shadow', 'content', 'highlight', 'accent'],
|
|
843
|
+
description: 'Layer to tune'
|
|
844
|
+
},
|
|
845
|
+
config: {
|
|
846
|
+
type: 'object',
|
|
847
|
+
description: 'Config values to merge (e.g., { opacity: 0.6, gain: 3.0, hueAngle: 120 })'
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
required: ['layer', 'config']
|
|
851
|
+
}
|
|
765
852
|
}
|
|
766
853
|
};
|
|
767
854
|
|