fragment-tools 0.1.19 → 0.2.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.
Files changed (102) hide show
  1. package/bin/index.js +1 -0
  2. package/package.json +5 -6
  3. package/src/cli/templates/three-fragment/index.js +6 -6
  4. package/src/cli/templates/three-orthographic/index.js +3 -3
  5. package/src/cli/templates/three-perspective/index.js +3 -3
  6. package/src/client/app/actions/resize.js +14 -0
  7. package/src/client/app/components/HintLoading.svelte +94 -0
  8. package/src/client/app/components/HintPaused.svelte +88 -0
  9. package/src/client/app/components/HintRecord.svelte +62 -0
  10. package/src/client/app/components/IconLocked.svelte +51 -0
  11. package/src/client/app/components/IconTriggers.svelte +48 -0
  12. package/src/client/app/components/Init.svelte +14 -27
  13. package/src/client/app/components/KeyBinding.svelte +3 -6
  14. package/src/client/app/helpers.js +4 -40
  15. package/src/client/app/hooks.js +41 -17
  16. package/src/client/app/inputs/MIDI.js +2 -1
  17. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +6 -1
  18. package/src/client/app/lib/gl/Renderer.js +1 -0
  19. package/src/client/app/lib/svelte-json-tree/ErrorNode.svelte +28 -0
  20. package/src/client/app/lib/svelte-json-tree/ErrorStack.svelte +31 -0
  21. package/src/client/app/lib/svelte-json-tree/Expandable.svelte +25 -0
  22. package/src/client/app/lib/svelte-json-tree/JSONArrayNode.svelte +38 -0
  23. package/src/client/app/lib/svelte-json-tree/JSONArrow.svelte +47 -0
  24. package/src/client/app/lib/svelte-json-tree/JSONFunctionNode.svelte +114 -0
  25. package/src/client/app/lib/svelte-json-tree/JSONIterableArrayNode.svelte +60 -0
  26. package/src/client/app/lib/svelte-json-tree/JSONIterableMapNode.svelte +87 -0
  27. package/src/client/app/lib/svelte-json-tree/JSONNested.svelte +94 -0
  28. package/src/client/app/lib/svelte-json-tree/JSONNode.svelte +91 -0
  29. package/src/client/app/lib/svelte-json-tree/JSONObjectNode.svelte +40 -0
  30. package/src/client/app/lib/svelte-json-tree/JSONStringNode.svelte +31 -0
  31. package/src/client/app/lib/svelte-json-tree/JSONValueNode.svelte +31 -0
  32. package/src/client/app/lib/svelte-json-tree/PreviewList.svelte +38 -0
  33. package/src/client/app/lib/svelte-json-tree/RegExpNode.svelte +42 -0
  34. package/src/client/app/lib/svelte-json-tree/Root.svelte +75 -0
  35. package/src/client/app/lib/svelte-json-tree/Summary.svelte +9 -0
  36. package/src/client/app/lib/svelte-json-tree/TypedArrayNode.svelte +56 -0
  37. package/src/client/app/lib/svelte-json-tree/index.js +1 -0
  38. package/src/client/app/lib/svelte-json-tree/utils.js +57 -0
  39. package/src/client/app/modules/Console/ConsoleLine.svelte +12 -11
  40. package/src/client/app/modules/Console.svelte +82 -17
  41. package/src/client/app/modules/Exports.svelte +48 -48
  42. package/src/client/app/modules/MidiPanel.svelte +12 -19
  43. package/src/client/app/modules/Monitor.svelte +147 -55
  44. package/src/client/app/modules/Params.svelte +127 -80
  45. package/src/client/app/renderers/2DRenderer.js +1 -0
  46. package/src/client/app/renderers/FragmentRenderer.js +1 -1
  47. package/src/client/app/renderers/P5GLRenderer.js +11 -5
  48. package/src/client/app/renderers/P5Renderer.js +7 -3
  49. package/src/client/app/renderers/THREERenderer.js +42 -79
  50. package/src/client/app/state/Sketch.svelte.js +538 -0
  51. package/src/client/app/state/errors.svelte.js +17 -0
  52. package/src/client/app/state/exports.svelte.js +152 -0
  53. package/src/client/app/state/layout.svelte.js +205 -0
  54. package/src/client/app/state/monitors.svelte.js +36 -0
  55. package/src/client/app/state/renderers.svelte.js +77 -0
  56. package/src/client/app/state/rendering.svelte.js +697 -0
  57. package/src/client/app/state/sketches.svelte.js +73 -0
  58. package/src/client/app/state/utils.svelte.js +65 -0
  59. package/src/client/app/ui/Build.svelte +53 -60
  60. package/src/client/app/ui/ErrorOverlay.svelte +2 -2
  61. package/src/client/app/ui/Field.svelte +63 -189
  62. package/src/client/app/ui/FieldGroup.svelte +4 -5
  63. package/src/client/app/ui/FieldSection.svelte +14 -9
  64. package/src/client/app/ui/FieldSpace.svelte +1 -1
  65. package/src/client/app/ui/FieldTrigger.svelte +86 -84
  66. package/src/client/app/ui/FieldTriggers.svelte +25 -24
  67. package/src/client/app/ui/FloatingParams.svelte +50 -12
  68. package/src/client/app/ui/Layout.svelte +24 -13
  69. package/src/client/app/ui/LayoutColumn.svelte +2 -2
  70. package/src/client/app/ui/LayoutComponent.svelte +86 -195
  71. package/src/client/app/ui/LayoutResizer.svelte +25 -37
  72. package/src/client/app/ui/LayoutRoot.svelte +3 -5
  73. package/src/client/app/ui/LayoutRow.svelte +2 -2
  74. package/src/client/app/ui/LayoutToolbar.svelte +17 -76
  75. package/src/client/app/ui/Module.svelte +31 -35
  76. package/src/client/app/ui/ModuleHeaderAction.svelte +23 -16
  77. package/src/client/app/ui/ModuleHeaderButton.svelte +3 -3
  78. package/src/client/app/ui/ModuleHeaderSelect.svelte +4 -12
  79. package/src/client/app/ui/ModuleRenderer.svelte +84 -22
  80. package/src/client/app/ui/ParamsOutput.svelte +61 -77
  81. package/src/client/app/ui/Preview.svelte +15 -4
  82. package/src/client/app/ui/SelectChevrons.svelte +1 -2
  83. package/src/client/app/ui/SketchRenderer.svelte +89 -701
  84. package/src/client/app/ui/SketchSelect.svelte +14 -49
  85. package/src/client/app/ui/fields/ButtonInput.svelte +14 -11
  86. package/src/client/app/ui/fields/CheckboxInput.svelte +5 -12
  87. package/src/client/app/ui/fields/ColorInput.svelte +46 -121
  88. package/src/client/app/ui/fields/FieldInputRow.svelte +5 -1
  89. package/src/client/app/ui/fields/ImageInput.svelte +14 -14
  90. package/src/client/app/ui/fields/Input.svelte +19 -25
  91. package/src/client/app/ui/fields/IntervalInput.svelte +22 -22
  92. package/src/client/app/ui/fields/NumberInput.svelte +32 -38
  93. package/src/client/app/ui/fields/ProgressInput.svelte +14 -13
  94. package/src/client/app/ui/fields/Select.svelte +34 -45
  95. package/src/client/app/ui/fields/TextInput.svelte +10 -6
  96. package/src/client/app/ui/fields/VectorInput.svelte +25 -30
  97. package/src/client/app/utils/canvas.utils.js +8 -8
  98. package/src/client/app/utils/color.utils.js +46 -13
  99. package/src/client/app/utils/fields.utils.js +1 -1
  100. package/src/client/app/utils/glsl.utils.js +1 -1
  101. package/src/client/app/utils/glslErrors.js +1 -1
  102. package/src/client/main.js +2 -2
