@stevejtrettel/shader-sandbox 0.1.0
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 +391 -0
- package/bin/cli.js +389 -0
- package/dist-lib/app/App.d.ts +134 -0
- package/dist-lib/app/App.d.ts.map +1 -0
- package/dist-lib/app/App.js +570 -0
- package/dist-lib/app/types.d.ts +32 -0
- package/dist-lib/app/types.d.ts.map +1 -0
- package/dist-lib/app/types.js +6 -0
- package/dist-lib/editor/EditorPanel.d.ts +39 -0
- package/dist-lib/editor/EditorPanel.d.ts.map +1 -0
- package/dist-lib/editor/EditorPanel.js +274 -0
- package/dist-lib/editor/prism-editor.css +99 -0
- package/dist-lib/editor/prism-editor.d.ts +19 -0
- package/dist-lib/editor/prism-editor.d.ts.map +1 -0
- package/dist-lib/editor/prism-editor.js +96 -0
- package/dist-lib/embed.d.ts +17 -0
- package/dist-lib/embed.d.ts.map +1 -0
- package/dist-lib/embed.js +35 -0
- package/dist-lib/engine/ShadertoyEngine.d.ts +160 -0
- package/dist-lib/engine/ShadertoyEngine.d.ts.map +1 -0
- package/dist-lib/engine/ShadertoyEngine.js +704 -0
- package/dist-lib/engine/glHelpers.d.ts +79 -0
- package/dist-lib/engine/glHelpers.d.ts.map +1 -0
- package/dist-lib/engine/glHelpers.js +298 -0
- package/dist-lib/engine/types.d.ts +77 -0
- package/dist-lib/engine/types.d.ts.map +1 -0
- package/dist-lib/engine/types.js +7 -0
- package/dist-lib/index.d.ts +12 -0
- package/dist-lib/index.d.ts.map +1 -0
- package/dist-lib/index.js +9 -0
- package/dist-lib/layouts/DefaultLayout.d.ts +17 -0
- package/dist-lib/layouts/DefaultLayout.d.ts.map +1 -0
- package/dist-lib/layouts/DefaultLayout.js +27 -0
- package/dist-lib/layouts/FullscreenLayout.d.ts +17 -0
- package/dist-lib/layouts/FullscreenLayout.d.ts.map +1 -0
- package/dist-lib/layouts/FullscreenLayout.js +27 -0
- package/dist-lib/layouts/SplitLayout.d.ts +26 -0
- package/dist-lib/layouts/SplitLayout.d.ts.map +1 -0
- package/dist-lib/layouts/SplitLayout.js +61 -0
- package/dist-lib/layouts/TabbedLayout.d.ts +38 -0
- package/dist-lib/layouts/TabbedLayout.d.ts.map +1 -0
- package/dist-lib/layouts/TabbedLayout.js +305 -0
- package/dist-lib/layouts/index.d.ts +24 -0
- package/dist-lib/layouts/index.d.ts.map +1 -0
- package/dist-lib/layouts/index.js +36 -0
- package/dist-lib/layouts/split.css +196 -0
- package/dist-lib/layouts/tabbed.css +345 -0
- package/dist-lib/layouts/types.d.ts +48 -0
- package/dist-lib/layouts/types.d.ts.map +1 -0
- package/dist-lib/layouts/types.js +4 -0
- package/dist-lib/main.d.ts +15 -0
- package/dist-lib/main.d.ts.map +1 -0
- package/dist-lib/main.js +102 -0
- package/dist-lib/project/generatedLoader.d.ts +3 -0
- package/dist-lib/project/generatedLoader.d.ts.map +1 -0
- package/dist-lib/project/generatedLoader.js +17 -0
- package/dist-lib/project/loadProject.d.ts +22 -0
- package/dist-lib/project/loadProject.d.ts.map +1 -0
- package/dist-lib/project/loadProject.js +350 -0
- package/dist-lib/project/loaderHelper.d.ts +7 -0
- package/dist-lib/project/loaderHelper.d.ts.map +1 -0
- package/dist-lib/project/loaderHelper.js +240 -0
- package/dist-lib/project/types.d.ts +192 -0
- package/dist-lib/project/types.d.ts.map +1 -0
- package/dist-lib/project/types.js +7 -0
- package/dist-lib/styles/base.css +29 -0
- package/package.json +48 -0
- package/src/app/App.ts +699 -0
- package/src/app/app.css +208 -0
- package/src/app/types.ts +36 -0
- package/src/editor/EditorPanel.ts +340 -0
- package/src/editor/editor-panel.css +175 -0
- package/src/editor/prism-editor.css +99 -0
- package/src/editor/prism-editor.ts +124 -0
- package/src/embed.ts +55 -0
- package/src/engine/ShadertoyEngine.ts +929 -0
- package/src/engine/glHelpers.ts +432 -0
- package/src/engine/types.ts +118 -0
- package/src/index.ts +13 -0
- package/src/layouts/DefaultLayout.ts +40 -0
- package/src/layouts/FullscreenLayout.ts +40 -0
- package/src/layouts/SplitLayout.ts +81 -0
- package/src/layouts/TabbedLayout.ts +371 -0
- package/src/layouts/default.css +22 -0
- package/src/layouts/fullscreen.css +15 -0
- package/src/layouts/index.ts +44 -0
- package/src/layouts/split.css +196 -0
- package/src/layouts/tabbed.css +345 -0
- package/src/layouts/types.ts +58 -0
- package/src/main.ts +114 -0
- package/src/project/generatedLoader.ts +23 -0
- package/src/project/loadProject.ts +421 -0
- package/src/project/loaderHelper.ts +300 -0
- package/src/project/types.ts +243 -0
- package/src/styles/base.css +29 -0
- package/src/styles/embed.css +14 -0
- package/src/vite-env.d.ts +1 -0
- package/templates/index.html +28 -0
- package/templates/main.ts +126 -0
- package/templates/package.json +12 -0
- package/templates/shaders/example-buffer/bufferA.glsl +14 -0
- package/templates/shaders/example-buffer/config.json +10 -0
- package/templates/shaders/example-buffer/image.glsl +5 -0
- package/templates/shaders/example-gradient/config.json +4 -0
- package/templates/shaders/example-gradient/image.glsl +7 -0
- package/templates/vite.config.js +35 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shader Sandbox CLI
|
|
5
|
+
* Commands:
|
|
6
|
+
* shader create <name> - Create a new shader project (recommended)
|
|
7
|
+
* shader init - Initialize shaders in current directory
|
|
8
|
+
* shader new <name> - Create a new shader
|
|
9
|
+
* shader dev <shader-name> - Start development server
|
|
10
|
+
* shader build <shader-name> - Build for production
|
|
11
|
+
* shader list - List available shaders
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { spawn } from 'child_process';
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = path.dirname(__filename);
|
|
21
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
22
|
+
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
const command = args[0];
|
|
25
|
+
|
|
26
|
+
function printUsage() {
|
|
27
|
+
console.log(`
|
|
28
|
+
Shader Sandbox - Local GLSL shader development
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
shader create <name> Create a new shader project (recommended)
|
|
32
|
+
shader init Initialize shaders in current directory
|
|
33
|
+
shader new <name> Create a new shader
|
|
34
|
+
shader dev <shader-name> Start development server
|
|
35
|
+
shader build <shader-name> Build for production
|
|
36
|
+
shader list List available shaders
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
shader create my-shaders Create a new project with everything set up
|
|
40
|
+
shader new my-shader Create shaders/my-shader/
|
|
41
|
+
shader dev my-shader Run shader in dev mode
|
|
42
|
+
shader build my-shader Build shader to dist/
|
|
43
|
+
shader list Show all shaders
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function copyDir(src, dest, skipFiles = []) {
|
|
48
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
49
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
50
|
+
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
// Skip specified files
|
|
53
|
+
if (skipFiles.includes(entry.name)) continue;
|
|
54
|
+
|
|
55
|
+
const srcPath = path.join(src, entry.name);
|
|
56
|
+
const destPath = path.join(dest, entry.name);
|
|
57
|
+
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
copyDir(srcPath, destPath, skipFiles);
|
|
60
|
+
} else {
|
|
61
|
+
fs.copyFileSync(srcPath, destPath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function listShaders(cwd) {
|
|
67
|
+
const shadersDir = path.join(cwd, 'shaders');
|
|
68
|
+
if (!fs.existsSync(shadersDir)) {
|
|
69
|
+
console.error('Error: shaders/ directory not found');
|
|
70
|
+
console.error('Run "shader init" first');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const entries = fs.readdirSync(shadersDir, { withFileTypes: true });
|
|
75
|
+
const shaders = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
76
|
+
|
|
77
|
+
if (shaders.length === 0) {
|
|
78
|
+
console.log('No shaders found. Run "shader new <name>" to create one.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log('Available shaders:');
|
|
83
|
+
shaders.forEach(s => console.log(` ${s}`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function create(projectName) {
|
|
87
|
+
// Validate name
|
|
88
|
+
if (!projectName || !/^[a-zA-Z0-9_-]+$/.test(projectName)) {
|
|
89
|
+
console.error('Error: Invalid project name');
|
|
90
|
+
console.error('Use only letters, numbers, hyphens, and underscores');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const projectDir = path.join(process.cwd(), projectName);
|
|
95
|
+
const templatesDir = path.join(packageRoot, 'templates');
|
|
96
|
+
|
|
97
|
+
// Check if directory already exists
|
|
98
|
+
if (fs.existsSync(projectDir)) {
|
|
99
|
+
console.error(`Error: Directory "${projectName}" already exists`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log(`Creating shader project "${projectName}"...`);
|
|
104
|
+
|
|
105
|
+
// Create project directory
|
|
106
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
107
|
+
|
|
108
|
+
// Generate package.json
|
|
109
|
+
const packageJson = {
|
|
110
|
+
name: projectName,
|
|
111
|
+
version: '1.0.0',
|
|
112
|
+
type: 'module',
|
|
113
|
+
scripts: {
|
|
114
|
+
dev: 'shader dev',
|
|
115
|
+
build: 'shader build',
|
|
116
|
+
list: 'shader list'
|
|
117
|
+
},
|
|
118
|
+
dependencies: {
|
|
119
|
+
'@stevejtrettel/shader-sandbox': '^0.1.0',
|
|
120
|
+
'vite': '^5.0.0'
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
fs.writeFileSync(
|
|
125
|
+
path.join(projectDir, 'package.json'),
|
|
126
|
+
JSON.stringify(packageJson, null, 2) + '\n'
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Copy template files (skip package.json since we generated our own)
|
|
130
|
+
copyDir(templatesDir, projectDir, ['package.json']);
|
|
131
|
+
|
|
132
|
+
// Run npm install
|
|
133
|
+
console.log('Installing dependencies...');
|
|
134
|
+
|
|
135
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
136
|
+
const child = spawn(npmCmd, ['install'], {
|
|
137
|
+
cwd: projectDir,
|
|
138
|
+
stdio: 'inherit',
|
|
139
|
+
shell: process.platform === 'win32'
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
child.on('error', (err) => {
|
|
143
|
+
console.error('Failed to run npm install:', err.message);
|
|
144
|
+
console.log('\nProject created but dependencies not installed.');
|
|
145
|
+
console.log(`Run: cd ${projectName} && npm install`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
child.on('close', (code) => {
|
|
150
|
+
if (code !== 0) {
|
|
151
|
+
console.error('\nnpm install failed.');
|
|
152
|
+
console.log(`Run: cd ${projectName} && npm install`);
|
|
153
|
+
process.exit(code);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(`
|
|
157
|
+
✓ Project "${projectName}" created!
|
|
158
|
+
|
|
159
|
+
Next steps:
|
|
160
|
+
cd ${projectName}
|
|
161
|
+
shader dev example-gradient Run a shader
|
|
162
|
+
shader list Show all shaders
|
|
163
|
+
shader new my-shader Create a new shader
|
|
164
|
+
`);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function init() {
|
|
169
|
+
const cwd = process.cwd();
|
|
170
|
+
const templatesDir = path.join(packageRoot, 'templates');
|
|
171
|
+
|
|
172
|
+
// Check if directory already has shader files
|
|
173
|
+
const shaderDir = path.join(cwd, 'shaders');
|
|
174
|
+
if (fs.existsSync(shaderDir)) {
|
|
175
|
+
console.error('Error: shaders/ directory already exists');
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log('Creating shader collection...');
|
|
180
|
+
|
|
181
|
+
// Copy template files (skip package.json to not overwrite user's)
|
|
182
|
+
copyDir(templatesDir, cwd, ['package.json']);
|
|
183
|
+
|
|
184
|
+
console.log(`
|
|
185
|
+
✓ Shader collection created!
|
|
186
|
+
|
|
187
|
+
Structure:
|
|
188
|
+
shaders/
|
|
189
|
+
example-gradient/ Simple animated gradient
|
|
190
|
+
example-buffer/ BufferA feedback example
|
|
191
|
+
|
|
192
|
+
Next steps:
|
|
193
|
+
shader list Show all shaders
|
|
194
|
+
shader dev example-gradient Run a shader
|
|
195
|
+
shader new my-shader Create a new shader
|
|
196
|
+
`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function createNewShader(name) {
|
|
200
|
+
const cwd = process.cwd();
|
|
201
|
+
const shadersDir = path.join(cwd, 'shaders');
|
|
202
|
+
|
|
203
|
+
// Check shaders directory exists
|
|
204
|
+
if (!fs.existsSync(shadersDir)) {
|
|
205
|
+
console.error('Error: shaders/ directory not found');
|
|
206
|
+
console.error('Run "shader init" first');
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Validate name
|
|
211
|
+
if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
212
|
+
console.error('Error: Invalid shader name');
|
|
213
|
+
console.error('Use only letters, numbers, hyphens, and underscores');
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const shaderDir = path.join(shadersDir, name);
|
|
218
|
+
|
|
219
|
+
// Check if already exists
|
|
220
|
+
if (fs.existsSync(shaderDir)) {
|
|
221
|
+
console.error(`Error: Shader "${name}" already exists`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Create directory
|
|
226
|
+
fs.mkdirSync(shaderDir, { recursive: true });
|
|
227
|
+
|
|
228
|
+
// Create image.glsl with starter template
|
|
229
|
+
const imageGlsl = `void mainImage(out vec4 fragColor, in vec2 fragCoord)
|
|
230
|
+
{
|
|
231
|
+
// Normalized pixel coordinates (0 to 1)
|
|
232
|
+
vec2 uv = fragCoord / iResolution.xy;
|
|
233
|
+
|
|
234
|
+
// Time varying pixel color
|
|
235
|
+
vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0, 2, 4));
|
|
236
|
+
|
|
237
|
+
// Output to screen
|
|
238
|
+
fragColor = vec4(col, 1.0);
|
|
239
|
+
}
|
|
240
|
+
`;
|
|
241
|
+
|
|
242
|
+
fs.writeFileSync(path.join(shaderDir, 'image.glsl'), imageGlsl);
|
|
243
|
+
|
|
244
|
+
// Create config.json
|
|
245
|
+
const config = {
|
|
246
|
+
layout: 'default',
|
|
247
|
+
controls: true
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
fs.writeFileSync(path.join(shaderDir, 'config.json'), JSON.stringify(config, null, 2) + '\n');
|
|
251
|
+
|
|
252
|
+
console.log(`
|
|
253
|
+
✓ Created shader "${name}"
|
|
254
|
+
|
|
255
|
+
Files:
|
|
256
|
+
shaders/${name}/image.glsl Main shader
|
|
257
|
+
shaders/${name}/config.json Configuration
|
|
258
|
+
|
|
259
|
+
Run it:
|
|
260
|
+
shader dev ${name}
|
|
261
|
+
`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function runVite(viteArgs, shaderName) {
|
|
265
|
+
const cwd = process.cwd();
|
|
266
|
+
|
|
267
|
+
// Check for vite.config.js
|
|
268
|
+
if (!fs.existsSync(path.join(cwd, 'vite.config.js'))) {
|
|
269
|
+
console.error('Error: vite.config.js not found');
|
|
270
|
+
console.error('Run "shader init" first');
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Find vite binary
|
|
275
|
+
const viteBin = path.join(cwd, 'node_modules', '.bin', 'vite');
|
|
276
|
+
if (!fs.existsSync(viteBin)) {
|
|
277
|
+
console.error('Error: vite not found in node_modules');
|
|
278
|
+
console.error('Run "npm install" first');
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const env = { ...process.env, SHADER_NAME: shaderName };
|
|
283
|
+
|
|
284
|
+
const child = spawn(viteBin, viteArgs, {
|
|
285
|
+
cwd,
|
|
286
|
+
stdio: 'inherit',
|
|
287
|
+
shell: process.platform === 'win32',
|
|
288
|
+
env
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
child.on('error', (err) => {
|
|
292
|
+
console.error('Failed to start vite:', err.message);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
child.on('close', (code) => {
|
|
297
|
+
process.exit(code || 0);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Main command handler
|
|
302
|
+
switch (command) {
|
|
303
|
+
case 'create': {
|
|
304
|
+
const name = args[1];
|
|
305
|
+
if (!name) {
|
|
306
|
+
console.error('Error: Specify a project name');
|
|
307
|
+
console.error(' shader create <name>');
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
create(name);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
case 'init':
|
|
315
|
+
init();
|
|
316
|
+
break;
|
|
317
|
+
|
|
318
|
+
case 'new': {
|
|
319
|
+
const name = args[1];
|
|
320
|
+
if (!name) {
|
|
321
|
+
console.error('Error: Specify a shader name');
|
|
322
|
+
console.error(' shader new <name>');
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
createNewShader(name);
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
case 'dev': {
|
|
330
|
+
const shaderName = args[1];
|
|
331
|
+
if (!shaderName) {
|
|
332
|
+
console.error('Error: Specify a shader name');
|
|
333
|
+
console.error(' shader dev <shader-name>');
|
|
334
|
+
console.error(' shader list');
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const cwd = process.cwd();
|
|
339
|
+
const shaderPath = path.join(cwd, 'shaders', shaderName);
|
|
340
|
+
if (!fs.existsSync(shaderPath)) {
|
|
341
|
+
console.error(`Error: Shader "${shaderName}" not found`);
|
|
342
|
+
console.error('Run "shader list" to see available shaders');
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log(`Starting dev server for "${shaderName}"...`);
|
|
347
|
+
runVite([], shaderName);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
case 'build': {
|
|
352
|
+
const shaderName = args[1];
|
|
353
|
+
if (!shaderName) {
|
|
354
|
+
console.error('Error: Specify a shader name');
|
|
355
|
+
console.error(' shader build <shader-name>');
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const cwd = process.cwd();
|
|
360
|
+
const shaderPath = path.join(cwd, 'shaders', shaderName);
|
|
361
|
+
if (!fs.existsSync(shaderPath)) {
|
|
362
|
+
console.error(`Error: Shader "${shaderName}" not found`);
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
console.log(`Building "${shaderName}"...`);
|
|
367
|
+
runVite(['build'], shaderName);
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
case 'list':
|
|
372
|
+
listShaders(process.cwd());
|
|
373
|
+
break;
|
|
374
|
+
|
|
375
|
+
case 'help':
|
|
376
|
+
case '--help':
|
|
377
|
+
case '-h':
|
|
378
|
+
printUsage();
|
|
379
|
+
break;
|
|
380
|
+
|
|
381
|
+
case undefined:
|
|
382
|
+
printUsage();
|
|
383
|
+
break;
|
|
384
|
+
|
|
385
|
+
default:
|
|
386
|
+
console.error(`Unknown command: ${command}`);
|
|
387
|
+
printUsage();
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Layer - Browser Runtime Coordinator
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Create and manage canvas
|
|
6
|
+
* - Initialize ShadertoyEngine
|
|
7
|
+
* - Run animation loop (requestAnimationFrame)
|
|
8
|
+
* - Handle resize and mouse events
|
|
9
|
+
* - Present Image pass output to screen
|
|
10
|
+
*/
|
|
11
|
+
import './app.css';
|
|
12
|
+
import { ShadertoyEngine } from '../engine/ShadertoyEngine';
|
|
13
|
+
import { AppOptions } from './types';
|
|
14
|
+
export declare class App {
|
|
15
|
+
private container;
|
|
16
|
+
private canvas;
|
|
17
|
+
private gl;
|
|
18
|
+
private engine;
|
|
19
|
+
private project;
|
|
20
|
+
private pixelRatio;
|
|
21
|
+
private animationId;
|
|
22
|
+
private startTime;
|
|
23
|
+
private mouse;
|
|
24
|
+
private fpsDisplay;
|
|
25
|
+
private frameCount;
|
|
26
|
+
private lastFpsUpdate;
|
|
27
|
+
private currentFps;
|
|
28
|
+
private controlsContainer;
|
|
29
|
+
private playPauseButton;
|
|
30
|
+
private isPaused;
|
|
31
|
+
private errorOverlay;
|
|
32
|
+
private resizeObserver;
|
|
33
|
+
private intersectionObserver;
|
|
34
|
+
private isVisible;
|
|
35
|
+
constructor(opts: AppOptions);
|
|
36
|
+
/**
|
|
37
|
+
* Check if there were any shader compilation errors.
|
|
38
|
+
* Returns true if the engine has errors and should not be started.
|
|
39
|
+
*/
|
|
40
|
+
hasErrors(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Get the underlying engine instance.
|
|
43
|
+
* Used for live recompilation in editor mode.
|
|
44
|
+
*/
|
|
45
|
+
getEngine(): ShadertoyEngine;
|
|
46
|
+
/**
|
|
47
|
+
* Start the animation loop.
|
|
48
|
+
*/
|
|
49
|
+
start(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Stop the animation loop.
|
|
52
|
+
*/
|
|
53
|
+
stop(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Clean up all resources.
|
|
56
|
+
*/
|
|
57
|
+
dispose(): void;
|
|
58
|
+
private animate;
|
|
59
|
+
/**
|
|
60
|
+
* Update FPS counter.
|
|
61
|
+
* Updates the display roughly once per second.
|
|
62
|
+
*/
|
|
63
|
+
private updateFps;
|
|
64
|
+
/**
|
|
65
|
+
* Present the Image pass output to the screen.
|
|
66
|
+
*
|
|
67
|
+
* Since Image is the final pass and we execute all passes to their FBOs,
|
|
68
|
+
* we need to blit the Image pass output to the default framebuffer.
|
|
69
|
+
*/
|
|
70
|
+
private presentToScreen;
|
|
71
|
+
private updateCanvasSize;
|
|
72
|
+
private setupMouseTracking;
|
|
73
|
+
/**
|
|
74
|
+
* Create playback control buttons (play/pause and reset).
|
|
75
|
+
*/
|
|
76
|
+
private createControls;
|
|
77
|
+
/**
|
|
78
|
+
* Set up keyboard tracking for shader keyboard texture.
|
|
79
|
+
* Tracks all key presses/releases and forwards to engine.
|
|
80
|
+
*/
|
|
81
|
+
private setupKeyboardTracking;
|
|
82
|
+
/**
|
|
83
|
+
* Set up global keyboard shortcuts (always available).
|
|
84
|
+
*/
|
|
85
|
+
private setupGlobalShortcuts;
|
|
86
|
+
/**
|
|
87
|
+
* Set up keyboard shortcuts for playback control.
|
|
88
|
+
*/
|
|
89
|
+
private setupKeyboardShortcuts;
|
|
90
|
+
/**
|
|
91
|
+
* Toggle between play and pause states.
|
|
92
|
+
*/
|
|
93
|
+
private togglePlayPause;
|
|
94
|
+
/**
|
|
95
|
+
* Reset the shader to frame 0.
|
|
96
|
+
*/
|
|
97
|
+
private reset;
|
|
98
|
+
/**
|
|
99
|
+
* Capture and download a screenshot of the current canvas as PNG.
|
|
100
|
+
* Filename format: shadertoy-{folderName}-{timestamp}.png
|
|
101
|
+
*/
|
|
102
|
+
private screenshot;
|
|
103
|
+
/**
|
|
104
|
+
* Update play/pause button icon based on current state.
|
|
105
|
+
*/
|
|
106
|
+
private updatePlayPauseButton;
|
|
107
|
+
/**
|
|
108
|
+
* Display shader compilation errors in an overlay.
|
|
109
|
+
*/
|
|
110
|
+
private showErrorOverlay;
|
|
111
|
+
/**
|
|
112
|
+
* Parse and improve WebGL shader error messages.
|
|
113
|
+
*/
|
|
114
|
+
private parseShaderError;
|
|
115
|
+
/**
|
|
116
|
+
* Extract code context around error line (±3 lines).
|
|
117
|
+
* Returns HTML with the error line highlighted.
|
|
118
|
+
*/
|
|
119
|
+
private extractCodeContext;
|
|
120
|
+
/**
|
|
121
|
+
* Extract code context from common.glsl file.
|
|
122
|
+
* Similar to extractCodeContext but uses the original common source.
|
|
123
|
+
*/
|
|
124
|
+
private extractCodeContextFromCommon;
|
|
125
|
+
/**
|
|
126
|
+
* Escape HTML to prevent XSS.
|
|
127
|
+
*/
|
|
128
|
+
private escapeHTML;
|
|
129
|
+
/**
|
|
130
|
+
* Hide the error overlay.
|
|
131
|
+
*/
|
|
132
|
+
private hideErrorOverlay;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=App.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/app/App.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,WAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAc,MAAM,SAAS,CAAC;AAEjD,qBAAa,GAAG;IACd,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAmB;IAElC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,SAAS,CAAa;IAG9B,OAAO,CAAC,KAAK,CAA8B;IAG3C,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAa;IAG/B,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAkB;IAGlC,OAAO,CAAC,YAAY,CAA4B;IAGhD,OAAO,CAAC,cAAc,CAAiB;IAGvC,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,SAAS,CAAiB;gBAEtB,IAAI,EAAE,UAAU;IA4F5B;;;OAGG;IACH,SAAS,IAAI,OAAO;IAIpB;;;OAGG;IACH,SAAS,IAAI,eAAe;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;OAEG;IACH,IAAI,IAAI,IAAI;IAOZ;;OAEG;IACH,OAAO,IAAI,IAAI;IAaf,OAAO,CAAC,OAAO,CAuBb;IAEF;;;OAGG;IACH,OAAO,CAAC,SAAS;IAYjB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAkCvB,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACH,OAAO,CAAC,cAAc;IA+CtB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,OAAO,CAAC,KAAK;IAOb;;;OAGG;IACH,OAAO,CAAC,UAAU;IAoClB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwB7B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA8ExB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAgC1B;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;OAEG;IACH,OAAO,CAAC,UAAU;IAMlB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAMzB"}
|