@vib3code/sdk 2.0.3-canary.91a95f3 → 2.0.3-canary.98b84da

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +2 -0
  2. package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
  3. package/DOCS/ARCHITECTURE.md +1 -0
  4. package/DOCS/CI_TESTING.md +2 -0
  5. package/DOCS/CLI_ONBOARDING.md +2 -0
  6. package/DOCS/CONTROL_REFERENCE.md +2 -0
  7. package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +2 -0
  8. package/DOCS/ENV_SETUP.md +2 -0
  9. package/DOCS/EPIC_SCROLL_EVENTS.md +2 -0
  10. package/DOCS/EXPANSION_DESIGN.md +979 -0
  11. package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
  12. package/DOCS/EXPORT_FORMATS.md +2 -0
  13. package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
  14. package/DOCS/HANDOFF_LANDING_PAGE.md +2 -0
  15. package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +2 -0
  16. package/DOCS/LICENSING_TIERS.md +2 -0
  17. package/DOCS/MASTER_PLAN_2026-01-31.md +4 -2
  18. package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +3 -1
  19. package/DOCS/OBS_SETUP_GUIDE.md +2 -0
  20. package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
  21. package/DOCS/PRODUCT_STRATEGY.md +2 -0
  22. package/DOCS/PROJECT_SETUP.md +2 -0
  23. package/DOCS/README.md +5 -3
  24. package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +2 -0
  25. package/DOCS/RENDERER_LIFECYCLE.md +2 -0
  26. package/DOCS/REPO_MANIFEST.md +2 -0
  27. package/DOCS/ROADMAP.md +2 -0
  28. package/DOCS/SCROLL_TIMELINE_v3.md +2 -0
  29. package/DOCS/SITE_REFACTOR_PLAN.md +2 -0
  30. package/DOCS/STATUS.md +2 -0
  31. package/DOCS/SYSTEM_INVENTORY.md +4 -2
  32. package/DOCS/TELEMETRY_EXPORTS.md +2 -0
  33. package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +2 -0
  34. package/DOCS/VISUAL_ANALYSIS_FACETAD.md +2 -0
  35. package/DOCS/VISUAL_ANALYSIS_SIMONE.md +2 -0
  36. package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +2 -0
  37. package/DOCS/WEBGPU_STATUS.md +121 -38
  38. package/DOCS/XR_BENCHMARKS.md +2 -0
  39. package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -34
  40. package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -80
  41. package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -42
  42. package/DOCS/archive/SESSION_014_PLAN.md +1 -195
  43. package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -56
  44. package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -72
  45. package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -741
  46. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -0
  47. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-01-31.md +2 -0
  48. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +2 -0
  49. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +15 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +144 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +110 -0
  52. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
  53. package/DOCS/dev-tracks/README.md +2 -0
  54. package/docs/webgpu-live.html +1 -1
  55. package/package.json +11 -4
  56. package/src/agent/index.js +1 -3
  57. package/src/agent/mcp/MCPServer.js +542 -188
  58. package/src/agent/mcp/index.js +1 -1
  59. package/src/agent/mcp/tools.js +132 -32
  60. package/src/cli/index.js +431 -47
  61. package/src/core/VIB3Engine.js +55 -3
  62. package/src/core/index.js +18 -0
  63. package/src/core/renderers/FacetedRendererAdapter.js +10 -9
  64. package/src/core/renderers/HolographicRendererAdapter.js +11 -7
  65. package/src/core/renderers/QuantumRendererAdapter.js +11 -7
  66. package/src/creative/index.js +11 -0
  67. package/src/experimental/GameLoop.js +72 -0
  68. package/src/experimental/LatticePhysics.js +100 -0
  69. package/src/experimental/LiveDirector.js +143 -0
  70. package/src/experimental/PlayerController4D.js +154 -0
  71. package/src/experimental/VIB3Actor.js +138 -0
  72. package/src/experimental/VIB3Compositor.js +117 -0
  73. package/src/experimental/VIB3Link.js +122 -0
  74. package/src/experimental/VIB3Orchestrator.js +146 -0
  75. package/src/experimental/VIB3Universe.js +109 -0
  76. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  77. package/src/export/SVGExporter.js +9 -5
  78. package/src/export/index.js +11 -1
  79. package/src/faceted/FacetedSystem.js +27 -10
  80. package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
  81. package/src/geometry/generators/Crystal.js +2 -2
  82. package/src/geometry/warp/HypersphereCore.js +53 -24
  83. package/src/holograms/HolographicVisualizer.js +58 -89
  84. package/src/holograms/RealHolographicSystem.js +126 -31
  85. package/src/math/Mat4x4.js +372 -140
  86. package/src/math/Projection.js +39 -4
  87. package/src/math/Rotor4D.js +157 -67
  88. package/src/math/Vec4.js +265 -111
  89. package/src/math/index.js +7 -7
  90. package/src/quantum/QuantumVisualizer.js +24 -20
  91. package/src/reactivity/index.js +3 -5
  92. package/src/render/LayerPresetManager.js +372 -0
  93. package/src/render/LayerReactivityBridge.js +344 -0
  94. package/src/render/LayerRelationshipGraph.js +610 -0
  95. package/src/render/MultiCanvasBridge.js +148 -25
  96. package/src/render/ShaderLoader.js +38 -0
  97. package/src/render/ShaderProgram.js +4 -4
  98. package/src/render/UnifiedRenderBridge.js +1 -1
  99. package/src/render/backends/WebGPUBackend.js +8 -4
  100. package/src/render/index.js +27 -2
  101. package/src/scene/Node4D.js +74 -24
  102. package/src/scene/index.js +4 -4
  103. package/src/shaders/common/geometry24.glsl +65 -0
  104. package/src/shaders/common/geometry24.wgsl +54 -0
  105. package/src/shaders/common/rotation4d.glsl +4 -4
  106. package/src/shaders/common/rotation4d.wgsl +2 -2
  107. package/src/shaders/common/uniforms.wgsl +15 -8
  108. package/src/shaders/faceted/faceted.frag.wgsl +19 -6
  109. package/src/shaders/holographic/holographic.frag.wgsl +7 -5
  110. package/src/shaders/quantum/quantum.frag.wgsl +7 -5
  111. package/src/testing/ParallelTestFramework.js +2 -2
  112. package/src/testing/ProjectionClass.test.js +38 -0
  113. package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
  114. package/src/viewer/GalleryUI.js +17 -0
  115. package/src/viewer/ViewerPortal.js +2 -2
  116. package/tools/shader-sync-verify.js +6 -4
  117. package/tools/update_projection.py +109 -0
  118. package/types/adaptive-sdk.d.ts +204 -5
  119. package/types/agent/cli.d.ts +78 -0
  120. package/types/agent/index.d.ts +18 -0
  121. package/types/agent/mcp.d.ts +87 -0
  122. package/types/agent/telemetry.d.ts +190 -0
  123. package/types/core/VIB3Engine.d.ts +26 -0
  124. package/types/core/index.d.ts +261 -0
  125. package/types/creative/AestheticMapper.d.ts +72 -0
  126. package/types/creative/ChoreographyPlayer.d.ts +96 -0
  127. package/types/creative/index.d.ts +17 -0
  128. package/types/export/index.d.ts +243 -0
  129. package/types/geometry/index.d.ts +164 -0
  130. package/types/math/index.d.ts +214 -0
  131. package/types/render/LayerPresetManager.d.ts +78 -0
  132. package/types/render/LayerReactivityBridge.d.ts +85 -0
  133. package/types/render/LayerRelationshipGraph.d.ts +174 -0
  134. package/types/render/index.d.ts +3 -0
  135. package/types/scene/index.d.ts +204 -0
  136. package/types/systems/index.d.ts +244 -0
  137. package/types/variations/index.d.ts +62 -0
  138. package/types/viewer/index.d.ts +225 -0