@@ -1,103 +1,126 @@
1
- <script context="module">
2
- import { writable } from 'svelte/store';
3
-
4
- export const params = writable([]);
5
-
6
- let ID = 0;
7
- </script>
8
-
9
1
  <script>
10
- import { onMount, onDestroy } from 'svelte';
11
- import { sketches } from '../stores/sketches.js';
12
- import { monitors, rendering } from '../stores/rendering';
13
2
  import Module from '../ui/Module.svelte';
14
3
  import Field from '../ui/Field.svelte';
15
4
  import OutputParams from '../ui/ParamsOutput.svelte';
16
5
  import ModuleHeaderAction from '../ui/ModuleHeaderAction.svelte';
17
- import { updateProp, props } from '../stores/props';
6
+ import { rendering } from '../state/rendering.svelte.js';
7
+ import { layout } from '../state/layout.svelte';
8
+ import FieldGroup from '../ui/FieldGroup.svelte';
9
+ import { sketchesManager } from '../state/sketches.svelte';
18
10
 
19
- export let mID;
20
- export let hasHeader = true;
21
- export let output = true;
11
+ let {
12
+ id = layout.getID(),
13
+ headless = false,
14
+ output = true,
15
+ params = $bindable({}),
16
+ } = $props();
22
17
 
23
- let id = ID++;
24
- let selected = id;
25
- let sketch,
26
- sketchKey,
27
- sketchProps = {};
28
- let monitor, showOutputParams;
18
+ let key = $derived(sketchesManager.keys[0]);
19
+ let sketch = $derived(sketchesManager.sketches[key]);
20
+ let sketchProps = $derived(sketch?.props ?? {});
29
21
 
