@viji-dev/sdk 1.0.0 → 1.0.1
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/README.md +155 -60
- package/bin/viji.js +9 -29
- package/dist/assets/artist-dts-BHUsvSI6.js +613 -0
- package/dist/assets/artist-dts-p5-Cyw8vmy_.js +736 -0
- package/dist/assets/core-CiQx3w0t.js +12 -0
- package/dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/dist/assets/docs-api-PBLtY4Ni.js +12381 -0
- package/dist/assets/engine-javascript-CXyY7cc8.js +141 -0
- package/dist/assets/essentia-wasm.web-0S-sW98u-CYV1l1zv.js +38 -0
- package/dist/assets/essentia.js-core.es-DnrJE0uR-DOSrF5_G.js +32 -0
- package/dist/assets/glsl-DMyvO4G4.js +1 -0
- package/dist/assets/index-BhFxsauQ.js +215 -0
- package/dist/assets/index-BqhVeA7U.css +1 -0
- package/dist/assets/index-T4TOjvD0.js +1 -0
- package/dist/assets/index-Wz9WqGqz.js +52 -0
- package/dist/assets/index-t24aGwla.js +1 -0
- package/dist/assets/javascript-wDzz0qaB.js +1 -0
- package/dist/assets/shader-uniforms-GdaUkQPK.js +1 -0
- package/dist/assets/typescript-BPQ3VLAy.js +1 -0
- package/dist/assets/viji.worker-CQSJ0SiO-ljtBlcNZ.js +27018 -0
- package/{index.html → dist/index.html} +2 -1
- package/package.json +31 -35
- package/src/cli/commands/build.js +50 -99
- package/src/cli/commands/create.js +32 -47
- package/src/cli/commands/dev.js +30 -97
- package/src/cli/server/dev-server.js +233 -0
- package/src/cli/server/scene-scanner.js +93 -0
- package/src/cli/server/vite-scene-plugin.d.ts +2 -0
- package/src/cli/server/vite-scene-plugin.js +134 -0
- package/src/cli/utils/cli-utils.js +29 -139
- package/src/cli/utils/scene-compiler.js +10 -17
- package/src/templates/scene-templates.js +85 -0
- package/.gitignore +0 -29
- package/eslint.config.js +0 -37
- package/postcss.config.js +0 -6
- package/scenes/audio-visualizer/main.js +0 -287
- package/scenes/core-demo/main.js +0 -532
- package/scenes/demo-scene/main.js +0 -619
- package/scenes/global.d.ts +0 -15
- package/scenes/particle-system/main.js +0 -349
- package/scenes/tsconfig.json +0 -12
- package/scenes/video-mirror/main.ts +0 -436
- package/src/App.css +0 -42
- package/src/App.tsx +0 -279
- package/src/cli/commands/init.js +0 -262
- package/src/components/SDKPage.tsx +0 -337
- package/src/components/core/CoreContainer.tsx +0 -126
- package/src/components/ui/DeviceSelectionList.tsx +0 -137
- package/src/components/ui/FPSCounter.tsx +0 -78
- package/src/components/ui/FileDropzonePanel.tsx +0 -120
- package/src/components/ui/FileListPanel.tsx +0 -285
- package/src/components/ui/InputExpansionPanel.tsx +0 -31
- package/src/components/ui/MediaPlayerControls.tsx +0 -191
- package/src/components/ui/MenuContainer.tsx +0 -71
- package/src/components/ui/ParametersMenu.tsx +0 -797
- package/src/components/ui/ProjectSwitcherMenu.tsx +0 -192
- package/src/components/ui/QuickInputControls.tsx +0 -542
- package/src/components/ui/SDKMenuSystem.tsx +0 -96
- package/src/components/ui/SettingsMenu.tsx +0 -346
- package/src/components/ui/SimpleInputControls.tsx +0 -137
- package/src/index.css +0 -68
- package/src/main.tsx +0 -10
- package/src/scenes-hmr.ts +0 -158
- package/src/services/project-filesystem.ts +0 -436
- package/src/stores/scene-player/index.ts +0 -3
- package/src/stores/scene-player/input-manager.store.ts +0 -1045
- package/src/stores/scene-player/scene-session.store.ts +0 -659
- package/src/styles/globals.css +0 -111
- package/src/templates/minimal-template.js +0 -11
- package/src/utils/debounce.js +0 -34
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.js +0 -18
- package/tsconfig.app.json +0 -27
- package/tsconfig.json +0 -27
- package/tsconfig.node.json +0 -27
- package/vite.config.ts +0 -54
- /package/{public → dist}/favicon.png +0 -0
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
// Video Reactive Mirror Scene - Parameter Object API
|
|
2
|
-
console.log('📹 VIDEO MIRROR SCENE LOADED');
|
|
3
|
-
|
|
4
|
-
// Define parameters using helper functions (returns parameter objects)
|
|
5
|
-
const videoBlur = viji.slider(0, {
|
|
6
|
-
min: 0,
|
|
7
|
-
max: 20,
|
|
8
|
-
step: 1,
|
|
9
|
-
label: 'Video Blur',
|
|
10
|
-
description: 'Apply blur effect to video',
|
|
11
|
-
group: 'video',
|
|
12
|
-
category: 'video'
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const videoSaturation = viji.slider(1.0, {
|
|
16
|
-
min: 0,
|
|
17
|
-
max: 3.0,
|
|
18
|
-
step: 0.1,
|
|
19
|
-
label: 'Video Saturation',
|
|
20
|
-
description: 'Color saturation level',
|
|
21
|
-
group: 'video',
|
|
22
|
-
category: 'video'
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const videoBrightness = viji.slider(1.0, {
|
|
26
|
-
min: 0.1,
|
|
27
|
-
max: 3.0,
|
|
28
|
-
step: 0.1,
|
|
29
|
-
label: 'Video Brightness',
|
|
30
|
-
description: 'Brightness adjustment',
|
|
31
|
-
group: 'video',
|
|
32
|
-
category: 'video'
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const videoContrast = viji.slider(1.0, {
|
|
36
|
-
min: 0.1,
|
|
37
|
-
max: 3.0,
|
|
38
|
-
step: 0.1,
|
|
39
|
-
label: 'Video Contrast',
|
|
40
|
-
description: 'Contrast adjustment',
|
|
41
|
-
group: 'video',
|
|
42
|
-
category: 'video'
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const mirrorMode = viji.select('none', {
|
|
46
|
-
options: ['none', 'horizontal', 'vertical', 'both'],
|
|
47
|
-
label: 'Mirror Mode',
|
|
48
|
-
description: 'How to mirror the video',
|
|
49
|
-
group: 'video',
|
|
50
|
-
category: 'video'
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const flipHorizontal = viji.toggle(false, {
|
|
54
|
-
label: 'Flip Horizontal',
|
|
55
|
-
description: 'Flip video horizontally',
|
|
56
|
-
group: 'video',
|
|
57
|
-
category: 'video'
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const flipVertical = viji.toggle(false, {
|
|
61
|
-
label: 'Flip Vertical',
|
|
62
|
-
description: 'Flip video vertically',
|
|
63
|
-
group: 'video',
|
|
64
|
-
category: 'video'
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const waveDistortion = viji.slider(0, {
|
|
68
|
-
min: 0,
|
|
69
|
-
max: 50,
|
|
70
|
-
step: 2,
|
|
71
|
-
label: 'Wave Distortion',
|
|
72
|
-
description: 'Strength of wave distortion effect',
|
|
73
|
-
group: 'effects'
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const waveFrequency = viji.slider(0.01, {
|
|
77
|
-
min: 0.001,
|
|
78
|
-
max: 0.1,
|
|
79
|
-
step: 0.005,
|
|
80
|
-
label: 'Wave Frequency',
|
|
81
|
-
description: 'Frequency of wave distortion',
|
|
82
|
-
group: 'effects'
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
const waveSpeed = viji.slider(1.0, {
|
|
86
|
-
min: 0.1,
|
|
87
|
-
max: 5.0,
|
|
88
|
-
step: 0.1,
|
|
89
|
-
label: 'Wave Speed',
|
|
90
|
-
description: 'Speed of wave animation',
|
|
91
|
-
group: 'effects'
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const pixelate = viji.slider(1, {
|
|
95
|
-
min: 1,
|
|
96
|
-
max: 32,
|
|
97
|
-
step: 1,
|
|
98
|
-
label: 'Pixelate',
|
|
99
|
-
description: 'Pixelation level (1 = no pixelation)',
|
|
100
|
-
group: 'effects'
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const colorShift = viji.slider(0, {
|
|
104
|
-
min: 0,
|
|
105
|
-
max: 360,
|
|
106
|
-
step: 10,
|
|
107
|
-
label: 'Color Shift',
|
|
108
|
-
description: 'Hue shift in degrees',
|
|
109
|
-
group: 'effects'
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const colorInvert = viji.toggle(false, {
|
|
113
|
-
label: 'Color Invert',
|
|
114
|
-
description: 'Invert video colors',
|
|
115
|
-
group: 'effects'
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const colorChannels = viji.select('rgb', {
|
|
119
|
-
options: ['rgb', 'red', 'green', 'blue', 'monochrome'],
|
|
120
|
-
label: 'Color Channels',
|
|
121
|
-
description: 'Which color channels to display',
|
|
122
|
-
group: 'effects'
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const glitchEffect = viji.toggle(false, {
|
|
126
|
-
label: 'Glitch Effect',
|
|
127
|
-
description: 'Random glitch artifacts',
|
|
128
|
-
group: 'effects'
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const showGrid = viji.toggle(false, {
|
|
132
|
-
label: 'Show Grid',
|
|
133
|
-
description: 'Overlay grid lines',
|
|
134
|
-
group: 'overlay'
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const gridSize = viji.slider(50, {
|
|
138
|
-
min: 10,
|
|
139
|
-
max: 200,
|
|
140
|
-
step: 10,
|
|
141
|
-
label: 'Grid Size',
|
|
142
|
-
description: 'Size of grid cells',
|
|
143
|
-
group: 'overlay'
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const showScanlines = viji.toggle(false, {
|
|
147
|
-
label: 'Show Scanlines',
|
|
148
|
-
description: 'CRT-style scanlines',
|
|
149
|
-
group: 'overlay'
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const scanlineIntensity = viji.slider(0.5, {
|
|
153
|
-
min: 0.1,
|
|
154
|
-
max: 1.0,
|
|
155
|
-
step: 0.1,
|
|
156
|
-
label: 'Scanline Intensity',
|
|
157
|
-
description: 'Opacity of scanlines',
|
|
158
|
-
group: 'overlay'
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const audioReactive = viji.toggle(false, {
|
|
162
|
-
label: 'Audio Reactive',
|
|
163
|
-
description: 'Make effects react to audio',
|
|
164
|
-
group: 'audio',
|
|
165
|
-
category: 'audio'
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const audioInfluence = viji.slider(1.0, {
|
|
169
|
-
min: 0.1,
|
|
170
|
-
max: 5.0,
|
|
171
|
-
step: 0.1,
|
|
172
|
-
label: 'Audio Influence',
|
|
173
|
-
description: 'How much audio affects video',
|
|
174
|
-
group: 'audio',
|
|
175
|
-
category: 'audio'
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// Helper function to apply video effects
|
|
180
|
-
function applyVideoEffects(_ctx: any, imageData: ImageData, _width: number, _height: number, _time: number, audio?: any): ImageData {
|
|
181
|
-
const data = imageData.data;
|
|
182
|
-
|
|
183
|
-
// Audio reactive modulation
|
|
184
|
-
let audioMod = 1;
|
|
185
|
-
if (audioReactive.value && audio && audio.isConnected) {
|
|
186
|
-
const volume = ((audio && audio.volume && audio.volume.rms) || 0);
|
|
187
|
-
audioMod = 1 + (volume * audioInfluence.value);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
191
|
-
let r = data[i];
|
|
192
|
-
let g = data[i + 1];
|
|
193
|
-
let b = data[i + 2];
|
|
194
|
-
|
|
195
|
-
// Apply brightness and contrast
|
|
196
|
-
r = Math.min(255, Math.max(0, (r - 128) * videoContrast.value + 128) * videoBrightness.value * audioMod);
|
|
197
|
-
g = Math.min(255, Math.max(0, (g - 128) * videoContrast.value + 128) * videoBrightness.value * audioMod);
|
|
198
|
-
b = Math.min(255, Math.max(0, (b - 128) * videoContrast.value + 128) * videoBrightness.value * audioMod);
|
|
199
|
-
|
|
200
|
-
// Apply saturation
|
|
201
|
-
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
202
|
-
r = gray + (r - gray) * videoSaturation.value;
|
|
203
|
-
g = gray + (g - gray) * videoSaturation.value;
|
|
204
|
-
b = gray + (b - gray) * videoSaturation.value;
|
|
205
|
-
|
|
206
|
-
// Color channel filtering
|
|
207
|
-
switch (colorChannels.value) {
|
|
208
|
-
case 'red':
|
|
209
|
-
g = b = 0;
|
|
210
|
-
break;
|
|
211
|
-
case 'green':
|
|
212
|
-
r = b = 0;
|
|
213
|
-
break;
|
|
214
|
-
case 'blue':
|
|
215
|
-
r = g = 0;
|
|
216
|
-
break;
|
|
217
|
-
case 'monochrome':
|
|
218
|
-
r = g = b = gray;
|
|
219
|
-
break;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Color inversion
|
|
223
|
-
if (colorInvert.value) {
|
|
224
|
-
r = 255 - r;
|
|
225
|
-
g = 255 - g;
|
|
226
|
-
b = 255 - b;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Color shift (simple hue rotation approximation)
|
|
230
|
-
if (colorShift.value > 0) {
|
|
231
|
-
const shift = colorShift.value / 360;
|
|
232
|
-
const temp = r;
|
|
233
|
-
r = Math.min(255, r * (1 - shift) + g * shift);
|
|
234
|
-
g = Math.min(255, g * (1 - shift) + b * shift);
|
|
235
|
-
b = Math.min(255, b * (1 - shift) + temp * shift);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
data[i] = Math.min(255, Math.max(0, r));
|
|
239
|
-
data[i + 1] = Math.min(255, Math.max(0, g));
|
|
240
|
-
data[i + 2] = Math.min(255, Math.max(0, b));
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return imageData;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Render function using parameter object API
|
|
247
|
-
function render(viji: any) {
|
|
248
|
-
const ctx = viji.useContext('2d');
|
|
249
|
-
const video = viji.video;
|
|
250
|
-
const audio = viji.audio;
|
|
251
|
-
|
|
252
|
-
// Clear background
|
|
253
|
-
ctx.fillStyle = '#000000';
|
|
254
|
-
ctx.fillRect(0, 0, viji.width, viji.height);
|
|
255
|
-
|
|
256
|
-
// Check if video is connected
|
|
257
|
-
if (!(video && video.isConnected) || !video.currentFrame) {
|
|
258
|
-
// Show instructions when no video
|
|
259
|
-
ctx.fillStyle = '#ff6b6b';
|
|
260
|
-
ctx.font = '24px Arial';
|
|
261
|
-
ctx.textAlign = 'center';
|
|
262
|
-
ctx.fillText('📹 Connect video to see mirror effects', viji.width / 2, viji.height / 2);
|
|
263
|
-
|
|
264
|
-
ctx.font = '16px Arial';
|
|
265
|
-
ctx.fillStyle = '#4ecdc4';
|
|
266
|
-
ctx.fillText('Use the video controls to connect camera, file, or screen capture', viji.width / 2, viji.height / 2 + 40);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
try {
|
|
271
|
-
const videoWidth = video.frameWidth || 640;
|
|
272
|
-
const videoHeight = video.frameHeight || 480;
|
|
273
|
-
|
|
274
|
-
// Calculate display dimensions
|
|
275
|
-
const aspectRatio = videoWidth / videoHeight;
|
|
276
|
-
const canvasAspect = viji.width / viji.height;
|
|
277
|
-
|
|
278
|
-
let drawWidth, drawHeight, drawX, drawY;
|
|
279
|
-
|
|
280
|
-
if (aspectRatio > canvasAspect) {
|
|
281
|
-
drawWidth = viji.width;
|
|
282
|
-
drawHeight = viji.width / aspectRatio;
|
|
283
|
-
drawX = 0;
|
|
284
|
-
drawY = (viji.height - drawHeight) / 2;
|
|
285
|
-
} else {
|
|
286
|
-
drawWidth = viji.height * aspectRatio;
|
|
287
|
-
drawHeight = viji.height;
|
|
288
|
-
drawX = (viji.width - drawWidth) / 2;
|
|
289
|
-
drawY = 0;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
ctx.save();
|
|
293
|
-
|
|
294
|
-
// Apply transformations
|
|
295
|
-
if (flipHorizontal.value || flipVertical.value) {
|
|
296
|
-
ctx.translate(drawX + drawWidth / 2, drawY + drawHeight / 2);
|
|
297
|
-
ctx.scale(flipHorizontal.value ? -1 : 1, flipVertical.value ? -1 : 1);
|
|
298
|
-
ctx.translate(-drawWidth / 2, -drawHeight / 2);
|
|
299
|
-
drawX = drawY = 0;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Apply wave distortion
|
|
303
|
-
if (waveDistortion.value > 0) {
|
|
304
|
-
const time = viji.time * waveSpeed.value;
|
|
305
|
-
for (let y = 0; y < drawHeight; y += 10) {
|
|
306
|
-
const wave = Math.sin((y * waveFrequency.value) + time) * waveDistortion.value;
|
|
307
|
-
ctx.drawImage(
|
|
308
|
-
video.currentFrame,
|
|
309
|
-
0, y, videoWidth, 10,
|
|
310
|
-
drawX + wave, drawY + y, drawWidth, 10
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
} else {
|
|
314
|
-
// Normal drawing
|
|
315
|
-
ctx.drawImage(video.currentFrame, drawX, drawY, drawWidth, drawHeight);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Apply pixelation
|
|
319
|
-
if (pixelate.value > 1) {
|
|
320
|
-
const pixelSize = pixelate.value;
|
|
321
|
-
|
|
322
|
-
for (let y = 0; y < drawHeight; y += pixelSize) {
|
|
323
|
-
for (let x = 0; x < drawWidth; x += pixelSize) {
|
|
324
|
-
const pixelData = ctx.getImageData(drawX + x, drawY + y, 1, 1).data;
|
|
325
|
-
ctx.fillStyle = `rgb(${pixelData[0]}, ${pixelData[1]}, ${pixelData[2]})`;
|
|
326
|
-
ctx.fillRect(drawX + x, drawY + y, pixelSize, pixelSize);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Apply post-processing effects
|
|
332
|
-
if (videoBlur.value > 0 || videoSaturation.value !== 1 || videoBrightness.value !== 1 ||
|
|
333
|
-
videoContrast.value !== 1 || colorInvert.value || colorShift.value > 0 ||
|
|
334
|
-
colorChannels.value !== 'rgb' || audioReactive.value) {
|
|
335
|
-
const imageData = ctx.getImageData(drawX, drawY, drawWidth, drawHeight);
|
|
336
|
-
const processedData = applyVideoEffects(ctx, imageData, drawWidth, drawHeight, viji.time, audio);
|
|
337
|
-
ctx.putImageData(processedData, drawX, drawY);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Apply blur filter if needed
|
|
341
|
-
if (videoBlur.value > 0) {
|
|
342
|
-
ctx.filter = `blur(${videoBlur.value}px)`;
|
|
343
|
-
ctx.drawImage(ctx.canvas, drawX, drawY, drawWidth, drawHeight, drawX, drawY, drawWidth, drawHeight);
|
|
344
|
-
ctx.filter = 'none';
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
ctx.restore();
|
|
348
|
-
|
|
349
|
-
// Mirror mode
|
|
350
|
-
if (mirrorMode.value !== 'none') {
|
|
351
|
-
|
|
352
|
-
if (mirrorMode.value === 'horizontal' || mirrorMode.value === 'both') {
|
|
353
|
-
// Mirror right half to left half
|
|
354
|
-
ctx.save();
|
|
355
|
-
ctx.scale(-1, 1);
|
|
356
|
-
ctx.drawImage(ctx.canvas,
|
|
357
|
-
-drawX - drawWidth, drawY, drawWidth / 2, drawHeight,
|
|
358
|
-
-drawX - drawWidth / 2, drawY, drawWidth / 2, drawHeight);
|
|
359
|
-
ctx.restore();
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (mirrorMode.value === 'vertical' || mirrorMode.value === 'both') {
|
|
363
|
-
// Mirror bottom half to top half
|
|
364
|
-
ctx.save();
|
|
365
|
-
ctx.scale(1, -1);
|
|
366
|
-
ctx.drawImage(ctx.canvas,
|
|
367
|
-
drawX, -drawY - drawHeight, drawWidth, drawHeight / 2,
|
|
368
|
-
drawX, -drawY - drawHeight / 2, drawWidth, drawHeight / 2);
|
|
369
|
-
ctx.restore();
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Glitch effect
|
|
374
|
-
if (glitchEffect.value && Math.random() < 0.1) {
|
|
375
|
-
const glitchHeight = Math.random() * 20 + 5;
|
|
376
|
-
const glitchY = Math.random() * (drawHeight - glitchHeight);
|
|
377
|
-
const offset = (Math.random() - 0.5) * 20;
|
|
378
|
-
|
|
379
|
-
const glitchData = ctx.getImageData(drawX, drawY + glitchY, drawWidth, glitchHeight);
|
|
380
|
-
ctx.putImageData(glitchData, drawX + offset, drawY + glitchY);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Overlay effects
|
|
384
|
-
if (showGrid.value) {
|
|
385
|
-
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
|
|
386
|
-
ctx.lineWidth = 1;
|
|
387
|
-
|
|
388
|
-
for (let x = 0; x <= viji.width; x += gridSize.value) {
|
|
389
|
-
ctx.beginPath();
|
|
390
|
-
ctx.moveTo(x, 0);
|
|
391
|
-
ctx.lineTo(x, viji.height);
|
|
392
|
-
ctx.stroke();
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
for (let y = 0; y <= viji.height; y += gridSize.value) {
|
|
396
|
-
ctx.beginPath();
|
|
397
|
-
ctx.moveTo(0, y);
|
|
398
|
-
ctx.lineTo(viji.width, y);
|
|
399
|
-
ctx.stroke();
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (showScanlines.value) {
|
|
404
|
-
ctx.fillStyle = `rgba(0, 0, 0, ${scanlineIntensity.value})`;
|
|
405
|
-
for (let y = 0; y < viji.height; y += 4) {
|
|
406
|
-
ctx.fillRect(0, y, viji.width, 2);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
} catch (error) {
|
|
411
|
-
console.error('Video processing error:', error);
|
|
412
|
-
ctx.fillStyle = '#ff4444';
|
|
413
|
-
ctx.font = '16px Arial';
|
|
414
|
-
ctx.textAlign = 'center';
|
|
415
|
-
ctx.fillText('Video processing error', viji.width / 2, viji.height / 2);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Draw info overlay
|
|
419
|
-
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
|
|
420
|
-
ctx.font = '14px monospace';
|
|
421
|
-
ctx.textAlign = 'left';
|
|
422
|
-
|
|
423
|
-
ctx.fillText('📹 VIDEO MIRROR', 20, 25);
|
|
424
|
-
ctx.font = '11px monospace';
|
|
425
|
-
ctx.fillText(`Resolution: ${video.frameWidth}x${video.frameHeight}`, 20, 45);
|
|
426
|
-
ctx.fillText(`Effects: ${mirrorMode.value} mirror, ${colorChannels.value} channels`, 20, 60);
|
|
427
|
-
|
|
428
|
-
if (audioReactive.value && audio && audio.isConnected) {
|
|
429
|
-
ctx.fillText(`🎵 Audio: ${((((audio && audio.volume && audio.volume.rms) || 0) * 100).toFixed(1))}%`, 20, 75);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Performance info
|
|
433
|
-
ctx.textAlign = 'right';
|
|
434
|
-
ctx.fillText(`Frame: ${viji.frameCount}`, viji.width - 20, viji.height - 25);
|
|
435
|
-
ctx.fillText(`Time: ${viji.time.toFixed(1)}s`, viji.width - 20, viji.height - 10);
|
|
436
|
-
}
|
package/src/App.css
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#root {
|
|
2
|
-
max-width: 1280px;
|
|
3
|
-
margin: 0 auto;
|
|
4
|
-
padding: 2rem;
|
|
5
|
-
text-align: center;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.logo {
|
|
9
|
-
height: 6em;
|
|
10
|
-
padding: 1.5em;
|
|
11
|
-
will-change: filter;
|
|
12
|
-
transition: filter 300ms;
|
|
13
|
-
}
|
|
14
|
-
.logo:hover {
|
|
15
|
-
filter: drop-shadow(0 0 2em #646cffaa);
|
|
16
|
-
}
|
|
17
|
-
.logo.react:hover {
|
|
18
|
-
filter: drop-shadow(0 0 2em #61dafbaa);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@keyframes logo-spin {
|
|
22
|
-
from {
|
|
23
|
-
transform: rotate(0deg);
|
|
24
|
-
}
|
|
25
|
-
to {
|
|
26
|
-
transform: rotate(360deg);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
31
|
-
a:nth-of-type(2) .logo {
|
|
32
|
-
animation: logo-spin infinite 20s linear;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.card {
|
|
37
|
-
padding: 2em;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.read-the-docs {
|
|
41
|
-
color: #888;
|
|
42
|
-
}
|