@viji-dev/sdk 1.0.0 → 1.0.2

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 (77) hide show
  1. package/README.md +70 -63
  2. package/bin/viji.js +9 -29
  3. package/dist/assets/artist-dts-BHUsvSI6.js +613 -0
  4. package/dist/assets/artist-dts-p5-Cyw8vmy_.js +736 -0
  5. package/dist/assets/core-CiQx3w0t.js +12 -0
  6. package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
  7. package/dist/assets/docs-api-PBLtY4Ni.js +12381 -0
  8. package/dist/assets/engine-javascript-CXyY7cc8.js +141 -0
  9. package/dist/assets/essentia-wasm.web-0S-sW98u-CYV1l1zv.js +38 -0
  10. package/dist/assets/essentia.js-core.es-DnrJE0uR-DOSrF5_G.js +32 -0
  11. package/dist/assets/glsl-DMyvO4G4.js +1 -0
  12. package/dist/assets/index-BhFxsauQ.js +215 -0
  13. package/dist/assets/index-BqhVeA7U.css +1 -0
  14. package/dist/assets/index-T4TOjvD0.js +1 -0
  15. package/dist/assets/index-Wz9WqGqz.js +52 -0
  16. package/dist/assets/index-t24aGwla.js +1 -0
  17. package/dist/assets/javascript-wDzz0qaB.js +1 -0
  18. package/dist/assets/shader-uniforms-GdaUkQPK.js +1 -0
  19. package/dist/assets/typescript-BPQ3VLAy.js +1 -0
  20. package/dist/assets/viji.worker-CQSJ0SiO-ljtBlcNZ.js +27018 -0
  21. package/{index.html → dist/index.html} +2 -1
  22. package/package.json +31 -35
  23. package/src/cli/commands/build.js +50 -99
  24. package/src/cli/commands/create.js +49 -46
  25. package/src/cli/commands/dev.js +30 -97
  26. package/src/cli/server/dev-server.js +233 -0
  27. package/src/cli/server/scene-scanner.js +93 -0
  28. package/src/cli/server/vite-scene-plugin.d.ts +2 -0
  29. package/src/cli/server/vite-scene-plugin.js +134 -0
  30. package/src/cli/utils/cli-utils.js +29 -139
  31. package/src/cli/utils/scene-compiler.js +10 -17
  32. package/src/templates/scene-templates.js +85 -0
  33. package/.gitignore +0 -29
  34. package/eslint.config.js +0 -37
  35. package/postcss.config.js +0 -6
  36. package/scenes/audio-visualizer/main.js +0 -287
  37. package/scenes/core-demo/main.js +0 -532
  38. package/scenes/demo-scene/main.js +0 -619
  39. package/scenes/global.d.ts +0 -15
  40. package/scenes/particle-system/main.js +0 -349
  41. package/scenes/tsconfig.json +0 -12
  42. package/scenes/video-mirror/main.ts +0 -436
  43. package/src/App.css +0 -42
  44. package/src/App.tsx +0 -279
  45. package/src/cli/commands/init.js +0 -262
  46. package/src/components/SDKPage.tsx +0 -337
  47. package/src/components/core/CoreContainer.tsx +0 -126
  48. package/src/components/ui/DeviceSelectionList.tsx +0 -137
  49. package/src/components/ui/FPSCounter.tsx +0 -78
  50. package/src/components/ui/FileDropzonePanel.tsx +0 -120
  51. package/src/components/ui/FileListPanel.tsx +0 -285
  52. package/src/components/ui/InputExpansionPanel.tsx +0 -31
  53. package/src/components/ui/MediaPlayerControls.tsx +0 -191
  54. package/src/components/ui/MenuContainer.tsx +0 -71
  55. package/src/components/ui/ParametersMenu.tsx +0 -797
  56. package/src/components/ui/ProjectSwitcherMenu.tsx +0 -192
  57. package/src/components/ui/QuickInputControls.tsx +0 -542
  58. package/src/components/ui/SDKMenuSystem.tsx +0 -96
  59. package/src/components/ui/SettingsMenu.tsx +0 -346
  60. package/src/components/ui/SimpleInputControls.tsx +0 -137
  61. package/src/index.css +0 -68
  62. package/src/main.tsx +0 -10
  63. package/src/scenes-hmr.ts +0 -158
  64. package/src/services/project-filesystem.ts +0 -436
  65. package/src/stores/scene-player/index.ts +0 -3
  66. package/src/stores/scene-player/input-manager.store.ts +0 -1045
  67. package/src/stores/scene-player/scene-session.store.ts +0 -659
  68. package/src/styles/globals.css +0 -111
  69. package/src/templates/minimal-template.js +0 -11
  70. package/src/utils/debounce.js +0 -34
  71. package/src/vite-env.d.ts +0 -1
  72. package/tailwind.config.js +0 -18
  73. package/tsconfig.app.json +0 -27
  74. package/tsconfig.json +0 -27
  75. package/tsconfig.node.json +0 -27
  76. package/vite.config.ts +0 -54
  77. /package/{public → dist}/favicon.png +0 -0