30
- onMount(() => {
31
- $params = [
32
- ...$params,
33
- {
34
- id,
35
- },
36
- ];
37
- });
22
+ let sketchPropsGroups = $derived(sketch?.propsGroups ?? []);
23
+ let framerate = $derived(
24
+ isFinite(sketch.fps) ? sketch.fps : rendering.refreshRate,
25
+ );
38
26
 
39
- onDestroy(() => {
40
- $params = $params.filter((p) => p.id !== id);
41
- });
27
+ let sketchGroupOptions = $derived(
28
+ [
29
+ { value: '', label: 'all ' },
30
+ sketchPropsGroups.length > 0 && output
31
+ ? { value: 'output', label: 'output' }
32
+ : undefined,
33
+ ...sketchPropsGroups.map((group) => ({
34
+ value: group,
35
+ label: group,
36
+ })),
37
+ ].filter((group) => group !== undefined),
38
+ );
39
+ let sketchPropGroup = $derived(
40
+ sketchGroupOptions
41
+ .map((opt) => opt.value)
42
+ .includes(params.sketchPropGroup)
43
+ ? params.sketchPropGroup
44
+ : sketchGroupOptions[0].value,
45
+ );
42
46
 
43
- $: options = [
44
- ...$monitors.map((monitor, index) => {
45
- return { value: index, label: `monitor ${index + 1}` };
46
- }),
47
- ...($params.length > 1 ? [{ value: 'output', label: 'output' }] : []),
48
- ];
47
+ let sketchPropsTree = $derived.by(() => {
48
+ const tree = [];
49
49
 
50
- monitors.subscribe((value) => {
51
- monitor = $monitors[Math.min(selected, $monitors.length - 1)];
52
- sketchKey = monitor ? monitor.selected : undefined;
53
- });
50
+ Object.keys(sketchProps).forEach((key) => {
51
+ const { folder, group } = sketchProps[key];
52
+
53
+ if (!sketchPropGroup || group === sketchPropGroup) {
54
+ if (folder) {
55
+ const fieldgroup = sketch?.propsFolders.find(
56
+ (f) => f.id === folder,
57
+ );
58
+
59
+ if (fieldgroup) {
60
+ const { depth, root } = fieldgroup;
54
61
 
55
- $: {
56
- sketch = $sketches[sketchKey];
57
- sketchProps = $props[sketchKey];
58
- }
62
+ if (depth === 0 && !tree.includes(fieldgroup)) {
63
+ tree.push(fieldgroup);
64
+ } else if (root && !tree.includes(root)) {
65
+ tree.push(root);
66
+ }
67
+ } else {
68
+ console.warn(
69
+ 'Prop cannot be render in undefined fielgroup',
70
+ );
71
+ }
72
+ } else {
73
+ tree.push({
74
+ type: 'field',
75
+ key,
76
+ });
77
+ }
78
+ }
79
+ });
59
80
 
60
- $: showOutputParams =
61
- (monitor && monitor.selected === 'output') ||
62
- $params.length === 1 ||
63
- selected === 'output';
81
+ return tree;
82
+ });
64
83
  </script>