package/src/cli/index.js CHANGED
@@ -5,9 +5,34 @@
5
5
  */
6
6
 
7
7
  import { performance } from 'node:perf_hooks';
8
+ import path from 'node:path';
8
9
  import { mcpServer, toolDefinitions } from '../agent/index.js';
9
10
  import { schemaRegistry } from '../schemas/index.js';
10
11
 
12
+ /**
13
+ * Resolves a file path and ensures it is within the current working directory.
14
+ * @param {string} filePath The path to validate
15
+ * @returns {string} The resolved absolute path
16
+ * @throws {Error} If the path is outside the allowed directory
17
+ */
18
+ function getSafePath(filePath) {
19
+ if (!filePath) return filePath;
20
+
21
+ const cwd = process.cwd();
22
+ const resolvedPath = path.resolve(cwd, filePath);
23
+ const relative = path.relative(cwd, resolvedPath);
24
+
25
+ const isOutside = relative.startsWith('..') || path.isAbsolute(relative);
26
+
27
+ if (isOutside) {
28
+ const error = new Error('Security Error: Path traversal detected. Access denied.');
29
+ error.code = 'EACCES';
30
+ throw error;
31
+ }
32
+
33
+ return resolvedPath;
34
+ }
35
+
11
36
  /**
12
37
  * CLI Configuration
13
38
  */
