fragment-tools 0.1.13 → 0.1.14

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 (52) hide show
  1. package/bin/index.js +2 -2
  2. package/package.json +4 -5
  3. package/src/cli/log.js +31 -21
  4. package/src/cli/plugins/check-dependencies.js +47 -30
  5. package/src/cli/plugins/hot-shader-replacement.js +384 -0
  6. package/src/cli/plugins/hot-sketch-reload.js +3 -13
  7. package/src/cli/plugins/screenshot.js +57 -20
  8. package/src/cli/server.js +144 -133
  9. package/src/client/app/App.svelte +3 -3
  10. package/src/client/app/client.js +55 -39
  11. package/src/client/app/components/Init.svelte +12 -9
  12. package/src/client/app/helpers.js +42 -0
  13. package/src/client/app/hooks.js +20 -0
  14. package/src/client/app/inputs/Keyboard.js +13 -15
  15. package/src/client/app/inputs/MIDI.js +14 -15
  16. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +41 -21
  17. package/src/client/app/lib/gl/Renderer.js +127 -139
  18. package/src/client/app/modules/Exports.svelte +62 -43
  19. package/src/client/app/modules/MidiPanel.svelte +100 -101
  20. package/src/client/app/modules/Params.svelte +116 -103
  21. package/src/client/app/renderers/2DRenderer.js +3 -3
  22. package/src/client/app/renderers/FragmentRenderer.js +30 -23
  23. package/src/client/app/renderers/P5Renderer.js +10 -7
  24. package/src/client/app/renderers/THREERenderer.js +136 -94
  25. package/src/client/app/stores/exports.js +36 -20
  26. package/src/client/app/stores/props.js +28 -5
  27. package/src/client/app/stores/renderers.js +22 -15
  28. package/src/client/app/stores/sketches.js +7 -9
  29. package/src/client/app/stores/utils.js +95 -38
  30. package/src/client/app/triggers/Keyboard.js +88 -79
  31. package/src/client/app/triggers/MIDI.js +110 -84
  32. package/src/client/app/ui/Field.svelte +343 -240
  33. package/src/client/app/ui/FieldGroup.svelte +106 -94
  34. package/src/client/app/ui/FieldSection.svelte +125 -116
  35. package/src/client/app/ui/ParamsMultisampling.svelte +96 -95
  36. package/src/client/app/ui/ParamsOutput.svelte +113 -113
  37. package/src/client/app/ui/SelectChevrons.svelte +27 -15
  38. package/src/client/app/ui/SketchRenderer.svelte +761 -667
  39. package/src/client/app/ui/fields/ButtonInput.svelte +61 -48
  40. package/src/client/app/ui/fields/CheckboxInput.svelte +67 -61
  41. package/src/client/app/ui/fields/ColorInput.svelte +294 -238
  42. package/src/client/app/ui/fields/ImageInput.svelte +123 -121
  43. package/src/client/app/ui/fields/Input.svelte +100 -111
  44. package/src/client/app/ui/fields/ListInput.svelte +96 -96
  45. package/src/client/app/ui/fields/NumberInput.svelte +121 -116
  46. package/src/client/app/ui/fields/ProgressInput.svelte +80 -73
  47. package/src/client/app/ui/fields/Select.svelte +137 -124
  48. package/src/client/app/ui/fields/VectorInput.svelte +86 -82
  49. package/src/client/app/utils/canvas.utils.js +228 -201
  50. package/src/client/app/utils/file.utils.js +38 -34
  51. package/src/client/public/css/global.css +27 -21
  52. package/src/cli/plugins/hot-shader-reload.js +0 -86
package/bin/index.js CHANGED
@@ -4,14 +4,14 @@ import sade from 'sade';
4
4
  import { run } from '../src/cli/index.js';
5
5
 
6
6
  sade('fragment [entry]')
7
- .version('0.1.13')
7
+ .version('0.1.14')
8
8
  .describe('Run a dev environment for fragment')
9
9
  .option('-n, --new', 'Create file if it does not exist', false)
10
10
  .option('-t, --template', 'Specify template to create the file from', '2d')
11
11
  .option('-p, --port', 'Port to bind', 3000)
12
12
  .option('-dev, --development', 'Enable development mode', false)
13
13
  .option('-b, --build', 'Build sketch for production', false)
14
- .option('--exportDir', 'Directory used for exports', process.cwd())
14
+ .option('--exportDir', 'Directory used for exports')
15
15
  .option('--outDir', 'Directory used for static build', null)