@@ -1,619 +0,0 @@
1
- // Full Feature Demo Scene - Parameter Object API
2
- console.log('🚀 DEMO SCENE LOADED');
3
-
4
- // Define parameters using helper functions (returns parameter objects)
5
- const primaryColor = viji.color('#ff6b6b', {
6
- label: 'Primary Color',
7
- description: 'Main color for the animated shapes',
8
- group: 'colors'
9
- });
10
-
11
- const secondaryColor = viji.color('#4ecdc4', {
12
- label: 'Secondary Color',
13
- description: 'Secondary color for gradient effects',
14
- group: 'colors'
15
- });
16
-
17
- const backgroundColor = viji.color('#2c3e50', {
18
- label: 'Background Color',
19
- description: 'Scene background color',
20
- group: 'colors'
21
- });
22
-
23
- const shapeSize = viji.slider(50, {
24
- min: 10,
25
- max: 150,
26
- step: 5,
27
- label: 'Shape Size',
28
- description: 'Size of the animated shapes',
29
- group: 'shape'
30
- });
31
-
32
- const shapeType = viji.select('circle', {
33
- options: ['circle', 'square', 'triangle', 'hexagon'],
34
- label: 'Shape Type',
35
- description: 'Type of shape to render',
36
- group: 'shape'
37
- });
38
-
39
- const particleCount = viji.slider(8, {
40
- min: 1,
41
- max: 20,
42
- step: 1,
43
- label: 'Particle Count',
44
- description: 'Number of particles to render',
45
- group: 'shape'
46
- });
47
-
48
- const animationSpeed = viji.slider(1.0, {
49
- min: 0.1,
50
- max: 3.0,
51
- step: 0.1,
52
- label: 'Animation Speed',
53
- description: 'Speed of the animation loop',
54
- group: 'animation'
55
- });
56
-
57
- const rotationSpeed = viji.slider(0.5, {
58
- min: -5,
59
- max: 5,
60
- step: 0.1,
61
- label: 'Rotation Speed',
62
- description: 'Rotation speed for shapes',
63
- group: 'animation'
64
- });
65
-
66
- const useGradient = viji.toggle(true, {
67
- label: 'Use Gradient',
68
- description: 'Enable gradient fill for shapes',
69
- group: 'visual'
70
- });
71
-
72
- const opacity = viji.slider(0.8, {
73
- min: 0.1,
74
- max: 1.0,
75
- step: 0.05,
76
- label: 'Opacity',
77
- description: 'Overall opacity of the scene',
78
- group: 'visual'
79
- });
80
-
81
- const enableTrails = viji.toggle(false, {
82
- label: 'Enable Trails',
83
- description: 'Show trails behind moving shapes',
84
- group: 'visual'
85
- });
86
-
87
- const glowIntensity = viji.slider(0.5, {
88
- min: 0.0,
89
- max: 2.0,
90
- step: 0.1,
91
- label: 'Glow Intensity',
92
- description: 'Intensity of shape glow effect',
93
- group: 'visual'
94
- });
95
-
96
- const sceneTitle = viji.text('Viji SDK Demo', {
97
- label: 'Scene Title',
98
- description: 'Title displayed in the scene',
99
- group: 'text'
100
- });
101
-
102
- const showDebugInfo = viji.toggle(true, {
103
- label: 'Show Debug Info',
104
- description: 'Display performance and parameter information',
105
- group: 'text'
106
- });
107
-
108
- // Interaction Parameters
109
- const mouseAttraction = viji.toggle(true, {
110
- label: 'Mouse Attraction',
111
- description: 'Particles are attracted to mouse cursor',
112
- group: 'interaction',
113
- category: 'interaction'
114
- });
115
-
116
- const attractionStrength = viji.slider(0.3, {
117
- min: 0,
118
- max: 1,
119
- step: 0.1,
120
- label: 'Attraction Strength',
121
- description: 'How strongly particles are attracted to mouse',
122
- group: 'interaction',
123
- category: 'interaction'
124
- });
125
-
126
- const keyboardControl = viji.toggle(true, {
127
- label: 'Keyboard Control',
128
- description: 'Use WASD keys to move particles',
129
- group: 'interaction',
130
- category: 'interaction'
131
- });
132
-
133
- const touchScale = viji.slider(1.0, {
134
- min: 0.5,
135
- max: 2.0,
136
- step: 0.1,
137
- label: 'Touch Scale Factor',
138
- description: 'Scale factor for touch interactions',
139
- group: 'interaction',
140
- category: 'interaction'
141
- });
142
-
143
- const showInteractionInfo = viji.toggle(true, {
144
- label: 'Show Interaction Info',
145
- description: 'Display current interaction state',
146
- group: 'interaction',
147
- category: 'interaction'
148
- });
149
-
150
- // Audio Parameters
151
- const audioReactive = viji.toggle(false, {
152
- label: 'Audio Reactive',
153
- description: 'Make particles react to audio input',
154
- group: 'audio',
155
- category: 'audio'
156
- });
157
-
158
- const volumeSensitivity = viji.slider(1.0, {
159
- min: 0.1,
160
- max: 5.0,
161
- step: 0.1,
162
- label: 'Volume Sensitivity',
163
- description: 'How sensitive particles are to volume changes',
164
- group: 'audio',
165
- category: 'audio'
166
- });
167
-
168
- const bassReactivity = viji.slider(1.0, {
169
- min: 0,
170
- max: 3.0,
171
- step: 0.1,
172
- label: 'Bass Reactivity',
173
- description: 'How much particles react to bass frequencies',
174
- group: 'audio',
175
- category: 'audio'
176
- });
177
-
178
- const trebleReactivity = viji.slider(0.5, {
179
- min: 0,
180
- max: 2.0,
181
- step: 0.1,
182
- label: 'Treble Reactivity',
183
- description: 'How much particles react to treble frequencies',
184
- group: 'audio',
185
- category: 'audio'
186
- });
187
-
188
- const showAudioViz = viji.toggle(true, {
189
- label: 'Show Audio Visualization',
190
- description: 'Display real-time audio analysis',
191
- group: 'audio',
192
- category: 'audio'
193
- });
194
-
195
- // Video Parameters
196
- const videoReactive = viji.toggle(false, {
197
- label: 'Video Reactive',
198
- description: 'Make particles react to video input',
199
- group: 'video',
200
- category: 'video'
201
- });
202
-
203
- const motionSensitivity = viji.slider(1.0, {
204
- min: 0.1,
205
- max: 3.0,
206
- step: 0.1,
207
- label: 'Motion Sensitivity',
208
- description: 'How sensitive particles are to video motion',
209
- group: 'video',
210
- category: 'video'
211
- });
212
-
213
- const brightnessReactivity = viji.slider(0.5, {
214
- min: 0,
215
- max: 2.0,
216
- step: 0.1,
217
- label: 'Brightness Reactivity',
218
- description: 'How much particles react to video brightness',
219
- group: 'video',
220
- category: 'video'
221
- });
222
-
223
- const showVideoOverlay = viji.toggle(true, {
224
- label: 'Show Video Overlay',
225
- description: 'Display current video frame on canvas',
226
- group: 'video',
227
- category: 'video'
228
- });
229
-
230
- // Render function using parameter object API
231
- function render(viji) {
232
- const ctx = viji.useContext('2d');
233
-
234
- // Get interaction state
235
- const mouse = viji.mouse;
236
- const keyboard = viji.keyboard;
237
- const touches = viji.touches;
238
-
239
- // Get audio state
240
- const audio = viji.audio;
241
-
242
- // Get video state
243
- const video = viji.video;
244
-
245
- // Clear canvas with trails effect if enabled
246
- if (enableTrails.value) {
247
- const alpha = Math.floor(0.1 * opacity.value * 255).toString(16).padStart(2, '0');
248
- ctx.fillStyle = backgroundColor.value + alpha;
249
- ctx.fillRect(0, 0, viji.width, viji.height);
250
- } else {
251
- ctx.fillStyle = backgroundColor.value;
252
- ctx.fillRect(0, 0, viji.width, viji.height);
253
- }
254
-
255
- // Draw title
256
- ctx.fillStyle = primaryColor.value;
257
- ctx.font = 'bold 24px Arial';
258
- ctx.textAlign = 'center';
259
- ctx.fillText(sceneTitle.value, viji.width / 2, 40);
260
-
261
- // Keyboard offset for particle center
262
- let keyboardOffsetX = 0;
263
- let keyboardOffsetY = 0;
264
-
265
- if (keyboardControl.value && keyboard) {
266
- const keySpeed = 3;
267
- const isPressed = (k) => (keyboard && typeof keyboard.isPressed === 'function' ? keyboard.isPressed(k) : false);
268
- if (isPressed('w') || isPressed('W')) keyboardOffsetY -= keySpeed;
269
- if (isPressed('s') || isPressed('S')) keyboardOffsetY += keySpeed;
270
- if (isPressed('a') || isPressed('A')) keyboardOffsetX -= keySpeed;
271
- if (isPressed('d') || isPressed('D')) keyboardOffsetX += keySpeed;
272
- }
273
-
274
- // Animation calculations
275
- let centerX = viji.width / 2 + keyboardOffsetX;
276
- let centerY = viji.height / 2 + keyboardOffsetY;
277
- const animTime = viji.time * animationSpeed.value;
278
-
279
- // Audio reactive calculations
280
- let audioScale = 1;
281
- let audioColorShift = 0;
282
- if (audioReactive.value && audio && audio.isConnected) {
283
- audioScale = 1 + ((((audio.volume && audio.volume.rms) || 0)) * volumeSensitivity.value);
284
-
285
- const bassEnergy = ((((audio && audio.bands && audio.bands.bass) || 0) + ((audio && audio.bands && audio.bands.subBass) || 0)) / 2);
286
- const trebleEnergy = ((((audio && audio.bands && audio.bands.treble) || 0) + ((audio && audio.bands && audio.bands.presence) || 0)) / 2);
287
- audioColorShift = (bassEnergy * bassReactivity.value) - (trebleEnergy * trebleReactivity.value);
288
- }
289
-
290
- // Video reactive calculations
291
- let videoScale = 1;
292
- if (videoReactive.value && video && video.isConnected) {
293
- const motionEnergy = Math.sin(animTime * 2) * 0.5 + 0.5; // Simulate motion
294
- videoScale = 1 + (motionEnergy * motionSensitivity.value * 0.3);
295
- }
296
-
297
- // Touch interaction - use primary touch for center offset
298
- if (touches && touches.points && touches.points.length > 0) {
299
- const primaryTouch = touches.points[0];
300
- centerX = primaryTouch.x * touchScale.value;
301
- centerY = primaryTouch.y * touchScale.value;
302
- }
303
-
304
- // Draw particles
305
- for (let i = 0; i < particleCount.value; i++) {
306
- const angle = (i / particleCount.value) * Math.PI * 2 + animTime;
307
- const radius = Math.min(viji.width, viji.height) * 0.25;
308
-
309
- let x = centerX + Math.cos(angle) * radius;
310
- let y = centerY + Math.sin(angle) * radius;
311
-
312
- // Mouse attraction
313
- if (mouseAttraction.value && mouse && mouse.isInCanvas) {
314
- const mouseX = mouse.x;
315
- const mouseY = mouse.y;
316
- const distToMouse = Math.sqrt((x - mouseX) ** 2 + (y - mouseY) ** 2);
317
-
318
- if (distToMouse > 0) {
319
- const attraction = attractionStrength.value * (1 / (distToMouse * 0.01 + 1));
320
- x += (mouseX - x) * attraction;
321
- y += (mouseY - y) * attraction;
322
- }
323
- }
324
-
325
- // Apply rotation
326
- const rotation = animTime * rotationSpeed.value;
327
-
328
- ctx.save();
329
- ctx.translate(x, y);
330
- ctx.rotate(rotation);
331
-
332
- // Set opacity
333
- ctx.globalAlpha = opacity.value;
334
-
335
- let scaledSize = shapeSize.value * Math.min(viji.width, viji.height) / 1000;
336
-
337
- // Apply audio scaling
338
- if (audioReactive.value && audio && audio.isConnected) {
339
- scaledSize *= audioScale;
340
- }
341
-
342
- // Apply video scaling
343
- if (videoReactive.value && video && video.isConnected) {
344
- scaledSize *= videoScale;
345
- }
346
-
347
- // Glow effect
348
- if (glowIntensity.value > 0) {
349
- const glowSize = scaledSize * (2 + glowIntensity.value);
350
- const gradient = ctx.createRadialGradient(0, 0, scaledSize / 2, 0, 0, glowSize / 2);
351
- gradient.addColorStop(0, primaryColor.value);
352
- gradient.addColorStop(1, primaryColor.value + '00');
353
-
354
- ctx.fillStyle = gradient;
355
- ctx.beginPath();
356
- ctx.arc(0, 0, glowSize / 2, 0, Math.PI * 2);
357
- ctx.fill();
358
- }
359
-
360
- // Create gradient or solid fill
361
- if (useGradient.value) {
362
- const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, scaledSize / 2);
363
-
364
- // Apply audio color shifting
365
- let color1 = primaryColor.value;
366
- let color2 = secondaryColor.value;
367
-
368
- if (audioReactive.value && audio && audio.isConnected && audioColorShift !== 0) {
369
- // Simple color shifting effect
370
- const audioHueShift = audioColorShift * 60;
371
- color1 = adjustHue(primaryColor.value, audioHueShift);
372
- color2 = adjustHue(secondaryColor.value, audioHueShift);
373
- }
374
-
375
- gradient.addColorStop(0, color1);
376
- gradient.addColorStop(1, color2);
377
- ctx.fillStyle = gradient;
378
- } else {
379
- ctx.fillStyle = primaryColor.value;
380
- }
381
-
382
- // Draw shape based on type
383
- ctx.beginPath();
384
- switch (shapeType.value) {
385
- case 'circle':
386
- ctx.arc(0, 0, scaledSize / 2, 0, Math.PI * 2);
387
- break;
388
-
389
- case 'square':
390
- const half = scaledSize / 2;
391
- ctx.rect(-half, -half, scaledSize, scaledSize);
392
- break;
393
-
394
- case 'triangle':
395
- const size = scaledSize;
396
- ctx.moveTo(0, -size / 2);
397
- ctx.lineTo(-size / 2, size / 2);
398
- ctx.lineTo(size / 2, size / 2);
399
- ctx.closePath();
400
- break;
401
-
402
- case 'hexagon':
403
- const hexRadius = scaledSize / 2;
404
- for (let j = 0; j < 6; j++) {
405
- const hexAngle = (j / 6) * Math.PI * 2;
406
- const hexX = Math.cos(hexAngle) * hexRadius;
407
- const hexY = Math.sin(hexAngle) * hexRadius;
408
- if (j === 0) ctx.moveTo(hexX, hexY);
409
- else ctx.lineTo(hexX, hexY);
410
- }
411
- ctx.closePath();
412
- break;
413
- }
414
- ctx.fill();
415
-
416
- ctx.restore();
417
- }
418
-
419
- // Draw mouse cursor indicator
420
- if (mouseAttraction.value && mouse && mouse.isInCanvas) {
421
- ctx.strokeStyle = primaryColor.value + '80';
422
- ctx.lineWidth = 2;
423
- ctx.setLineDash([5, 5]);
424
- ctx.beginPath();
425
- ctx.arc(mouse.x, mouse.y, 25, 0, Math.PI * 2);
426
- ctx.stroke();
427
- ctx.setLineDash([]);
428
-
429
- // Draw crosshair
430
- ctx.strokeStyle = primaryColor.value + 'CC';
431
- ctx.lineWidth = 1;
432
- ctx.beginPath();
433
- ctx.moveTo(mouse.x - 10, mouse.y);
434
- ctx.lineTo(mouse.x + 10, mouse.y);
435
- ctx.moveTo(mouse.x, mouse.y - 10);
436
- ctx.lineTo(mouse.x, mouse.y + 10);
437
- ctx.stroke();
438
- }
439
-
440
- // Draw debug info
441
- if (showDebugInfo.value) {
442
- ctx.fillStyle = secondaryColor.value;
443
- ctx.font = '12px monospace';
444
- ctx.textAlign = 'left';
445
-
446
- let debugY = viji.height - 120;
447
- ctx.fillText(`Frame: ${viji.frameCount}`, 10, debugY);
448
- debugY += 15;
449
- ctx.fillText(`Time: ${viji.time.toFixed(2)}s`, 10, debugY);
450
- debugY += 15;
451
- ctx.fillText(`Particles: ${particleCount.value}`, 10, debugY);
452
- debugY += 15;
453
- ctx.fillText(`Shape: ${shapeType.value} (${shapeSize.value}px)`, 10, debugY);
454
- debugY += 15;
455
- ctx.fillText(`Animation: ${animationSpeed.value.toFixed(1)}x`, 10, debugY);
456
- }
457
-
458
- // Draw interaction info
459
- if (showInteractionInfo.value) {
460
- ctx.fillStyle = primaryColor.value + 'CC';
461
- ctx.font = '12px monospace';
462
- ctx.textAlign = 'right';
463
-
464
- let infoY = viji.height - 140;
465
-
466
- ctx.fillText('INTERACTIONS:', viji.width - 10, infoY);
467
- infoY += 15;
468
-
469
- if (mouse && mouse.isInCanvas) {
470
- ctx.fillText(`Mouse: (${Math.round(mouse.x)}, ${Math.round(mouse.y)})`, viji.width - 10, infoY);
471
- infoY += 15;
472
- const buttons = (mouse.leftButton ? 'L' : '-') + (mouse.rightButton ? 'R' : '-') + (mouse.middleButton ? 'M' : '-');
473
- ctx.fillText(`Buttons: ${buttons}`, viji.width - 10, infoY);
474
- infoY += 15;
475
- } else {
476
- ctx.fillText('Mouse: outside canvas', viji.width - 10, infoY);
477
- infoY += 15;
478
- }
479
-
480
- if (keyboardControl.value && keyboard) {
481
- const activeKeys = Array.from(keyboard.activeKeys || []);
482
- ctx.fillText(`Keys: ${activeKeys.length > 0 ? activeKeys.slice(0, 3).join(', ') : 'none'}`, viji.width - 10, infoY);
483
- infoY += 15;
484
- }
485
-
486
- ctx.fillText(`Touches: ${(touches && touches.points ? touches.points.length : 0)}`, viji.width - 10, infoY);
487
- infoY += 15;
488
-
489
- if (touches && touches.points && touches.points.length > 0) {
490
- const touch0 = touches.points[0];
491
- ctx.fillText(`Touch: (${Math.round(touch0.x)}, ${Math.round(touch0.y)})`, viji.width - 10, infoY);
492
- }
493
- }
494
-
495
- // Draw audio visualization
496
- if (showAudioViz.value && audio && audio.isConnected) {
497
- ctx.fillStyle = 'rgba(0, 255, 255, 0.9)';
498
- ctx.font = '12px monospace';
499
- ctx.textAlign = 'left';
500
-
501
- let audioY = 60;
502
-
503
- ctx.fillText('🎵 AUDIO ANALYSIS:', 10, audioY);
504
- audioY += 15;
505
- ctx.fillText(`Volume: ${((audio.volume?.rms || 0) * 100).toFixed(1)}%`, 10, audioY);
506
- audioY += 15;
507
- ctx.fillText(`Peak: ${((audio.volume?.peak || 0) * 100).toFixed(1)}%`, 10, audioY);
508
- audioY += 15;
509
-
510
- // Frequency bands
511
- const bands = ['bass', 'mid', 'treble'];
512
- for (const band of bands) {
513
- const value = (audio && audio.bands ? (audio.bands[band] || 0) : 0);
514
- ctx.fillText(`${band}: ${(value * 100).toFixed(1)}%`, 10, audioY);
515
- audioY += 15;
516
- }
517
-
518
- // Visual frequency bars
519
- const barWidth = 4;
520
- const barSpacing = 6;
521
- const barHeight = 40;
522
- const barStartX = 10;
523
- const barStartY = audioY + 5;
524
-
525
- const allBands = ['subBass', 'bass', 'lowMid', 'mid', 'highMid', 'presence', 'brilliance', 'treble'];
526
-
527
- for (let i = 0; i < allBands.length; i++) {
528
- const bandValue = (audio && audio.bands ? (audio.bands[allBands[i]] || 0) : 0);
529
- const x = barStartX + i * barSpacing;
530
- const barHeightValue = bandValue * barHeight;
531
-
532
- // Background bar
533
- ctx.fillStyle = 'rgba(100, 100, 100, 0.3)';
534
- ctx.fillRect(x, barStartY, barWidth, barHeight);
535
-
536
- // Value bar with color
537
- const barHue = (i / allBands.length) * 300;
538
- ctx.fillStyle = `hsla(${barHue}, 70%, 60%, 0.8)`;
539
- ctx.fillRect(x, barStartY + barHeight - barHeightValue, barWidth, barHeightValue);
540
- }
541
- }
542
-
543
- // Draw video overlay
544
- if (showVideoOverlay.value && video && video.isConnected && video.currentFrame) {
545
- ctx.save();
546
- ctx.globalAlpha = 0.3;
547
-
548
- // Calculate video display size
549
- const videoWidth = video.frameWidth || 320;
550
- const videoHeight = video.frameHeight || 240;
551
- const displayWidth = 160;
552
- const displayHeight = (videoHeight / videoWidth) * displayWidth;
553
-
554
- try {
555
- ctx.drawImage(
556
- video.currentFrame,
557
- 0, 0, videoWidth, videoHeight,
558
- viji.width - displayWidth - 10, 80, displayWidth, displayHeight
559
- );
560
- } catch (error) {
561
- // Fallback
562
- ctx.fillStyle = 'rgba(255, 100, 100, 0.5)';
563
- ctx.fillRect(viji.width - displayWidth - 10, 80, displayWidth, displayHeight);
564
- ctx.fillStyle = 'white';
565
- ctx.font = '10px monospace';
566
- ctx.textAlign = 'center';
567
- ctx.fillText('Video', viji.width - displayWidth/2 - 10, 95);
568
- }
569
-
570
- ctx.restore();
571
-
572
- // Video info
573
- ctx.fillStyle = 'rgba(255, 255, 0, 0.9)';
574
- ctx.font = '10px monospace';
575
- ctx.textAlign = 'right';
576
-
577
- let videoInfoY = 250;
578
- ctx.fillText('📹 VIDEO:', viji.width - 10, videoInfoY);
579
- videoInfoY += 12;
580
- ctx.fillText(`${videoWidth}x${videoHeight}`, viji.width - 10, videoInfoY);
581
- videoInfoY += 12;
582
- ctx.fillText(`${(video.frameRate || 30).toFixed(1)} FPS`, viji.width - 10, videoInfoY);
583
- }
584
- }
585
-
586
- // Helper function for color hue adjustment
587
- function adjustHue(hexColor, degrees) {
588
- // Simple hue adjustment - in a real implementation this would be more sophisticated
589
- const hex = hexColor.replace('#', '');
590
- const r = parseInt(hex.substr(0, 2), 16) / 255;
591
- const g = parseInt(hex.substr(2, 2), 16) / 255;
592
- const b = parseInt(hex.substr(4, 2), 16) / 255;
593
-
594
- // Convert to HSL, adjust hue, convert back to RGB
595
- const max = Math.max(r, g, b);
596
- const min = Math.min(r, g, b);
597
- let h = 0;
598
-
599
- if (max !== min) {
600
- const d = max - min;
601
- switch (max) {
602
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
603
- case g: h = (b - r) / d + 2; break;
604
- case b: h = (r - g) / d + 4; break;
605
- }
606
- h /= 6;
607
- }
608
-
609
- // Adjust hue
610
- h = (h + degrees / 360) % 1;
611
- if (h < 0) h += 1;
612
-
613
- // Convert back to RGB (simplified)
614
- const newR = Math.round(Math.max(0, Math.min(255, r * 255 + Math.sin(h * Math.PI * 2) * 50)));
615
- const newG = Math.round(Math.max(0, Math.min(255, g * 255 + Math.cos(h * Math.PI * 2) * 50)));
616
- const newB = Math.round(Math.max(0, Math.min(255, b * 255 + Math.sin(h * Math.PI * 4) * 50)));
617
-
618
- return `#${newR.toString(16).padStart(2, '0')}${newG.toString(16).padStart(2, '0')}${newB.toString(16).padStart(2, '0')}`;
619
- }
@@ -1,15 +0,0 @@
1
- // Ambient types for Viji scenes in this folder only.
2
- // This file is editor-only; it is not bundled into artist code.
3
- /// <reference types="@viji-dev/core/artist-global" />
4
-
5
- // Some older bundles referenced ArtistAPI; provide a compatibility alias.
6
- declare namespace VijiCore {
7
- type ArtistAPI = VijiAPI;
8
- }
9
-
10
- // Tell the type-checker that a global render function is observed externally by runtime
11
- declare function render(viji: any): void;
12
- // This prevents editor "unused" noise without requiring artists to add code
13
- // (Implementations defined per scene are consumed by Viji Core worker)
14
-
15
-