65
84
 
66
- <Module {mID} {hasHeader} name={`Parameters`} slug="params">
67
- <div slot="header-right">
68
- {#if options.length > 1}
85
+ <Module {id} {headless} name={`Parameters`} slug="params">
86
+ {#snippet headerRight()}
87
+ {#if sketchGroupOptions.length > 1}
69
88
  <ModuleHeaderAction
70
- value={selected}
89
+ value={sketchPropGroup}
71
90
  permanent
72
91
  border
73
- on:change={(event) => (selected = event.detail)}
74
- {options}
92
+ onchange={(event) => {
93
+ params.sketchPropGroup = event.currentTarget.value;
94
+ }}
95
+ options={sketchGroupOptions}
75
96
  />
76
97
  {/if}
77
- </div>
78
- {#if showOutputParams && output}
98
+ {/snippet}
99
+ {#if (!sketchPropGroup || sketchPropGroup === 'output') && output}
79
100
  <OutputParams />
80
101
  {/if}
81
102
 
82
103
  {#if sketch}
83
- {#if typeof props === 'object'}
84
- {#if output}
85
- <Field
86
- key="framerate"
87
- value={isFinite(sketch.fps) ? sketch.fps : 60}
88
- disabled
89
- />
90
- {/if}
104
+ {#if !sketchPropGroup && output && sketch}
105
+ <Field
106
+ key="framerate"
107
+ value={framerate}
108
+ disabled
109
+ params={{
110
+ suffix: isFinite(sketch.fps) ? undefined : ' (native)',
111
+ }}
112
+ />
91
113
  {#if sketch.duration && sketch.duration > 0 && output}
92
114
  <Field
93
115
  key="duration"
94
116
  value={sketch.duration}
95
- params={{ suffix: 's' }}
117
+ params={{ suffix: 's', step: 0.1 }}
96
118
  disabled
97
119
  />
98
120
  {/if}
99
- {#each Object.keys(sketchProps) as key, index (key)}
100
- {@const sketchProp = sketchProps[key]}
121
+ {/if}
122
+ {#if typeof sketchProps === 'object'}
123
+ {#snippet sketchField(index, key, prop)}
101
124
  {@const {
102
125
  hidden,
103
126
  displayName,
@@ -105,12 +128,12 @@
105
128
  type,
106
129
  disabled,
107
130
  __initialValue: initialValue,
108
- } = sketchProp}
131
+ } = prop}
109
132
  {@const isDisabled =
110
133
  typeof disabled === 'function' ? disabled() : disabled}
111
- {#if typeof hidden === 'function' ? !hidden() : !hidden}
134
+ {#if !hidden}
112
135
  <Field
113
- context={sketchKey}
136
+ context={sketch.key}
114
137
  {key}
115
138
  {displayName}
116
139
  {value}
@@ -119,18 +142,42 @@
119
142
  {index}
120
143
  disabled={isDisabled}
121
144
  bind:params={sketchProps[key].params}
122
- on:click={() => {
123
- $props[sketchKey][key].value._refresh = true;
145
+ triggers={prop.triggers}
146
+ onclick={(event) => {
147
+ sketch.version++;
148
+ // value(event, sketch.params);
124
149
  }}
125
- on:change={(event) => {
126
- updateProp(sketchKey, key, event.detail, {
127
- width: $rendering.width,
128
- height: $rendering.height,
129
- pixelRatio: $rendering.pixelRatio,
130
- });
150
+ onchange={(v) => {
151
+ sketch.updateProp(key, v);
131
152
  }}
132
153
  />
133
154
  {/if}
155
+ {/snippet}
156
+ {#snippet sketchPropItem(index, item)}
157
+ {#if item.type === 'field'}
158
+ {@render sketchField(
159
+ index,
160
+ item.key,
161
+ sketchProps[item.key],
162
+ )}
163
+ {:else if item.type === 'fieldgroup'}
164
+ <FieldGroup
165
+ name={item.displayName}
166
+ collapsed={item.collapsed}
167
+ onchange={(collapsed) => {
168
+ sketch.updateFolder(item, collapsed);
169
+ }}
170
+ >
171
+ {#if item.children.length > 0}
172
+ {#each item.children as child, childIndex}
173
+ {@render sketchPropItem(childIndex, child)}
174
+ {/each}
175
+ {/if}
176
+ </FieldGroup>
177
+ {/if}
178
+ {/snippet}
179
+ {#each sketchPropsTree as sketchPropsTreeItem, index}
180
+ {@render sketchPropItem(index, sketchPropsTreeItem)}
134
181
  {/each}
135
182
  {/if}
136
183
  {/if}
@@ -15,6 +15,7 @@
15
15
  */
16
16
  export let onMountPreview = ({ canvas }) => {
17
17
  return {
18
+ canvas,
18
19
  context: canvas.getContext('2d'),
19
20
  };
20
21
  };
@@ -1,7 +1,7 @@
1
1
  import { fragment } from '../lib/gl';
2
2
  import { client } from '@fragment/client';
3
3
  import { getShaderPath } from '../utils/glsl.utils';
4
- import { clearError } from '../stores/errors';
4
+ import { clearError } from '../state/errors';
5
5
 
6
6
  let frags = [];
7
7
 
@@ -1,7 +1,7 @@
1
1
  import p5 from 'p5';
2
2
  import { client } from '@fragment/client';
3
3
  import { getShaderPath } from '../utils/glsl.utils';
4
- import { clearError } from '../stores/errors';
4
+ import { clearError } from '../state/errors.svelte';
5
5
 
6
6
  /**
7
7
  * @typedef {object} PreviewP5GLRenderer
@@ -66,7 +66,8 @@ export let onBeforeUpdatePreview = ({ id }) => {
66
66
 
67
67
  if (preview) {
68
68
  preview.rendered = false;
69
- preview.p.resetMatrix();
69
+
70
+ preview.p?.resetMatrix();
70
71
  }
71
72
  };
72
73
 
@@ -91,9 +92,13 @@ export let onAfterUpdatePreview = ({ id }) => {
91
92
  /**
92
93
  * @param {PreviewParamsP5GLRenderer} params
93
94
  */
94
- export let onResizePreview = ({ p, width, height, pixelRatio }) => {
95
- p.pixelDensity(pixelRatio);
96
- p.resizeCanvas(width, height, false);
95
+ export let onResizePreview = ({ id, width, height, pixelRatio }) => {
96
+ const preview = previews.find((p) => p.id === id);
97
+
98
+ if (preview) {
99
+ preview.p.pixelDensity(pixelRatio);
100
+ preview.p.resizeCanvas(width, height, false);
101
+ }
97
102
  };
98
103
 
99
104
  /**
@@ -180,6 +185,7 @@ if (import.meta.hot) {
180
185
 
181
186
  client.on('shader-update', (shaderUpdates) => {
182
187
  previews.forEach(({ p }) => {
188
+ console.log('clear error', p._renderer.GL.__uuid);
183
189
  clearError(p._renderer.GL.__uuid);
184
190
  });
185
191
 
@@ -30,9 +30,13 @@ export let onBeforeUpdatePreview = ({ id }) => {
30
30
  }
31
31
  };
32
32
 
33
- export let onResizePreview = ({ p, width, height, pixelRatio }) => {
34
- p.pixelDensity(pixelRatio);
35
- p.resizeCanvas(width, height, false);
33
+ export let onResizePreview = ({ id, width, height, pixelRatio }) => {
34
+ const preview = previews.find((p) => p.id === id);
35
+
36
+ if (preview) {
37
+ preview.p.pixelDensity(pixelRatio);
38
+ preview.p.resizeCanvas(width, height, false);
39
+ }
36
40
  };
37
41
 
38
42
  export let onDestroyPreview = ({ id }) => {
@@ -1,27 +1,12 @@
1
1
  import { WebGLRenderer, Scene } from 'three';
2
- import { Texture, fragment } from '@fragment/lib/gl';
3
2
  import { client } from '@fragment/client';
4
3
  import { getShaderPath } from '../utils/glsl.utils';
5
- import { clearError } from '../stores/errors';
4
+ import { clearError } from '../state/errors.svelte';
6
5
 
7
6
  let previews = [];
8
7
 
9
- /** @type {WebGLRenderer} */
10
- let renderer;
11
-
12
- let fragmentShader = /* glsl */ `
13
- precision highp float;
14
- uniform sampler2D uSampler;
15
- varying vec2 vUv;
16
-
17
- void main() {
18
- vec3 mapTexel = texture2D(uSampler, vUv).rgb;
19
- gl_FragColor = vec4(mapTexel, 1.);
20
- }
21
- `;
22
-
23
- export let init = ({ canvas }) => {
24
- renderer = new WebGLRenderer({ antialias: true });
8
+ export let onMountPreview = ({ id, canvas }) => {
9
+ let renderer = new WebGLRenderer({ antialias: true, canvas });
25
10
 
26
11
  const render = renderer.render;
27
12
 
@@ -31,41 +16,19 @@ export let init = ({ canvas }) => {
31
16
  render.call(renderer, scene, camera);
32
17
  };
33
18
 
34
- return {
35
- renderer,
36
- };
37
- };
38
-
39
- export let onMountPreview = ({ id, canvas, width, height, pixelRatio }) => {
40
- let { gl, render, resize, uniforms, destroy } = fragment({
41
- canvas,
42
- shader: fragmentShader,
43
- uniforms: {
44
- uSampler: { value: null, type: 'sampler2D' },
45
- },
46
- });
47
-
48
- let texture = new Texture(gl, {
49
- image: renderer.domElement,
50
- });
51
-
52
- uniforms.uSampler.value = texture;
53
-
54
19
  let scene = new Scene();
55
20
 
56
21
  previews.push({
57
22
  id,
58
23
  scene,
59
- texture,
60
- render,
61
- resize,
62
- destroy,
24
+ renderer,
63
25
  rendered: false,
64
26
  });
65
27
 
66
28
  return {
67
29
  scene,
68
30
  renderer,
31
+ canvas: renderer.domElement,
69
32
  };
70
33
  };
71
34
 
@@ -73,11 +36,10 @@ export let onDestroyPreview = ({ id }) => {
73
36
  const previewIndex = previews.findIndex((p) => p.id === id);
74
37
  const preview = previews[previewIndex];
75
38
 
76
- clearError(renderer.getContext().__uuid);
77
-
78
39
  if (preview) {
79
- preview.texture.destroy();
80
- preview.destroy();
40
+ const { renderer } = preview;
41
+ clearError(renderer.getContext().__uuid);
42
+ renderer.dispose();
81
43
  previews.splice(previewIndex, 1);
82
44
  }
83
45
  };
@@ -94,8 +56,6 @@ export let onAfterUpdatePreview = ({ id }) => {
94
56
  const preview = previews.find((p) => p.id === id);
95
57
 
96
58
  if (preview) {
97
- preview.texture.needsUpdate = true;
98
- preview.render();
99
59
  preview.rendered = true;
100
60
  }
101
61
 
@@ -107,16 +67,13 @@ export let onAfterUpdatePreview = ({ id }) => {
107
67
  }
108
68
  };
109
69
 
110
- export let resize = ({ width, height, pixelRatio }) => {
111
- renderer.setPixelRatio(pixelRatio);
112
- renderer.setSize(width, height);
113
- };
114
-
115
70
  export let onResizePreview = ({ id, width, height, pixelRatio }) => {
116
71
  const preview = previews.find((p) => p.id === id);
117
72
 
118
73
  if (preview) {
119
- preview.resize({ width, height, pixelRatio });
74
+ const { renderer } = preview;
75
+ renderer.setPixelRatio(pixelRatio);
76
+ renderer.setSize(width, height);
120
77
  }
121
78
  };
122
79
 
@@ -125,34 +82,38 @@ let _shaderUpdates = [];
125
82
 
126
83
  function handleHotShaderUpdate(scene) {
127
84
  if (_shaderUpdates.length > 0) {
85
+ const verifyMaterial = (material) => {
86
+ if (!material) return;
87
+
88
+ const { vertexShader = '', fragmentShader = '' } = material;
89
+
90
+ Object.keys({ vertexShader, fragmentShader }).forEach((key) => {
91
+ const shader = material[key];
92
+ const shaderPath = getShaderPath(shader);
93
+ const shaderUpdate = _shaderUpdates.find(
94
+ (shaderUpdate) => shaderUpdate.filepath === shaderPath,
95
+ );
96
+
97
+ if (shaderUpdate) {
98
+ console.log(
99
+ `[fragment-plugin-hsr] hsr update ${shaderPath.replace(
100
+ __CWD__,
101
+ '',
102
+ )}`,
103
+ );
104
+ material[key] = shaderUpdate.source;
105
+ material.needsUpdate = true;
106
+ }
107
+ });
108
+ };
128
109
  scene.traverse((child) => {
129
110
  if (child.material) {
130
111
  const { material } = child;
131
112
 
132
- if (material.isShaderMaterial || material.isRawShaderMaterial) {
133
- const { vertexShader, fragmentShader } = material;
134
-
135
- Object.keys({ vertexShader, fragmentShader }).forEach(
136
- (key) => {
137
- const shader = material[key];
138
- const shaderPath = getShaderPath(shader);
139
- const shaderUpdate = _shaderUpdates.find(
140
- (shaderUpdate) =>
141
- shaderUpdate.filepath === shaderPath,
142
- );
143
-
144
- if (shaderUpdate) {
145
- console.log(
146
- `[fragment-plugin-hsr] hsr update ${shaderPath.replace(
147
- __CWD__,
148
- '',
149
- )}`,
150
- );
151
- material[key] = shaderUpdate.source;
152
- material.needsUpdate = true;
153
- }
154
- },
155
- );
113
+ if (Array.isArray(material)) {
114
+ material.forEach((m) => verifyMaterial(m));
115
+ } else {
116
+ verifyMaterial(material);
156
117
  }
157
118
  }
158
119
  });
@@ -170,7 +131,9 @@ if (import.meta.hot) {
170
131
  }
171
132
 
172
133
  client.on('shader-update', (shaderUpdates) => {
173
- clearError(renderer.getContext().__uuid);
134
+ previews.forEach((preview) => {
135
+ clearError(preview.renderer.getContext().__uuid);
136
+ });
174
137
 
175
138
  _shaderUpdates = shaderUpdates;
176
139
  });