16
16
  .option('--emptyOutDir', 'Empty outDir before static build', false)
17
17
  .action((entry, options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fragment-tools",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "A web development environment for creative coding",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -18,8 +18,7 @@
18
18
  },
19
19
  "homepage": "https://github.com/raphaelameaume/fragment#readme",
20
20
  "dependencies": {
21
- "@rollup/plugin-alias": "^3.1.5",
22
- "@sveltejs/vite-plugin-svelte": "^1.0.2",
21
+ "@sveltejs/vite-plugin-svelte": "^2.4.5",
23
22
  "body-parser": "^1.20.0",
24
23
  "changedpi": "^1.0.4",
25
24
  "chokidar": "^3.5.2",
@@ -29,9 +28,9 @@
29
28
  "glslify": "^7.1.1",
30
29
  "kleur": "^4.1.4",
31
30
  "sade": "^1.7.4",
32
- "svelte": "^3.49.0",
31
+ "svelte": "^4.0.0",
33
32
  "svelte-json-tree": "^1.0.0",
34
- "vite": "^3.0.9",
33
+ "vite": "^4.4.9",
35
34
  "webm-writer": "^1.0.0",
36
35
  "ws": "^8.2.3"
37
36
  }
package/src/cli/log.js CHANGED
@@ -1,26 +1,36 @@
1
- import kleur from "kleur";
1
+ import kleur from 'kleur';
2
2
 
3
3
  const log = (() => {
4
- let prefix = kleur.grey('[fragment]');
5
-
6
- const success = (message) => {
7
- console.log(prefix, kleur.green(`✔ ${message}`));
8
- };
9
-
10
- const warning = (message) => {
11
- console.log(prefix, kleur.yellow(`ℹ ${message}`));
12
- };
13
-
14
- const error = (message) => {
15
- console.log(prefix, kleur.red(`✖ ${message}`));
16
- };
17
-
18
- return {
19
- prefix,
20
- success,
21
- warning,
22
- error,
23
- };
4
+ let _prefix = createPrefix('fragment');
5
+
6
+ const success = (message, prefix = _prefix) => {
7
+ console.log(prefix, kleur.green(`✔ ${message}`));
8
+ };
9
+
10
+ const warning = (message, prefix = _prefix) => {
11
+ console.log(prefix, kleur.yellow(`ℹ ${message}`));
12
+ };
13
+
14
+ const error = (message, prefix = _prefix) => {
15
+ console.log(prefix, kleur.red(`✖ ${message}`));
16
+ };
17
+
18
+ const text = (message, prefix = _prefix) => {
19
+ console.log(prefix, message);
20
+ };
21
+
22
+ function createPrefix(prefix) {
23
+ return kleur.grey(`[${prefix}]`);
24
+ }
25
+
26
+ return {
27
+ prefix: _prefix,
28
+ createPrefix,
29
+ success,
30
+ warning,
31
+ error,
32
+ text,
33
+ };
24
34
  })();
25
35
 
26
36
  export default log;
@@ -1,36 +1,45 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import log from "../log.js";
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import log from '../log.js';
4
4
 
5
- export default function checkDependencies({ cwd, app, entriesPaths, build } = {}) {
6
- const regex = /\bexport[\s]*\b(let|const)[\s]*\brendering\b[\s]*=[\s]*["'](.*?)["']/;
5
+ export default function checkDependencies({
6
+ cwd,
7
+ app,
8
+ entriesPaths,
9
+ build,
10
+ } = {}) {
11
+ const regex =
12
+ /\bexport[\s]*\b(let|const)[\s]*\brendering\b[\s]*=[\s]*["'](.*?)["']/;
7
13
 
8
- const dependenciesMap = new Map();
9
- dependenciesMap.set("three", ["three"]);
10
- dependenciesMap.set("p5", ["p5"]);
11
- dependenciesMap.set("fragment", []);
12
- dependenciesMap.set("2d", []);
14
+ const dependenciesMap = new Map();
15
+ dependenciesMap.set('three', ['three']);
16
+ dependenciesMap.set('p5', ['p5']);
17
+ dependenciesMap.set('fragment', []);
18
+ dependenciesMap.set('2d', []);
13
19
 
14
20
  const renderers = new Map();
15
- renderers.set("three", `${app}/renderers/THREERenderer.js`);
16
- renderers.set("p5", `${app}/renderers/P5Renderer.js`);
17
- renderers.set("ogl", `${app}/renderers/OGLRenderer.js`);
18
- renderers.set("fragment", `${app}/renderers/FragmentRenderer.js`);
19
- renderers.set("2d", `${app}/renderers/2DRenderer.js`);
21
+ renderers.set('three', `${app}/renderers/THREERenderer.js`);
22
+ renderers.set('p5', `${app}/renderers/P5Renderer.js`);
23
+ renderers.set('ogl', `${app}/renderers/OGLRenderer.js`);
24
+ renderers.set('fragment', `${app}/renderers/FragmentRenderer.js`);
25
+ renderers.set('2d', `${app}/renderers/2DRenderer.js`);
20
26
 
21
27
  const renderings = [];
22
28
 
23
29
  entriesPaths.forEach((entry) => {
24
- const content = fs.readFileSync(entry, { encoding: "utf-8" });
25
- const match = content.match(regex);
30
+ const content = fs.readFileSync(entry, { encoding: 'utf-8' });
31
+ const match = content.match(regex);
26
32
  const rendering = match && match[2];
27
33
 
28
- if (rendering) {
34
+ if (rendering && dependenciesMap.has(rendering)) {
29
35
  renderings.push(rendering);
30
36
 
31
37
  const dependencies = dependenciesMap.get(rendering);
32
38
  dependencies.forEach((dependency) => {
33
- const dependencyPath = path.join(cwd, `node_modules/${dependency}`);
39
+ const dependencyPath = path.join(
40
+ cwd,
41
+ `node_modules/${dependency}`,
42
+ );
34
43
  const isInstalled = fs.existsSync(dependencyPath);
35
44
 
36
45
  if (!isInstalled) {
@@ -40,7 +49,7 @@ export default function checkDependencies({ cwd, app, entriesPaths, build } = {}
40
49
  console.log(`
41
50
  It looks like you're trying to build a ${dependency} sketch (${filename}) without having ${dependency} installed.
42
51
  Run 'npm install ${dependency}' before starting Fragment to run ${filename}.
43
- `)
52
+ `);
44
53
 
45
54
  throw new Error(error);
46
55
  }
@@ -58,20 +67,28 @@ Run 'npm install ${dependency}' before starting Fragment to run ${filename}.
58
67
  })
59
68
  .flat();
60
69
 
61
- return {
62
- name: 'check-dependencies',
70
+ return {
71
+ name: 'check-dependencies',
63
72
  config: () => ({
64
73
  define: {
65
- '__THREE_RENDERER__': build ? renderings.some((rendering) => rendering === "three") : true,
66
- '__P5_RENDERER__': build ? renderings.some((rendering) => rendering === "p5") : true,
67
- '__FRAGMENT_RENDERER__': build ? renderings.some((rendering) => rendering === "fragment") : true,
68
- '__2D_RENDERER__': build ? renderings.some((rendering) => rendering === "2d") : true,
74
+ __THREE_RENDERER__: build
75
+ ? renderings.some((rendering) => rendering === 'three')
76
+ : true,
77
+ __P5_RENDERER__: build
78
+ ? renderings.some((rendering) => rendering === 'p5')
79
+ : true,
80
+ __FRAGMENT_RENDERER__: build
81
+ ? renderings.some((rendering) => rendering === 'fragment')
82
+ : true,
83
+ __2D_RENDERER__: build
84
+ ? renderings.some((rendering) => rendering === '2d')
85
+ : true,
69
86
  },
70
87
  }),
71
- load(id) {
88
+ load(id) {
72
89
  if (build && skipFiles.includes(id)) {
73
- return { code: "", map: null };
90
+ return { code: '', map: null };
74
91
  }
75
- },
76
- };
92
+ },
93
+ };
77
94
  }
@@ -0,0 +1,384 @@
1
+ import { posix, sep, resolve, dirname, extname, relative } from 'path';
2
+ import { readFileSync } from 'fs';
3
+ import glslify from 'glslify';
4
+ import log from '../log.js';
5
+ import { readFile } from 'fs/promises';
6
+ import kleur from 'kleur';
7
+
8
+ /**
9
+ * @typedef {Object} ShaderUpdate
10
+ * @property {string} filepath - The path of the shader on the filesystem
11
+ * @property {string} source - The source code of the shader
12
+ * @property {boolean} nohsr - Whether the shader can be injected on the fly or if the sketch needs to be fully reloaded
13
+ * @property {string[]} warnings - Indicates whether the Wisdom component is present.
14
+ */
15
+
16
+ export default function hotShaderReplacement({ cwd, wss, watch = false }) {
17
+ const name = 'fragment-plugin-hsr';
18
+ const prefix = log.createPrefix(name);
19
+ const fileRegex = /\.(?:frag|vert|glsl|vs|fs)$/;
20
+ const includeRegex = /#include(\s+([^\s<>]+));?/gi;
21
+ const ignoreRegex = /^(?:\/|\*)*\s*@fragment-nohsr/;
22
+ const commentRegex =
23
+ /(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(\/\/.*)/gi;
24
+ const base = process.cwd().split(sep).join(posix.sep);
25
+
26
+ let dependencies = new Map();
27
+ let shaders = [];
28
+ let modulesToReload = [];
29
+
30
+ function reloadSketch() {
31
+ const clone = [...modulesToReload];
32
+
33
+ modulesToReload = [];
34
+
35
+ if (clone.length > 0) {
36
+ const { file } = clone[0];
37
+ const filepath = relative(cwd, file);
38
+ console.log(
39
+ `${log.prefix} ${kleur.green(`hmr update`)} /${filepath}`,
40
+ );
41
+
42
+ server.ws.send({
43
+ type: 'custom',
44
+ event: 'sketch-update',
45
+ data: {
46
+ file,
47
+ filepath,
48
+ cwd,
49
+ },
50
+ });
51
+ }
52
+
53
+ return clone;
54
+ }
55
+
56
+ function addShaderFilepath(shaderSource, shaderPath) {
57
+ let keyword = `void main`;
58
+ let shaderParts = shaderSource.split(keyword);
59
+ let hint = `// <filepath://${shaderPath}>`;
60
+
61
+ return `${shaderParts[0]}
62
+ ${hint}
63
+ ${keyword}${shaderParts[1]}
64
+ `;
65
+ }
66
+
67
+ function getUnixPath(shaderPath) {
68
+ return shaderPath.split(sep).join(posix.sep);
69
+ }
70
+
71
+ function compileGLSL(shaderSource, shaderPath) {
72
+ // test if shader source contains hint to avoid shader injection
73
+ const nohsr = ignoreRegex.test(shaderSource);
74
+
75
+ // remove current shader from dependency list before resolving dependencies again
76
+ dependencies.forEach((shadersPaths, dependency) => {
77
+ const shadersList = shadersPaths.filter((p) => p !== shaderPath);
78
+ dependencies.set(dependency, shadersList);
79
+ });
80
+
81
+ // if a dependency no longer have any parent shader, we can remove it from the watch
82
+ dependencies.forEach((shadersPaths, dependency) => {
83
+ if (shadersPaths.length === 0) {
84
+ if (server) {
85
+ server.watcher.unwatch(dependency);
86
+ }
87
+
88
+ dependencies.delete(dependency);
89
+ }
90
+ });
91
+
92
+ /**
93
+ *
94
+ * @param {string} parentSource
95
+ * @param {string} parentPath
96
+ * @param {string[]} deps
97
+ * @returns {}
98
+ */
99
+ function resolveDependencies(
100
+ parentSource,
101
+ parentPath,
102
+ deps = [],
103
+ warnings = [],
104
+ ) {
105
+ // remove comments
106
+ parentSource = parentSource.replace(commentRegex, '');
107
+
108
+ let parentUnixPath = getUnixPath(parentPath);
109
+ let directory = dirname(parentUnixPath);
110
+
111
+ if (includeRegex.test(parentSource)) {
112
+ const currentDirectory = directory;
113
+
114
+ parentSource = parentSource.replace(
115
+ includeRegex,
116
+ (_, include) => {
117
+ include = include.trim();
118
+ let chunkPath = include.replace(
119
+ /^(?:"|')?|(?:"|')?;?$/gi,
120
+ '',
121
+ );
122
+
123
+ if (!chunkPath.indexOf('/')) {
124
+ chunkPath = `${base}/${chunkPath}`;
125
+ }
126
+
127
+ const directoryIndex = chunkPath.lastIndexOf('/');
128
+ directory = currentDirectory;
129
+
130
+ if (directoryIndex !== -1) {
131
+ directory = resolve(
132
+ directory,
133
+ chunkPath.slice(0, directoryIndex + 1),
134
+ );
135
+ chunkPath = chunkPath.slice(
136
+ directoryIndex + 1,
137
+ chunkPath.length,
138
+ );
139
+ }
140
+
141
+ let chunkResolvedPath = resolve(directory, chunkPath);
142
+ let extension = 'glsl';
143
+
144
+ if (!extname(chunkResolvedPath))
145
+ chunkResolvedPath = `${chunkResolvedPath}.${extension}`;
146
+
147
+ const chunkUnixPath = getUnixPath(chunkResolvedPath);
148
+
149
+ if (!dependencies.has(chunkUnixPath)) {
150
+ // first time chunk is detected
151
+ dependencies.set(chunkUnixPath, []);
152
+
153
+ if (server) {
154
+ server.watcher.add(chunkResolvedPath);
155
+ }
156
+ }
157
+
158
+ const parents = dependencies.get(chunkUnixPath);
159
+
160
+ if (!parents.includes(shaderPath)) {
161
+ parents.push(shaderPath);
162
+ deps.push(chunkResolvedPath);
163
+ } else {
164
+ const message = `Dependency is already included in ${shaderPath}.\nInclude was skipped to avoid errors.`;
165
+
166
+ warnings.push({
167
+ type: 'duplicated dependency',
168
+ message,
169
+ importer: parentPath,
170
+ url: chunkResolvedPath,
171
+ location: {
172
+ lineText: `#include ${include}`,
173
+ },
174
+ });
175
+
176
+ return '';
177
+ }
178
+
179
+ const { code: chunkCode } = resolveDependencies(
180
+ readFileSync(chunkResolvedPath, 'utf8'),
181
+ chunkResolvedPath,
182
+ deps,
183
+ warnings,
184
+ );
185
+
186
+ const prefix = server ? `//#include ${include}\n` : ``;
187
+
188
+ return `${prefix}\n${chunkCode}`;
189
+ },
190
+ );
191
+ }
192
+
193
+ return {
194
+ code: parentSource.trim().replace(/(\r\n|\r|\n){3,}/g, '$1\n'),
195
+ deps,
196
+ warnings,
197
+ };
198
+ }
199
+
200
+ let { code, deps, warnings } = resolveDependencies(
201
+ shaderSource,
202
+ shaderPath,
203
+ );
204
+
205
+ code = glslify(code, {
206
+ basedir: process.cwd(),
207
+ });
208
+
209
+ if (server) {
210
+ code = addShaderFilepath(code, shaderPath);
211
+ }
212
+
213
+ warnings.forEach((warning) => {
214
+ const { location } = warning;
215
+ const line = 1;
216
+ const column = 4;
217
+ log.text(
218
+ `${kleur.yellow(warning.type)} ${warning.importer}`,
219
+ prefix,
220
+ );
221
+ console.log();
222
+ console.log(` ${kleur.dim(location.lineText)}`);
223
+ console.log();
224
+ console.log(warning.message);
225
+ console.log();
226
+ });
227
+
228
+ return { code, deps, warnings, nohsr };
229
+ }
230
+
231
+ /**
232
+ * Reload shaders after changes via custom Websocket or Vite HMR (sketch reload)
233
+ * @param {ShaderUpdate[]} shaderUpdates
234
+ */
235
+ function reloadShaders(shaderUpdates) {
236
+ const shadersNeedReload = shaderUpdates.filter(
237
+ (shaderUpdate) => shaderUpdate.nohsr,
238
+ );
239
+
240
+ if (shadersNeedReload.length > 0) {
241
+ shadersNeedReload.forEach((shaderUpdate) => {
242
+ log.text(
243
+ `${kleur.yellow('hsr ignore')} ${shaderUpdate.filepath}`,
244
+ prefix,
245
+ );
246
+ });
247
+
248
+ return reloadSketch();
249
+ } else {
250
+ shaderUpdates.forEach((shaderUpdate) => {
251
+ log.text(
252
+ `${kleur.green('hsr update')} ${shaderUpdate.filepath}`,
253
+ prefix,
254
+ );
255
+ });
256
+
257
+ wss.send({
258
+ type: 'custom',
259
+ event: 'shader-update',
260
+ data: shaderUpdates,
261
+ });
262
+
263
+ return [];
264
+ }
265
+ }
266
+
267
+ /** @type import('vite').ViteDevServer */
268
+ let server;
269
+
270
+ return {
271
+ name: 'fragment-plugin-hsr',
272
+ config: () => ({
273
+ optimizeDeps: {
274
+ esbuildOptions: {
275
+ loader: {
276
+ '.frag': 'text',
277
+ '.vert': 'text',
278
+ '.glsl': 'text',
279
+ '.fs': 'text',
280
+ '.vs': 'text',
281
+ },
282
+ },
283
+ },
284
+ }),
285
+ configureServer(_server) {
286
+ server = _server;
287
+ },
288
+ handleHotUpdate: async ({ modules, file, read }) => {
289
+ const { moduleGraph } = server;
290
+
291
+ if (fileRegex.test(file)) {
292
+ const thisModule = moduleGraph.getModuleById(file);
293
+
294
+ if (thisModule) {
295
+ modulesToReload.push(thisModule);
296
+ }
297
+
298
+ let unixPath = getUnixPath(file);
299
+ if (shaders.includes(file)) {
300
+ let source = await read();
301
+ let {
302
+ code: glsl,
303
+ warnings,
304
+ nohsr,
305
+ } = compileGLSL(source, file);
306
+
307
+ /** @type ShaderUpdate[] */
308
+ const shaderUpdate = {
309
+ filepath: unixPath,
310
+ source: glsl,
311
+ warnings,
312
+ nohsr,
313
+ };
314
+
315
+ return reloadShaders([shaderUpdate]);
316
+ } else {
317
+ if (dependencies.has(unixPath)) {
318
+ const shadersList = dependencies.get(unixPath);
319
+
320
+ // retrieve modules from module graph
321
+ const moduleNodes = shadersList.map((moduleNode) =>
322
+ moduleGraph.getModuleById(moduleNode),
323
+ );
324
+
325
+ // save it as modules to reload to invalidate the top level shaders in case a dependency has been hot updated in between
326
+ modulesToReload.push(...moduleNodes);
327
+
328
+ const sources = await Promise.all(
329
+ shadersList.map((shader) => {
330
+ return readFile(shader, 'utf-8');
331
+ }),
332
+ );
333
+
334
+ log.text(
335
+ `${kleur.yellow(`dependency update`)} ${unixPath}`,
336
+ prefix,
337
+ );
338
+
339
+ /** @type ShaderUpdate[] */
340
+ const shaderUpdates = shadersList.map(
341
+ (shader, index) => {
342
+ let source = sources[index];
343
+ let {
344
+ code: glsl,
345
+ warnings,
346
+ nohsr,
347
+ } = compileGLSL(source, shader);
348
+
349
+ return {
350
+ filepath: shader,
351
+ source: glsl,
352
+ warnings: warnings,
353
+ nohsr,
354
+ };
355
+ },
356
+ );
357
+
358
+ return reloadShaders(shaderUpdates);
359
+ }
360
+ }
361
+
362
+ return [];
363
+ } else if (modulesToReload.length > 0) {
364
+ // only return if some shaders have been updated in between
365
+ // otherwise, returning an empty array would prevent hmr on sketch files
366
+ return reloadSketch();
367
+ }
368
+ },
369
+ transform(source, file) {
370
+ if (!fileRegex.test(file)) return;
371
+
372
+ if (!shaders.includes(file)) {
373
+ shaders.push(file);
374
+ }
375
+
376
+ let { code: glsl } = compileGLSL(source, file);
377
+
378
+ return {
379
+ code: `export default ${JSON.stringify(glsl)}`,
380
+ map: null, // provide source map if available
381
+ };
382
+ },
383
+ };
384
+ }
@@ -3,10 +3,11 @@ import kleur from "kleur";
3
3
  import log from "../log.js";
4
4
 
5
5
  export default function hotSketchReload({ cwd }) {
6
+ const shaderRegex = /\.(?:frag|vert|glsl|vs|fs)$/;
6
7
  return {
7
8
  name: 'hot-sketch-reload',
8
9
  handleHotUpdate: async ({ server, modules, file, read }) => {
9
- if (file.includes(cwd)) {
10
+ if (file.includes(cwd) && !shaderRegex.test(file)) {
10
11
  const filepath = path.relative(cwd, file);
11
12
  console.log(`${log.prefix} ${kleur.green(`hmr update`)} /${filepath}`);
12
13
 
@@ -23,17 +24,6 @@ export default function hotSketchReload({ cwd }) {
23
24
  }
24
25
 
25
26
  return modules;
26
- },
27
- // transform: (src, id) => {
28
- // if (fileRegex.test(id)) {
29
- // let source = glslify(src);
30
- // source = addShaderFilepath(source, id);
31
-
32
- // return {
33
- // code: `export default ${JSON.stringify(source)}`,
34
- // map: null // provide source map if available
35
- // }
36
- // }
37
- // }
27
+ }
38
28
  };
39
29
  }