@@ -172,7 +197,8 @@ function showHelp(isJson) {
172
197
  description: 'VIB3+ 4D Visualization Engine CLI',
173
198
  usage: `${CLI_NAME} <command> [options]`,
174
199
  commands: {
175
- create: 'Create a new 4D visualization',
200
+ init: 'Scaffold a new VIB3+ project (--template vanilla|react|vue|svelte)',
201
+ create: 'Create a new 4D visualization (--describe, --preset, --color, --hue, --XW, etc.)',
176
202
  state: 'Get current engine state',
177
203
  set: 'Set parameters (rotation, visual)',
178
204
  geometry: 'Change or list geometries',
@@ -190,7 +216,14 @@ function showHelp(isJson) {
190
216
  '--verbose': 'Verbose output'
191
217
  },
192
218
  examples: [
219
+ `${CLI_NAME} init my-app`,
220
+ `${CLI_NAME} init my-app --template react`,
221
+ `${CLI_NAME} init my-app --template vue`,
222
+ `${CLI_NAME} init my-app --template svelte`,
193
223
  `${CLI_NAME} create --system quantum --geometry 8 --json`,
224
+ `${CLI_NAME} create --describe "serene ocean deep organic"`,
225
+ `${CLI_NAME} create --system holographic --preset energetic --color neon`,
226
+ `${CLI_NAME} create --system faceted --geometry 16 --XW 0.8 --YW 0.5 --hue 200`,
194
227
  `${CLI_NAME} set rotation --XW 1.5 --YW 0.5`,
195
228
  `${CLI_NAME} set visual --hue 200 --chaos 0.3`,
196
229
  `${CLI_NAME} geometry list --core-type hypersphere`,
@@ -224,15 +257,84 @@ function showVersion(isJson) {
224
257
 
225
258
  /**
226
259
  * Handle 'create' command
260
+ *
261
+ * Supports full creative parameter control:
262
+ * vib3 create --system quantum --geometry 11 --hue 200 --chaos 0.3
263
+ * vib3 create --system holographic --preset energetic
264
+ * vib3 create --describe "serene ocean deep organic"
265
+ * vib3 create --system faceted --geometry 16 --XW 0.8 --YW 0.5 --speed 0.6
227
266
  */
228
267
  async function handleCreate(parsed) {
229
- const args = {
230
- system: parsed.options.system || 'quantum',
231
- geometry_index: parseInt(parsed.options.geometry || '0'),
232
- projection: parsed.options.projection || 'perspective'
268
+ const opts = parsed.options;
269
+
270
+ // Natural language description path — uses AestheticMapper
271
+ if (opts.describe || opts.description) {
272
+ const description = opts.describe || opts.description;
273
+ return await mcpServer.handleToolCall('design_from_description', {
274
+ description,
275
+ apply: true
276
+ });
277
+ }
278
+
279
+ // Step 1: Create the visualization scene
280
+ const createArgs = {
281
+ system: opts.system || 'quantum',
282
+ geometry_index: parseInt(opts.geometry || '0'),
283
+ projection: opts.projection || 'perspective'
233
284
  };
285
+ const createResult = await mcpServer.handleToolCall('create_4d_visualization', createArgs);
286
+
287
+ // Step 2: Apply rotation if any 6D rotation flags provided
288
+ const rotationPlanes = ['XY', 'XZ', 'YZ', 'XW', 'YW', 'ZW'];
289
+ const rotationArgs = {};
290
+ let hasRotation = false;
291
+ for (const plane of rotationPlanes) {
292
+ if (opts[plane] !== undefined) {
293
+ rotationArgs[plane] = parseFloat(opts[plane]);
294
+ hasRotation = true;
295
+ }
296
+ }
297
+ if (hasRotation) {
298
+ await mcpServer.handleToolCall('set_rotation', rotationArgs);
299
+ }
234
300
 
235
- return await mcpServer.handleToolCall('create_4d_visualization', args);
301
+ // Step 3: Apply visual parameters if any provided
302
+ const visualKeys = ['hue', 'saturation', 'intensity', 'speed', 'chaos', 'morphFactor', 'gridDensity', 'dimension'];
303
+ const visualArgs = {};
304
+ let hasVisual = false;
305
+ for (const key of visualKeys) {
306
+ if (opts[key] !== undefined) {
307
+ visualArgs[key] = key === 'hue' ? parseInt(opts[key]) : parseFloat(opts[key]);
308
+ hasVisual = true;
309
+ }
310
+ }
311
+ if (hasVisual) {
312
+ await mcpServer.handleToolCall('set_visual_parameters', visualArgs);
313
+ }
314
+
315
+ // Step 4: Apply behavior preset if specified (ambient, reactive, immersive, energetic, calm, cinematic)
316
+ if (opts.preset) {
317
+ const presetDefaults = {
318
+ ambient: { speed: 0.3, chaos: 0.1 },
319
+ reactive: { speed: 1.0, chaos: 0.3 },
320
+ immersive: { speed: 0.8, chaos: 0.15 },
321
+ energetic: { speed: 2.5, chaos: 0.8 },
322
+ calm: { speed: 0.2, chaos: 0.05 },
323
+ cinematic: { speed: 0.5, chaos: 0.2 }
324
+ };
325
+ const presetParams = presetDefaults[opts.preset];
326
+ if (presetParams) {
327
+ await mcpServer.handleToolCall('set_visual_parameters', presetParams);
328
+ }
329
+ }
330
+
331
+ // Step 5: Apply color preset if specified (ocean, neon, galaxy, etc.)
332
+ if (opts.color || opts.colorPreset) {
333
+ const colorName = opts.color || opts.colorPreset;
334
+ await mcpServer.handleToolCall('apply_color_preset', { preset: colorName });
335
+ }
336
+
337
+ return createResult;
236
338
  }
237
339
 
238
340
  /**
@@ -369,7 +471,7 @@ async function handleTools(parsed, startTime) {
369
471
  */
370
472
  async function handleValidate(parsed, startTime) {
371
473
  const subcommand = parsed.subcommand || 'pack';
372
- const filePath = parsed.options.file || parsed.options.f || parsed.positional[0];
474
+ let filePath = parsed.options.file || parsed.options.f || parsed.positional[0];
373
475
 
374
476
  if (!filePath && subcommand !== 'schema') {
375
477
  return wrapResponse('validate', {
@@ -383,6 +485,10 @@ async function handleValidate(parsed, startTime) {
383
485
  }
384
486
 
385
487
  try {
488
+ if (filePath) {
489
+ filePath = getSafePath(filePath);
490
+ }
491
+
386
492
  switch (subcommand) {
387
493
  case 'pack': {
388
494
  // Validate a .vib3 scene pack file
@@ -456,6 +562,17 @@ async function handleValidate(parsed, startTime) {
456
562
  }, false, performance.now() - startTime);
457
563
  }
458
564
  } catch (error) {
565
+ if (error.code === 'EACCES') {
566
+ return wrapResponse('validate', {
567
+ error: {
568
+ type: 'SecurityError',
569
+ code: 'ACCESS_DENIED',
570
+ message: error.message,
571
+ suggestion: 'Ensure the file path is within the project directory'
572
+ }
573
+ }, false, performance.now() - startTime);
574
+ }
575
+
459
576
  if (error.code === 'ENOENT') {
460
577
  return wrapResponse('validate', {
461
578
  error: {
@@ -578,13 +695,43 @@ async function main() {
578
695
 
579
696
  /**
580
697
  * Handle init command — scaffold a new VIB3+ project
698
+ * Supports --template vanilla|react|vue|svelte
581
699
  */
582
700
  async function handleInit(parsed, startTime) {
583
701
  const { writeFileSync, mkdirSync, existsSync } = await import('node:fs');
584
- const { join } = await import('node:path');
585
702
 
586
- const projectName = parsed.positional[0] || 'my-vib3-app';
587
- const projectDir = join(process.cwd(), projectName);
703
+ const projectName = parsed.subcommand || parsed.positional[0] || 'my-vib3-app';
704
+ const template = parsed.options.template || parsed.options.t || 'vanilla';
705
+ const validTemplates = ['vanilla', 'react', 'vue', 'svelte'];
706
+
707
+ if (!validTemplates.includes(template)) {
708
+ return wrapResponse('init', {
709
+ error: {
710
+ type: 'ValidationError',
711
+ code: 'INVALID_TEMPLATE',
712
+ message: `Unknown template: ${template}`,
713
+ valid_options: validTemplates,
714
+ suggestion: `Use --template ${validTemplates.join('|')}`
715
+ }
716
+ }, false, performance.now() - startTime);
717
+ }
718
+
719
+ let projectDir;
720
+ try {
721
+ projectDir = getSafePath(projectName);
722
+ } catch (error) {
723
+ if (error.code === 'EACCES') {
724
+ return wrapResponse('init', {
725
+ error: {
726
+ type: 'SecurityError',
727
+ code: 'ACCESS_DENIED',
728
+ message: error.message,
729
+ suggestion: 'Choose a project name that results in a valid subdirectory'
730
+ }
731
+ }, false, performance.now() - startTime);
732
+ }
733
+ throw error;
734
+ }
588
735
 
589
736
  if (existsSync(projectDir)) {
590
737
  return wrapResponse('init', {
@@ -599,25 +746,277 @@ async function handleInit(parsed, startTime) {
599
746
 
600
747
  mkdirSync(projectDir, { recursive: true });
601
748
 
602
- // package.json
603
- writeFileSync(join(projectDir, 'package.json'), JSON.stringify({
604
- name: projectName,
605
- version: '0.1.0',
606
- type: 'module',
607
- scripts: {
608
- dev: 'npx vite --open',
609
- build: 'npx vite build'
610
- },
611
- dependencies: {
612
- '@vib3code/sdk': '^2.0.0'
613
- },
614
- devDependencies: {
615
- vite: '^5.3.0'
749
+ const files = getTemplateFiles(template, projectName);
750
+
751
+ for (const [filename, content] of Object.entries(files)) {
752
+ const filepath = path.join(projectDir, filename);
753
+ const dir = path.join(projectDir, filename.split('/').slice(0, -1).join('/'));
754
+ if (dir !== projectDir) {
755
+ mkdirSync(dir, { recursive: true });
616
756
  }
617
- }, null, 2) + '\n');
757
+ writeFileSync(filepath, content);
758
+ }
618
759
 
619
- // index.html
620
- writeFileSync(join(projectDir, 'index.html'), `<!DOCTYPE html>
760
+ const fileNames = Object.keys(files);
761
+ const tree = fileNames.map((f, i) =>
762
+ ` ${i === fileNames.length - 1 ? '└── ' : '├── '}${f}`
763
+ ).join('\n');
764
+
765
+ console.log(`\n Created ${projectName}/ (${template} template)`);
766
+ console.log(tree);
767
+ console.log(`\n Next steps:`);
768
+ console.log(` cd ${projectName}`);
769
+ console.log(' npm install');
770
+ console.log(' npm run dev\n');
771
+
772
+ return wrapResponse('init', {
773
+ project: projectName,
774
+ template,
775
+ files: fileNames,
776
+ next_steps: [`cd ${projectName}`, 'npm install', 'npm run dev']
777
+ }, true, performance.now() - startTime);
778
+ }
779
+
780
+ /**
781
+ * Generate template files based on framework choice
782
+ */
783
+ function getTemplateFiles(template, projectName) {
784
+ const sdkDep = { '@vib3code/sdk': '^2.0.0' };
785
+ const viteDep = { vite: '^5.3.0' };
786
+
787
+ switch (template) {
788
+ case 'react':
789
+ return {
790
+ 'package.json': JSON.stringify({
791
+ name: projectName,
792
+ version: '0.1.0',
793
+ type: 'module',
794
+ scripts: { dev: 'npx vite --open', build: 'npx vite build' },
795
+ dependencies: { ...sdkDep, react: '^18.3.0', 'react-dom': '^18.3.0' },
796
+ devDependencies: { ...viteDep, '@vitejs/plugin-react': '^4.3.0' }
797
+ }, null, 2) + '\n',
798
+ 'vite.config.js': `import { defineConfig } from 'vite';
799
+ import react from '@vitejs/plugin-react';
800
+ export default defineConfig({ plugins: [react()] });
801
+ `,
802
+ 'index.html': `<!DOCTYPE html>
803
+ <html lang="en">
804
+ <head>
805
+ <meta charset="utf-8">
806
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
807
+ <title>${projectName}</title>
808
+ </head>
809
+ <body>
810
+ <div id="root"></div>
811
+ <script type="module" src="/src/main.jsx"></script>
812
+ </body>
813
+ </html>
814
+ `,
815
+ 'src/main.jsx': `import React from 'react';
816
+ import ReactDOM from 'react-dom/client';
817
+ import App from './App.jsx';
818
+
819
+ ReactDOM.createRoot(document.getElementById('root')).render(<App />);
820
+ `,
821
+ 'src/App.jsx': `import React, { useRef, useEffect, useState } from 'react';
822
+ import { VIB3Engine } from '@vib3code/sdk/core';
823
+
824
+ export default function App() {
825
+ const engineRef = useRef(null);
826
+ const [system, setSystem] = useState('quantum');
827
+ const [geometry, setGeometry] = useState(0);
828
+ const [hue, setHue] = useState(200);
829
+
830
+ useEffect(() => {
831
+ const engine = new VIB3Engine();
832
+ engineRef.current = engine;
833
+ engine.initialize().then(() => engine.switchSystem(system));
834
+ return () => engine.destroy();
835
+ }, []);
836
+
837
+ useEffect(() => {
838
+ engineRef.current?.switchSystem(system);
839
+ }, [system]);
840
+
841
+ useEffect(() => {
842
+ engineRef.current?.setParameter('geometry', geometry);
843
+ }, [geometry]);
844
+
845
+ useEffect(() => {
846
+ engineRef.current?.setParameter('hue', hue);
847
+ }, [hue]);
848
+
849
+ return (
850
+ <div style={{ margin: 0, background: '#07070f', minHeight: '100vh' }}>
851
+ <div style={{ position: 'fixed', top: 12, left: 12, zIndex: 10, font: '13px monospace', color: '#0fc', display: 'flex', gap: 12 }}>
852
+ <label>System:
853
+ <select value={system} onChange={e => setSystem(e.target.value)} style={{ marginLeft: 6 }}>
854
+ <option>quantum</option>
855
+ <option>faceted</option>
856
+ <option>holographic</option>
857
+ </select>
858
+ </label>
859
+ <label>Geometry: <input type="range" min="0" max="23" value={geometry} onChange={e => setGeometry(+e.target.value)} /></label>
860
+ <label>Hue: <input type="range" min="0" max="360" value={hue} onChange={e => setHue(+e.target.value)} /></label>
861
+ </div>
862
+ </div>
863
+ );
864
+ }
865
+ `
866
+ };
867
+
868
+ case 'vue':
869
+ return {
870
+ 'package.json': JSON.stringify({
871
+ name: projectName,
872
+ version: '0.1.0',
873
+ type: 'module',
874
+ scripts: { dev: 'npx vite --open', build: 'npx vite build' },
875
+ dependencies: { ...sdkDep, vue: '^3.4.0' },
876
+ devDependencies: { ...viteDep, '@vitejs/plugin-vue': '^5.1.0' }
877
+ }, null, 2) + '\n',
878
+ 'vite.config.js': `import { defineConfig } from 'vite';
879
+ import vue from '@vitejs/plugin-vue';
880
+ export default defineConfig({ plugins: [vue()] });
881
+ `,
882
+ 'index.html': `<!DOCTYPE html>
883
+ <html lang="en">
884
+ <head>
885
+ <meta charset="utf-8">
886
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
887
+ <title>${projectName}</title>
888
+ </head>
889
+ <body>
890
+ <div id="app"></div>
891
+ <script type="module" src="/src/main.js"></script>
892
+ </body>
893
+ </html>
894
+ `,
895
+ 'src/main.js': `import { createApp } from 'vue';
896
+ import App from './App.vue';
897
+ createApp(App).mount('#app');
898
+ `,
899
+ 'src/App.vue': `<script setup>
900
+ import { ref, onMounted, onUnmounted, watch } from 'vue';
901
+ import { VIB3Engine } from '@vib3code/sdk/core';
902
+
903
+ const engine = ref(null);
904
+ const system = ref('quantum');
905
+ const geometry = ref(0);
906
+ const hue = ref(200);
907
+
908
+ onMounted(async () => {
909
+ engine.value = new VIB3Engine();
910
+ await engine.value.initialize();
911
+ await engine.value.switchSystem(system.value);
912
+ });
913
+
914
+ onUnmounted(() => engine.value?.destroy());
915
+
916
+ watch(system, (val) => engine.value?.switchSystem(val));
917
+ watch(geometry, (val) => engine.value?.setParameter('geometry', val));
918
+ watch(hue, (val) => engine.value?.setParameter('hue', val));
919
+ </script>
920
+
921
+ <template>
922
+ <div style="margin: 0; background: #07070f; min-height: 100vh">
923
+ <div style="position: fixed; top: 12px; left: 12px; z-index: 10; font: 13px monospace; color: #0fc; display: flex; gap: 12px">
924
+ <label>System:
925
+ <select v-model="system" style="margin-left: 6px">
926
+ <option>quantum</option>
927
+ <option>faceted</option>
928
+ <option>holographic</option>
929
+ </select>
930
+ </label>
931
+ <label>Geometry: <input type="range" min="0" max="23" v-model.number="geometry" /></label>
932
+ <label>Hue: <input type="range" min="0" max="360" v-model.number="hue" /></label>
933
+ </div>
934
+ </div>
935
+ </template>
936
+ `
937
+ };
938
+
939
+ case 'svelte':
940
+ return {
941
+ 'package.json': JSON.stringify({
942
+ name: projectName,
943
+ version: '0.1.0',
944
+ type: 'module',
945
+ scripts: { dev: 'npx vite --open', build: 'npx vite build' },
946
+ dependencies: sdkDep,
947
+ devDependencies: { ...viteDep, '@sveltejs/vite-plugin-svelte': '^3.2.0', svelte: '^4.2.0' }
948
+ }, null, 2) + '\n',
949
+ 'vite.config.js': `import { defineConfig } from 'vite';
950
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
951
+ export default defineConfig({ plugins: [svelte()] });
952
+ `,
953
+ 'index.html': `<!DOCTYPE html>
954
+ <html lang="en">
955
+ <head>
956
+ <meta charset="utf-8">
957
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
958
+ <title>${projectName}</title>
959
+ </head>
960
+ <body>
961
+ <div id="app"></div>
962
+ <script type="module" src="/src/main.js"></script>
963
+ </body>
964
+ </html>
965
+ `,
966
+ 'src/main.js': `import App from './App.svelte';
967
+ const app = new App({ target: document.getElementById('app') });
968
+ export default app;
969
+ `,
970
+ 'src/App.svelte': `<script>
971
+ import { onMount, onDestroy } from 'svelte';
972
+ import { VIB3Engine } from '@vib3code/sdk/core';
973
+
974
+ let engine = null;
975
+ let system = 'quantum';
976
+ let geometry = 0;
977
+ let hue = 200;
978
+
979
+ onMount(async () => {
980
+ engine = new VIB3Engine();
981
+ await engine.initialize();
982
+ await engine.switchSystem(system);
983
+ });
984
+
985
+ onDestroy(() => engine?.destroy());
986
+
987
+ $: engine?.switchSystem(system);
988
+ $: engine?.setParameter('geometry', geometry);
989
+ $: engine?.setParameter('hue', hue);
990
+ </script>
991
+
992
+ <div style="margin: 0; background: #07070f; min-height: 100vh">
993
+ <div style="position: fixed; top: 12px; left: 12px; z-index: 10; font: 13px monospace; color: #0fc; display: flex; gap: 12px">
994
+ <label>System:
995
+ <select bind:value={system} style="margin-left: 6px">
996
+ <option>quantum</option>
997
+ <option>faceted</option>
998
+ <option>holographic</option>
999
+ </select>
1000
+ </label>
1001
+ <label>Geometry: <input type="range" min="0" max="23" bind:value={geometry} /></label>
1002
+ <label>Hue: <input type="range" min="0" max="360" bind:value={hue} /></label>
1003
+ </div>
1004
+ </div>
1005
+ `
1006
+ };
1007
+
1008
+ case 'vanilla':
1009
+ default:
1010
+ return {
1011
+ 'package.json': JSON.stringify({
1012
+ name: projectName,
1013
+ version: '0.1.0',
1014
+ type: 'module',
1015
+ scripts: { dev: 'npx vite --open', build: 'npx vite build' },
1016
+ dependencies: sdkDep,
1017
+ devDependencies: viteDep
1018
+ }, null, 2) + '\n',
1019
+ 'index.html': `<!DOCTYPE html>
621
1020
  <html lang="en">
622
1021
  <head>
623
1022
  <meta charset="utf-8">
@@ -638,10 +1037,8 @@ async function handleInit(parsed, startTime) {
638
1037
  <script type="module" src="main.js"></script>
639
1038
  </body>
640
1039
  </html>
641
- `);
642
-
643
- // main.js
644
- writeFileSync(join(projectDir, 'main.js'), `import { VIB3Engine } from '@vib3code/sdk/core';
1040
+ `,
1041
+ 'main.js': `import { VIB3Engine } from '@vib3code/sdk/core';
645
1042
 
646
1043
  const engine = new VIB3Engine();
647
1044
  await engine.initialize();
@@ -650,22 +1047,9 @@ await engine.switchSystem('quantum');
650
1047
  document.getElementById('sys').addEventListener('change', (e) => engine.switchSystem(e.target.value));
651
1048
  document.getElementById('geo').addEventListener('input', (e) => engine.setParameter('geometry', +e.target.value));
652
1049
  document.getElementById('hue').addEventListener('input', (e) => engine.setParameter('hue', +e.target.value));
653
- `);
654
-
655
- console.log(`\\n Created ${projectName}/`);
656
- console.log(' ├── package.json');
657
- console.log(' ├── index.html');
658
- console.log(' └── main.js');
659
- console.log(`\\n Next steps:`);
660
- console.log(` cd ${projectName}`);
661
- console.log(' npm install');
662
- console.log(' npm run dev\\n');
663
-
664
- return wrapResponse('init', {
665
- project: projectName,
666
- files: ['package.json', 'index.html', 'main.js'],
667
- next_steps: [`cd ${projectName}`, 'npm install', 'npm run dev']
668
- }, true, performance.now() - startTime);
1050
+ `
1051
+ };
1052
+ }
669
1053
  }
670
1054
 
671
1055
  // Run CLI
@@ -26,7 +26,7 @@ export class VIB3Engine {
26
26
  */
27
27
  constructor(options = {}) {
28
28
  this.activeSystem = null; // Only one system active at a time
29
- this.currentSystemName = 'quantum';
29
+ this.currentSystemName = options.system || 'quantum';
30
30
  this.parameters = new ParameterManager();
31
31
  this.initialized = false;
32
32
  this.canvasManager = null;
@@ -82,7 +82,11 @@ export class VIB3Engine {
82
82
  }
83
83
 
84
84
  // Initialize starting system
85
- await this.switchSystem(this.currentSystemName);
85
+ const systemOk = await this.switchSystem(this.currentSystemName);
86
+ if (!systemOk) {
87
+ console.error(`VIB3+ Engine: Failed to create initial system "${this.currentSystemName}"`);
88
+ return false;
89
+ }
86
90
 
87
91
  // Sync base parameters to reactivity manager
88
92
  this.reactivity.setBaseParameters(this.parameters.getAllParameters());
@@ -167,7 +171,7 @@ export class VIB3Engine {
167
171
  }
168
172
  }
169
173
 
170
- const facetedSuccess = system.initialize();
174
+ const facetedSuccess = await system.initialize();
171
175
  if (!facetedSuccess) {
172
176
  throw new Error('Faceted system initialization failed');
173
177
  }
@@ -273,6 +277,17 @@ export class VIB3Engine {
273
277
 
274
278
  if (this.activeSystem && this.activeSystem.updateParameters) {
275
279
  this.activeSystem.updateParameters(params);
280
+ } else if (this.debug && this.activeSystem && !this.activeSystem.updateParameters) {
281
+ console.warn('VIB3+ Engine [debug]: activeSystem missing updateParameters() method');
282
+ } else if (this.debug && !this.activeSystem) {
283
+ console.warn('VIB3+ Engine [debug]: updateCurrentSystemParameters() called with no activeSystem');
284
+ }
285
+
286
+ // Notify parameter change listeners
287
+ if (this._parameterListeners && this._parameterListeners.size > 0) {
288
+ for (const listener of this._parameterListeners) {
289
+ try { listener(params); } catch (_) { /* listener error */ }
290
+ }
276
291
  }
277
292
  }
278
293
 
@@ -632,6 +647,43 @@ export class VIB3Engine {
632
647
  }
633
648
  }
634
649
 
650
+ // ========================================================================
651
+ // Convenience Methods (dogfood feedback)
652
+ // ========================================================================
653
+
654
+ /**
655
+ * Create a parameter update callback for use with creative modules.
656
+ * Returns (name, value) => void that calls setParameter internally.
657
+ * Eliminates boilerplate: `(name, value) => engine.setParameter(name, value)`.
658
+ * @returns {(name: string, value: number) => void}
659
+ */
660
+ createParameterCallback() {
661
+ return (name, value) => this.setParameter(name, value);
662
+ }
663
+
664
+ /**
665
+ * Get current breath value from VitalitySystem (0-1).
666
+ * Avoids reaching into engine.vitality.getBreath() directly.
667
+ * @returns {number}
668
+ */
669
+ getBreath() {
670
+ return this.vitality.getBreath();
671
+ }
672
+
673
+ /**
674
+ * Register a listener for parameter changes.
675
+ * Callback receives the full parameter object after each change.
676
+ * @param {(params: object) => void} callback
677
+ * @returns {() => void} Unsubscribe function
678
+ */
679
+ onParameterChange(callback) {
680
+ if (!this._parameterListeners) {
681
+ this._parameterListeners = new Set();
682
+ }
683
+ this._parameterListeners.add(callback);
684
+ return () => this._parameterListeners.delete(callback);
685
+ }
686
+
635
687
  /**
636
688
  * Destroy engine and clean up
637
689
  */
@@ -0,0 +1,18 @@
1
+ /**
2
+ * VIB3+ Core Module
3
+ * @module core
4
+ */
5
+
6
+ export { VIB3Engine } from './VIB3Engine.js';
7
+ export { CanvasManager } from './CanvasManager.js';
8
+ export { ParameterManager } from './Parameters.js';
9
+ export { ParameterMapper } from './ParameterMapper.js';
10
+ export { ErrorReporter } from './ErrorReporter.js';
11
+ export { VitalitySystem } from './VitalitySystem.js';
12
+ export { UnifiedResourceManager } from './UnifiedResourceManager.js';
13
+ export {
14
+ RendererContract,
15
+ RendererContractAdapter,
16
+ verifyRendererContract,
17
+ ResourceManagerContract
18
+ } from './RendererContracts.js';