fragment-tools 0.1.13 → 0.1.15

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 (184) hide show
  1. package/.prettierignore +1 -2
  2. package/.prettierrc +23 -7
  3. package/README.md +28 -9
  4. package/bin/index.js +70 -10
  5. package/package.json +14 -6
  6. package/src/cli/build.js +125 -0
  7. package/src/cli/create.js +238 -0
  8. package/src/cli/createConfig.js +82 -0
  9. package/src/cli/createFragmentFile.js +70 -0
  10. package/src/cli/getEntries.js +85 -0
  11. package/src/cli/log.js +36 -24
  12. package/src/cli/plugins/check-dependencies.js +88 -42
  13. package/src/cli/plugins/hot-shader-replacement.js +408 -0
  14. package/src/cli/plugins/hot-sketch-reload.js +21 -25
  15. package/src/cli/plugins/save.js +101 -0
  16. package/src/cli/preview.js +55 -0
  17. package/src/cli/prompts.js +260 -0
  18. package/src/cli/run.js +131 -0
  19. package/src/cli/templates/blank/index.js +33 -0
  20. package/src/cli/templates/blank/meta.json +4 -0
  21. package/src/cli/templates/default/index.js +39 -0
  22. package/src/cli/templates/default/meta.json +5 -0
  23. package/src/cli/templates/fragment-gl/index.js +37 -0
  24. package/src/cli/templates/fragment-gl/meta.json +4 -0
  25. package/src/cli/templates/p5/index.js +32 -0
  26. package/src/cli/templates/p5/meta.json +5 -0
  27. package/src/cli/templates/p5-webgl/fragment.fs +14 -0
  28. package/src/cli/templates/p5-webgl/index.js +67 -0
  29. package/src/cli/templates/p5-webgl/meta.json +5 -0
  30. package/src/cli/templates/three-fragment/fragment.fs +10 -0
  31. package/src/cli/templates/three-fragment/index.js +95 -0
  32. package/src/cli/templates/three-fragment/meta.json +5 -0
  33. package/src/cli/templates/three-orthographic/index.js +55 -0
  34. package/src/cli/templates/three-orthographic/meta.json +5 -0
  35. package/src/cli/templates/three-perspective/index.js +52 -0
  36. package/src/cli/templates/three-perspective/meta.json +5 -0
  37. package/src/cli/utils.js +70 -0
  38. package/src/cli/ws.js +87 -78
  39. package/src/client/app/App.svelte +3 -3
  40. package/src/client/app/client.js +55 -39
  41. package/src/client/app/components/IconCross.svelte +18 -18
  42. package/src/client/app/components/Init.svelte +40 -8
  43. package/src/client/app/components/KeyBinding.svelte +22 -22
  44. package/src/client/app/helpers.js +42 -0
  45. package/src/client/app/hooks.js +20 -0
  46. package/src/client/app/inputs/Input.js +9 -9
  47. package/src/client/app/inputs/Keyboard.js +13 -15
  48. package/src/client/app/inputs/MIDI.js +14 -15
  49. package/src/client/app/inputs/Mouse.js +1 -1
  50. package/src/client/app/inputs/Webcam.js +89 -88
  51. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +41 -21
  52. package/src/client/app/lib/canvas-recorder/FrameRecorder.js +7 -6
  53. package/src/client/app/lib/canvas-recorder/H264Recorder.js +45 -0
  54. package/src/client/app/lib/canvas-recorder/MP4Recorder.js +7 -9
  55. package/src/client/app/lib/canvas-recorder/WebMRecorder.js +3 -4
  56. package/src/client/app/lib/canvas-recorder/mp4.js +1649 -15
  57. package/src/client/app/lib/canvas-recorder/utils.js +33 -17
  58. package/src/client/app/lib/gl/Geometry.js +11 -8
  59. package/src/client/app/lib/gl/Program.js +38 -19
  60. package/src/client/app/lib/gl/Renderer.js +163 -156
  61. package/src/client/app/lib/gl/Texture.js +113 -85
  62. package/src/client/app/lib/gl/index.js +12 -12
  63. package/src/client/app/lib/gl/utils.js +1 -3
  64. package/src/client/app/lib/helpers/frameDebounce.js +30 -30
  65. package/src/client/app/lib/loader/index.js +10 -10
  66. package/src/client/app/lib/loader/loadImage.js +15 -15
  67. package/src/client/app/lib/loader/loadScript.js +1 -1
  68. package/src/client/app/lib/paper-sizes.js +75 -76
  69. package/src/client/app/lib/presets.js +25 -5
  70. package/src/client/app/lib/tempo/Analyser.js +18 -17
  71. package/src/client/app/lib/tempo/Range.js +15 -12
  72. package/src/client/app/lib/tempo/index.js +34 -27
  73. package/src/client/app/modules/AudioAnalyser/Range.svelte +69 -72
  74. package/src/client/app/modules/AudioAnalyser/Spectrum.svelte +20 -19
  75. package/src/client/app/modules/AudioAnalyser.svelte +52 -35
  76. package/src/client/app/modules/Console/ConsoleLine.svelte +193 -172
  77. package/src/client/app/modules/Console.svelte +76 -74
  78. package/src/client/app/modules/Exports.svelte +62 -43
  79. package/src/client/app/modules/MidiPanel.svelte +100 -101
  80. package/src/client/app/modules/Monitor.svelte +57 -57
  81. package/src/client/app/modules/Params.svelte +128 -103
  82. package/src/client/app/renderers/2DRenderer.js +3 -3
  83. package/src/client/app/renderers/FragmentRenderer.js +30 -23
  84. package/src/client/app/renderers/P5GLRenderer.js +144 -0
  85. package/src/client/app/renderers/P5Renderer.js +10 -7
  86. package/src/client/app/renderers/THREERenderer.js +136 -94
  87. package/src/client/app/stores/audioAnalysis.js +3 -4
  88. package/src/client/app/stores/console.js +9 -10
  89. package/src/client/app/stores/errors.js +1 -1
  90. package/src/client/app/stores/exports.js +36 -20
  91. package/src/client/app/stores/index.js +2 -2
  92. package/src/client/app/stores/layout.js +143 -138
  93. package/src/client/app/stores/multisampling.js +4 -4
  94. package/src/client/app/stores/props.js +76 -13
  95. package/src/client/app/stores/renderers.js +26 -15
  96. package/src/client/app/stores/rendering.js +108 -89
  97. package/src/client/app/stores/sketches.js +7 -9
  98. package/src/client/app/stores/time.js +18 -18
  99. package/src/client/app/stores/utils.js +95 -38
  100. package/src/client/app/transitions/fade.js +3 -3
  101. package/src/client/app/transitions/index.js +6 -7
  102. package/src/client/app/transitions/splitX.js +2 -2
  103. package/src/client/app/transitions/splitY.js +2 -2
  104. package/src/client/app/triggers/Keyboard.js +88 -79
  105. package/src/client/app/triggers/MIDI.js +110 -84
  106. package/src/client/app/triggers/Mouse.js +73 -65
  107. package/src/client/app/triggers/Trigger.js +59 -58
  108. package/src/client/app/triggers/index.js +7 -7
  109. package/src/client/app/triggers/shared.js +5 -5
  110. package/src/client/app/ui/Build.svelte +70 -71
  111. package/src/client/app/ui/ErrorOverlay.svelte +118 -104
  112. package/src/client/app/ui/Field.svelte +393 -258
  113. package/src/client/app/ui/FieldGroup.svelte +106 -94
  114. package/src/client/app/ui/FieldSection.svelte +127 -116
  115. package/src/client/app/ui/FieldSpace.svelte +29 -30
  116. package/src/client/app/ui/FieldTrigger.svelte +256 -244
  117. package/src/client/app/ui/FieldTriggers.svelte +46 -46
  118. package/src/client/app/ui/FloatingParams.svelte +29 -30
  119. package/src/client/app/ui/Layout.svelte +31 -32
  120. package/src/client/app/ui/LayoutColumn.svelte +4 -4
  121. package/src/client/app/ui/LayoutComponent.svelte +239 -225
  122. package/src/client/app/ui/LayoutResizer.svelte +195 -176
  123. package/src/client/app/ui/LayoutRoot.svelte +6 -6
  124. package/src/client/app/ui/LayoutRow.svelte +4 -4
  125. package/src/client/app/ui/LayoutToolbar.svelte +191 -194
  126. package/src/client/app/ui/Module.svelte +134 -135
  127. package/src/client/app/ui/ModuleHeaderAction.svelte +81 -78
  128. package/src/client/app/ui/ModuleHeaderButton.svelte +12 -12
  129. package/src/client/app/ui/ModuleHeaderSelect.svelte +47 -37
  130. package/src/client/app/ui/ModuleRenderer.svelte +26 -27
  131. package/src/client/app/ui/OutputRenderer.svelte +112 -105
  132. package/src/client/app/ui/ParamsMultisampling.svelte +96 -95
  133. package/src/client/app/ui/ParamsOutput.svelte +130 -113
  134. package/src/client/app/ui/Preview.svelte +7 -8
  135. package/src/client/app/ui/SelectChevrons.svelte +27 -15
  136. package/src/client/app/ui/SketchRenderer.svelte +780 -667
  137. package/src/client/app/ui/SketchSelect.svelte +50 -44
  138. package/src/client/app/ui/fields/ButtonInput.svelte +61 -48
  139. package/src/client/app/ui/fields/CheckboxInput.svelte +67 -61
  140. package/src/client/app/ui/fields/ColorInput.svelte +294 -238
  141. package/src/client/app/ui/fields/FieldInputRow.svelte +8 -8
  142. package/src/client/app/ui/fields/ImageInput.svelte +123 -121
  143. package/src/client/app/ui/fields/Input.svelte +100 -111
  144. package/src/client/app/ui/fields/IntervalInput.svelte +268 -0
  145. package/src/client/app/ui/fields/ListInput.svelte +96 -96
  146. package/src/client/app/ui/fields/NumberInput.svelte +120 -116
  147. package/src/client/app/ui/fields/ProgressInput.svelte +99 -73
  148. package/src/client/app/ui/fields/Select.svelte +137 -124
  149. package/src/client/app/ui/fields/TextInput.svelte +10 -11
  150. package/src/client/app/ui/fields/VectorInput.svelte +86 -82
  151. package/src/client/app/utils/canvas.utils.js +189 -208
  152. package/src/client/app/utils/color.utils.js +138 -101
  153. package/src/client/app/utils/fields.utils.js +131 -0
  154. package/src/client/app/utils/file.utils.js +209 -37
  155. package/src/client/app/utils/glsl.utils.js +2 -2
  156. package/src/client/app/utils/glslErrors.js +49 -31
  157. package/src/client/app/utils/index.js +32 -29
  158. package/src/client/app/utils/math.utils.js +14 -10
  159. package/src/client/index.html +16 -16
  160. package/src/client/main.js +4 -4
  161. package/src/client/public/css/global.css +26 -16
  162. package/src/cli/db.js +0 -17
  163. package/src/cli/index.js +0 -198
  164. package/src/cli/plugins/db.js +0 -12
  165. package/src/cli/plugins/hot-shader-reload.js +0 -86
  166. package/src/cli/plugins/screenshot.js +0 -46
  167. package/src/cli/server.js +0 -153
  168. package/src/cli/templates/2d.js +0 -15
  169. package/src/cli/templates/blank.js +0 -13
  170. package/src/cli/templates/fragment.js +0 -18
  171. package/src/cli/templates/index.js +0 -27
  172. package/src/cli/templates/p5.js +0 -13
  173. package/src/cli/templates/three-fragment.js +0 -53
  174. package/src/cli/templates/three-orthographic.js +0 -23
  175. package/src/cli/templates/three-perspective.js +0 -20
  176. package/src/client/app/lib/canvas-recorder/FFMPEGRecorder.js +0 -56
  177. package/src/client/app/utils/props.utils.js +0 -51
  178. package/src/client/public/fonts/Inter-Bold.woff2 +0 -0
  179. package/src/client/public/fonts/Inter-Italic.woff2 +0 -0
  180. package/src/client/public/fonts/Inter-Regular.woff2 +0 -0
  181. package/src/client/public/fonts/Inter-SemiBold.woff2 +0 -0
  182. package/src/client/public/js/ffmpeg.min.js +0 -2
  183. package/src/client/public/js/ffmpeg.min.js.map +0 -1
  184. /package/src/cli/templates/{fragment.fs → fragment-gl/fragment.fs} +0 -0
@@ -1,17 +1,17 @@
1
1
  export const FORMATS = {
2
- HEX_STRING: "hex-string",
3
- RGB_STRING: "rgb-string",
4
- RGBA_STRING: "rgba-string",
5
- HSL_STRING: "hsl-string",
6
- HSLA_STRING: "hsla-string",
7
- RGB_OBJECT: "rgb-object",
8
- RGBA_OBJECT: "rgba-object",
9
- VEC3_STRING: "vec3-string",
10
- VEC4_STRING: "vec4-string",
11
- VEC3_ARRAY: "vec3-array",
12
- VEC4_ARRAY: "vec4-array",
13
- THREE: "three",
14
- CSS_COLOR: "css-color",
2
+ HEX_STRING: 'hex-string',
3
+ RGB_STRING: 'rgb-string',
4
+ RGBA_STRING: 'rgba-string',
5
+ HSL_STRING: 'hsl-string',
6
+ HSLA_STRING: 'hsla-string',
7
+ RGB_OBJECT: 'rgb-object',
8
+ RGBA_OBJECT: 'rgba-object',
9
+ VEC3_STRING: 'vec3-string',
10
+ VEC4_STRING: 'vec4-string',
11
+ VEC3_ARRAY: 'vec3-array',
12
+ VEC4_ARRAY: 'vec4-array',
13
+ THREE: 'three',
14
+ CSS_COLOR: 'css-color',
15
15
  };
16
16
 
17
17
  export function toHex(color, format = getColorFormat(color)) {
@@ -21,11 +21,16 @@ export function toHex(color, format = getColorFormat(color)) {
21
21
 
22
22
  if (format === FORMATS.THREE) return threeToHex(color);
23
23
  if (format === FORMATS.HEX_STRING) return color;
24
- if (format === FORMATS.HSL_STRING || format === FORMATS.HSLA_STRING) return hslToHex(color);
25
- if (format === FORMATS.RGB_STRING || format === FORMATS.RGBA_STRING) return stringToHex(color);
26
- if (format === FORMATS.RGB_OBJECT || format === FORMATS.RGBA_OBJECT) return componentsToHex([color.r, color.g, color.b, color.a]);
27
- if (format === FORMATS.VEC3_STRING || format === FORMATS.VEC4_STRING) return vecStringToHex(color);
28
- if (format === FORMATS.VEC3_ARRAY || format === FORMATS.VEC4_ARRAY) return vecArrayToHex(color);
24
+ if (format === FORMATS.HSL_STRING || format === FORMATS.HSLA_STRING)
25
+ return hslToHex(color);
26
+ if (format === FORMATS.RGB_STRING || format === FORMATS.RGBA_STRING)
27
+ return stringToHex(color);
28
+ if (format === FORMATS.RGB_OBJECT || format === FORMATS.RGBA_OBJECT)
29
+ return componentsToHex([color.r, color.g, color.b, color.a]);
30
+ if (format === FORMATS.VEC3_STRING || format === FORMATS.VEC4_STRING)
31
+ return vecStringToHex(color);
32
+ if (format === FORMATS.VEC3_ARRAY || format === FORMATS.VEC4_ARRAY)
33
+ return vecArrayToHex(color);
29
34
  if (format === FORMATS.CSS_COLOR) return nameToHex(color);
30
35
  }
31
36
 
@@ -36,10 +41,14 @@ export function toComponents(color, format = getColorFormat(color)) {
36
41
 
37
42
  if (format === FORMATS.THREE) return [color.r, color.g, color.b, 1];
38
43
  if (format === FORMATS.HEX_STRING) return hexToComponents(color);
39
- if (format === FORMATS.HSL_STRING || format === FORMATS.HSLA_STRING) return hslToComponents(color);
40
- if (format === FORMATS.RGB_STRING || format === FORMATS.RGBA_STRING) return stringToComponents(color);
41
- if (format === FORMATS.RGB_OBJECT || format === FORMATS.RGBA_OBJECT) return [color.r, color.g, color.b, isFinite(color.a) ? color.a : 1];
42
- if (format === FORMATS.VEC3_STRING || format === FORMATS.VEC4_STRING) return vecStringToComponents(color);
44
+ if (format === FORMATS.HSL_STRING || format === FORMATS.HSLA_STRING)
45
+ return hslToComponents(color);
46
+ if (format === FORMATS.RGB_STRING || format === FORMATS.RGBA_STRING)
47
+ return stringToComponents(color);
48
+ if (format === FORMATS.RGB_OBJECT || format === FORMATS.RGBA_OBJECT)
49
+ return [color.r, color.g, color.b, isFinite(color.a) ? color.a : 1];
50
+ if (format === FORMATS.VEC3_STRING || format === FORMATS.VEC4_STRING)
51
+ return vecStringToComponents(color);
43
52
  if (format === FORMATS.CSS_COLOR) return nameToComponents(color);
44
53
  }
45
54
 
@@ -57,20 +66,30 @@ export function toString(color, format = getColorFormat(color)) {
57
66
  format === FORMATS.VEC3_STRING ||
58
67
  format === FORMATS.VEC4_STRING ||
59
68
  format === FORMATS.CSS_COLOR
60
- ) return color;
61
- if (format === FORMATS.VEC3_ARRAY) return componentsToRGBString(vecArrayToComponents(color));
62
- if (format === FORMATS.VEC4_ARRAY) return componentsToRGBAString(vecArrayToComponents(color));
69
+ )
70
+ return color;
71
+ if (format === FORMATS.VEC3_ARRAY)
72
+ return componentsToRGBString(vecArrayToComponents(color));
73
+ if (format === FORMATS.VEC4_ARRAY)
74
+ return componentsToRGBAString(vecArrayToComponents(color));
63
75
  if (format === FORMATS.THREE) return threeToHex(color);
64
- if (format === FORMATS.RGB_OBJECT) return componentsToRGBString([color.r, color.g, color.b])
65
- if (format === FORMATS.RGBA_OBJECT) return componentsToRGBAString([color.r, color.g, color.b, color.a ? color.a : 1]);
76
+ if (format === FORMATS.RGB_OBJECT)
77
+ return componentsToRGBString([color.r, color.g, color.b]);
78
+ if (format === FORMATS.RGBA_OBJECT)
79
+ return componentsToRGBAString([
80
+ color.r,
81
+ color.g,
82
+ color.b,
83
+ color.a ? color.a : 1,
84
+ ]);
66
85
  }
67
86
 
68
87
  /**
69
- *
70
- * @param {string} colorName
88
+ *
89
+ * @param {string} colorName
71
90
  */
72
- export function nameToComponents(colorName, element = "temp") {
73
- if (colorName.toLowerCase() === "transparent") return [0, 0, 0, 0];
91
+ export function nameToComponents(colorName, element = 'temp') {
92
+ if (colorName.toLowerCase() === 'transparent') return [0, 0, 0, 0];
74
93
 
75
94
  let temp = document.createElement(element);
76
95
  document.body.appendChild(temp);
@@ -102,19 +121,22 @@ export function nameToHex(color) {
102
121
  }
103
122
 
104
123
  /**
105
- *
124
+ *
106
125
  * @param {string} value
107
126
  * @return {array}
108
127
  */
109
128
  export function stringToComponents(color) {
110
- const match = color.match(/rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d*(?:\.?\d*?))\))?/);
129
+ const match = color.match(
130
+ /rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d*(?:\.?\d*?))\))?/,
131
+ );
111
132
 
112
133
  if (match) {
113
134
  return [
114
135
  parseInt(match[1]) / 255,
115
136
  parseInt(match[2]) / 255,
116
137
  parseInt(match[3]) / 255,
117
- match[4] ? Number(match[4]) : 1];
138
+ match[4] ? Number(match[4]) : 1,
139
+ ];
118
140
  }
119
141
 
120
142
  return [];
@@ -125,14 +147,17 @@ export function stringToHex(color) {
125
147
  }
126
148
 
127
149
  export function vecStringToComponents(color) {
128
- const match = color.match(/vec[3-4]?\((\d*(?:\.\d*?)), ?(\d*(?:\.\d*?)), ?(\d*(?:\.\d*))?(?:, ?(\d*(?:\.?\d*?))\))?/);
150
+ const match = color.match(
151
+ /vec[3-4]?\((\d*(?:\.\d*?)), ?(\d*(?:\.\d*?)), ?(\d*(?:\.\d*))?(?:, ?(\d*(?:\.?\d*?))\))?/,
152
+ );
129
153
 
130
154
  if (match) {
131
155
  return [
132
156
  Math.min(1, Math.max(Number(match[1]), 0)),
133
157
  Math.min(1, Math.max(Number(match[2]), 0)),
134
158
  Math.min(1, Math.max(Number(match[3]), 0)),
135
- match[4] ? Math.min(1, Math.max(Number(match[4]), 0)) : 1];
159
+ match[4] ? Math.min(1, Math.max(Number(match[4]), 0)) : 1,
160
+ ];
136
161
  }
137
162
 
138
163
  console.error(`color.vecStringToComponents :: cannot parse color`, color);
@@ -143,12 +168,7 @@ export function vecStringToComponents(color) {
143
168
  export function vecArrayToComponents(color) {
144
169
  if (color.every((c) => isFinite(c))) {
145
170
  const [r, g, b, a = 1] = color;
146
- return [
147
- r,
148
- g,
149
- b,
150
- a
151
- ];
171
+ return [r, g, b, a];
152
172
  }
153
173
 
154
174
  console.error(`color.vecArrayToComponents :: cannot parse color`, color);
@@ -165,12 +185,12 @@ export function vecArrayToHex(color) {
165
185
  }
166
186
 
167
187
  // https://stackoverflow.com/questions/39118528/rgb-to-hsl-conversion
168
- export function rgbTohsl(r,g,b) {
169
-
170
- }
188
+ export function rgbTohsl(r, g, b) {}
171
189
 
172
190
  export function hslToHSLComponents(color) {
173
- const match = color.match(/hsla?\((\d{1,3}),?[\s]?(\d{1,3})\%,?[\s]?(\d{1,3})\%\)?(?:,?[\s]?(\d*(?:\.?\d*?))\))?/);
191
+ const match = color.match(
192
+ /hsla?\((\d{1,3}),?[\s]?(\d{1,3})\%,?[\s]?(\d{1,3})\%\)?(?:,?[\s]?(\d*(?:\.?\d*?))\))?/,
193
+ );
174
194
 
175
195
  if (match) {
176
196
  const h = Math.min(360, Math.max(Number(match[1]), 0));
@@ -198,7 +218,7 @@ export function hslToComponents(color) {
198
218
  l /= 100;
199
219
 
200
220
  function f(n) {
201
- let k = (n + h/30) % 12;
221
+ let k = (n + h / 30) % 12;
202
222
  let a = s * Math.min(l, 1 - l);
203
223
  return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
204
224
  }
@@ -208,10 +228,10 @@ export function hslToComponents(color) {
208
228
 
209
229
  export function hslToHex(color) {
210
230
  return componentsToHex(hslToComponents(color));
211
- };
231
+ }
212
232
 
213
233
  export function hexToComponents(color) {
214
- if (color.length < 7){
234
+ if (color.length < 7) {
215
235
  const R = color[1];
216
236
  const G = color[2];
217
237
  const B = color[3];
@@ -223,20 +243,20 @@ export function hexToComponents(color) {
223
243
  } else {
224
244
  color = `#${R}${R}${G}${G}${B}${B}`;
225
245
  }
226
- }
246
+ }
227
247
 
228
- return [
248
+ return [
229
249
  parseInt(color.substr(1, 2), 16) / 255,
230
- parseInt(color.substr(3, 2), 16) / 255,
250
+ parseInt(color.substr(3, 2), 16) / 255,
231
251
  parseInt(color.substr(5, 2), 16) / 255,
232
- color.length > 7 ? parseInt(color.substr(7, 2), 16)/255 : 1
252
+ color.length > 7 ? parseInt(color.substr(7, 2), 16) / 255 : 1,
233
253
  ];
234
254
  }
235
255
 
236
256
  /**
237
- * Convert a hexadecimal string to
238
- * @param {string} color
239
- * @returns
257
+ * Convert a hexadecimal string to
258
+ * @param {string} color
259
+ * @returns
240
260
  */
241
261
  export function hexToVec3String(color) {
242
262
  return componentsToVec3String(hexToComponents(color));
@@ -263,7 +283,7 @@ export function toVec4String(color) {
263
283
  }
264
284
 
265
285
  export function componentsToVec3String(components = []) {
266
- const [ r = 0, g = 0, b = 0] = components;
286
+ const [r = 0, g = 0, b = 0] = components;
267
287
 
268
288
  let rn = `${Math.round(r * 1000) / 1000}`;
269
289
  let gn = `${Math.round(g * 1000) / 1000}`;
@@ -285,7 +305,7 @@ export function componentsToVec3String(components = []) {
285
305
  }
286
306
 
287
307
  export function componentsToVec4String(components = []) {
288
- const [ r = 0, g = 0, b = 0, a = 1] = components;
308
+ const [r = 0, g = 0, b = 0, a = 1] = components;
289
309
 
290
310
  let rn = `${Math.round(r * 1000) / 1000}`;
291
311
  let gn = `${Math.round(g * 1000) / 1000}`;
@@ -330,13 +350,13 @@ export function hexToRGBAString(color) {
330
350
  }
331
351
 
332
352
  export function componentsToRGBString(components) {
333
- const [ r, g, b ] = components;
353
+ const [r, g, b] = components;
334
354
 
335
355
  return `rgb(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)})`;
336
356
  }
337
357
 
338
358
  export function componentsToRGBAString(components = []) {
339
- const [ r = 0, g = 0, b = 0, a = 1 ] = components;
359
+ const [r = 0, g = 0, b = 0, a = 1] = components;
340
360
 
341
361
  return `rgba(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}, ${a})`;
342
362
  }
@@ -345,16 +365,21 @@ export function componentsToHSLComponents(components = []) {
345
365
  let [r, g, b] = components;
346
366
  let max = Math.max(...components);
347
367
  let min = Math.min(...components);
348
- let [h, s, l] = [NaN, 0, (min + max)/2];
368
+ let [h, s, l] = [NaN, 0, (min + max) / 2];
349
369
  let d = max - min;
350
370
 
351
371
  if (d !== 0) {
352
- s = (l === 0 || l === 1) ? 0 : (max - l) / Math.min(l, 1 - l);
372
+ s = l === 0 || l === 1 ? 0 : (max - l) / Math.min(l, 1 - l);
353
373
 
354
374
  switch (max) {
355
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
356
- case g: h = (b - r) / d + 2; break;
357
- case b: h = (r - g) / d + 4;
375
+ case r:
376
+ h = (g - b) / d + (g < b ? 6 : 0);
377
+ break;
378
+ case g:
379
+ h = (b - r) / d + 2;
380
+ break;
381
+ case b:
382
+ h = (r - g) / d + 4;
358
383
  }
359
384
 
360
385
  h = h * 60;
@@ -368,25 +393,25 @@ export function componentsToHSLComponents(components = []) {
368
393
  }
369
394
 
370
395
  export function hslToHSLString(components) {
371
- const [ h = 0, s = 0, l = 0] = components;
396
+ const [h = 0, s = 0, l = 0] = components;
372
397
 
373
398
  return `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`;
374
399
  }
375
400
 
376
401
  export function hslaToHSLAString(components) {
377
- const [ h = 0, s = 0, l = 0, a = 1] = components;
402
+ const [h = 0, s = 0, l = 0, a = 1] = components;
378
403
 
379
404
  return `hsla(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%, ${a})`;
380
405
  }
381
406
 
382
407
  export function componentsToHSLString(components = []) {
383
- const [ r = 0, g = 0, b = 0, a = 1 ] = components;
408
+ const [r = 0, g = 0, b = 0, a = 1] = components;
384
409
  return hslToHSLString(componentsToHSLComponents([r, g, b]));
385
410
  }
386
411
 
387
412
  export function componentsToHSLAString(components = []) {
388
- const [ r = 0, g = 0, b = 0, a = 1 ] = components;
389
- const [ h, s, l] = componentsToHSLComponents([r, g, b]);
413
+ const [r = 0, g = 0, b = 0, a = 1] = components;
414
+ const [h, s, l] = componentsToHSLComponents([r, g, b]);
390
415
  return hslaToHSLAString([h, s, l, a]);
391
416
  }
392
417
 
@@ -395,76 +420,87 @@ export function componentToHex(c) {
395
420
  }
396
421
 
397
422
  export function componentsToHex(components = []) {
398
- const [ r = 0, g = 0, b = 0 ] = components;
423
+ const [r = 0, g = 0, b = 0] = components;
399
424
 
400
425
  let hex = [r, g, b]
401
426
  .map((c) => Math.round(c * 255))
402
- .map(c => {
403
- return c.toString(16).padStart(2, "0");
404
- }).join("");
427
+ .map((c) => {
428
+ return c.toString(16).padStart(2, '0');
429
+ })
430
+ .join('');
405
431
 
406
432
  return `#${hex}`;
407
433
  }
408
434
 
409
- export function isHexString(value, isString = typeof value === "string") {
435
+ export function isHexString(value, isString = typeof value === 'string') {
410
436
  return isString && /^#([a-f0-9]{3,4}){1,2}$/i.test(value);
411
437
  }
412
438
 
413
- export function isRGBAString(value, isString = typeof value === "string") {
414
- return isString && /rgba\((\d{1,3}),[\s]*(\d{1,3}),[\s]*(\d{1,3})\)?(?:,[\s]*(\d*(?:\.?\d*?))\))?/.test(value);
439
+ export function isRGBAString(value, isString = typeof value === 'string') {
440
+ return (
441
+ isString &&
442
+ /rgba\((\d{1,3}),[\s]*(\d{1,3}),[\s]*(\d{1,3})\)?(?:,[\s]*(\d*(?:\.?\d*?))\))?/.test(
443
+ value,
444
+ )
445
+ );
415
446
  }
416
447
 
417
- export function isRGBString(value, isString = typeof value === "string") {
418
- return isString && /rgb\((\d{1,3}),[\s]*(\d{1,3}),[\s]*(\d{1,3})\)/.test(value);
448
+ export function isRGBString(value, isString = typeof value === 'string') {
449
+ return (
450
+ isString && /rgb\((\d{1,3}),[\s]*(\d{1,3}),[\s]*(\d{1,3})\)/.test(value)
451
+ );
419
452
  }
420
453
 
421
- export function isHSLAString(value, isString = typeof value === "string") {
422
- return isString && value.includes("hsla");
454
+ export function isHSLAString(value, isString = typeof value === 'string') {
455
+ return isString && value.includes('hsla');
423
456
  }
424
457
 
425
- export function isHSLString(value, isString = typeof value === "string") {
426
- return isString && value.includes("hsl");
458
+ export function isHSLString(value, isString = typeof value === 'string') {
459
+ return isString && value.includes('hsl');
427
460
  }
428
461
 
429
- export function isVec3String(value, isString = typeof value === "string") {
430
- return isString && value.includes("vec3(");
462
+ export function isVec3String(value, isString = typeof value === 'string') {
463
+ return isString && value.includes('vec3(');
431
464
  }
432
465
 
433
- export function isVec4String(value, isString = typeof value === "string") {
434
- return isString && value.includes("vec4(");
466
+ export function isVec4String(value, isString = typeof value === 'string') {
467
+ return isString && value.includes('vec4(');
435
468
  }
436
469
 
437
470
  export function isRGBAObject(value) {
438
- if (typeof value === "object") {
471
+ if (typeof value === 'object') {
439
472
  const keys = Object.keys(value);
440
473
 
441
- return keys.length === 4 &&
474
+ return (
475
+ keys.length === 4 &&
442
476
  keys.includes('r') &&
443
477
  keys.includes('g') &&
444
478
  keys.includes('b') &&
445
- keys.includes('a');
479
+ keys.includes('a')
480
+ );
446
481
  }
447
482
 
448
483
  return false;
449
484
  }
450
485
 
451
486
  export function isRGBObject(value) {
452
- if (typeof value === "object") {
487
+ if (typeof value === 'object') {
453
488
  const keys = Object.keys(value);
454
489
 
455
- return keys.length === 3 &&
490
+ return (
491
+ keys.length === 3 &&
456
492
  keys.includes('r') &&
457
493
  keys.includes('g') &&
458
- keys.includes('b');
494
+ keys.includes('b')
495
+ );
459
496
  }
460
497
 
461
498
  return false;
462
499
  }
463
500
 
464
-
465
501
  export function isVec3Array(value) {
466
502
  if (Array.isArray(value)) {
467
- return value.length == 3 && value.every(c => c >= 0 && c <= 1);
503
+ return value.length == 3 && value.every((c) => c >= 0 && c <= 1);
468
504
  }
469
505
 
470
506
  return false;
@@ -472,13 +508,13 @@ export function isVec3Array(value) {
472
508
 
473
509
  export function isVec4Array(value) {
474
510
  if (Array.isArray(value)) {
475
- return value.length == 4 && value.every(c => c >= 0 && c <= 1);
511
+ return value.length == 4 && value.every((c) => c >= 0 && c <= 1);
476
512
  }
477
513
 
478
514
  return false;
479
515
  }
480
516
 
481
- export function isCSSColor(value, isString = typeof value === "string") {
517
+ export function isCSSColor(value, isString = typeof value === 'string') {
482
518
  const components = isString && nameToComponents(value);
483
519
 
484
520
  return components && components.length > 0;
@@ -490,14 +526,16 @@ export function isTHREE(value) {
490
526
 
491
527
  export function threeToHex(value) {
492
528
  if (!isTHREE(value)) {
493
- console.error(`color.threeToHex() : value is not an instance of THREE.Color`);
529
+ console.error(
530
+ `color.threeToHex() : value is not an instance of THREE.Color`,
531
+ );
494
532
  }
495
533
 
496
534
  return `#${value.getHexString()}`;
497
535
  }
498
536
 
499
537
  export function isColor(value) {
500
- let isString = typeof value === "string";
538
+ let isString = typeof value === 'string';
501
539
 
502
540
  if (isTHREE(value)) return true;
503
541
  if (isHexString(value, isString)) return true;
@@ -512,7 +550,6 @@ export function isColor(value) {
512
550
  return false;
513
551
  }
514
552
 
515
-
516
553
  export function getColorFormat(value) {
517
554
  if (isTHREE(value)) return FORMATS.THREE;
518
555
  if (isHexString(value)) return FORMATS.HEX_STRING;
@@ -527,4 +564,4 @@ export function getColorFormat(value) {
527
564
  if (isHSLAString(value)) return FORMATS.HSLA_STRING;
528
565
  if (isHSLString(value)) return FORMATS.HSL_STRING;
529
566
  if (isCSSColor(value)) return FORMATS.CSS_COLOR;
530
- };
567
+ }
@@ -0,0 +1,131 @@
1
+ import { isColor } from './color.utils';
2
+
3
+ export const fieldTypes = {
4
+ SELECT: 'select',
5
+ NUMBER: 'number',
6
+ VEC: 'vec',
7
+ CHECKBOX: 'checkbox',
8
+ TEXT: 'text',
9
+ LIST: 'list',
10
+ COLOR: 'color',
11
+ BUTTON: 'button',
12
+ DOWNLOAD: 'download',
13
+ IMAGE: 'image',
14
+ INTERVAL: 'interval',
15
+ };
16
+
17
+ /** @type string[] */
18
+ const types = Object.values(fieldTypes);
19
+
20
+ function isImageURL(url) {
21
+ return url.match(/\.(jpeg|jpg|gif|png|webp)$/) !== null;
22
+ }
23
+
24
+ function isImage(value) {
25
+ return typeof value === HTMLImageElement || isImageURL(value);
26
+ }
27
+
28
+ export function inferFieldType({ type, value, params, key }) {
29
+ if (type) {
30
+ if (types.includes(type)) {
31
+ return type;
32
+ }
33
+
34
+ console.warn(`Field: type ${type} is invalid for ${key}`);
35
+ } else if (params.options && Array.isArray(params.options)) {
36
+ return 'select';
37
+ } else {
38
+ if (value === undefined || value === null) {
39
+ console.warn(`Field: value ${value} for ${key}`);
40
+ return undefined;
41
+ }
42
+
43
+ const isArray = Array.isArray(value);
44
+ const isObject = !isArray && typeof value === 'object';
45
+ const values = isObject ? Object.values(value) : value;
46
+
47
+ if (
48
+ isArray &&
49
+ value.length === 2 &&
50
+ typeof params.min === 'number' &&
51
+ typeof params.max === 'number'
52
+ ) {
53
+ return fieldTypes.INTERVAL;
54
+ } else if (isColor(value)) {
55
+ return fieldTypes.COLOR;
56
+ } else if (typeof value === 'number') {
57
+ return fieldTypes.NUMBER;
58
+ } else if (typeof value === 'function') {
59
+ return fieldTypes.BUTTON;
60
+ } else if (typeof value === 'boolean') {
61
+ return fieldTypes.CHECKBOX;
62
+ } else if (typeof value === 'string') {
63
+ if (isImage(value)) {
64
+ return fieldTypes.IMAGE;
65
+ }
66
+
67
+ return fieldTypes.TEXT;
68
+ } else {
69
+ if (
70
+ (isArray || isObject) &&
71
+ values.every((v) => typeof v === 'number') &&
72
+ values.length <= 4
73
+ ) {
74
+ return fieldTypes.VEC;
75
+ }
76
+ }
77
+ }
78
+
79
+ console.warn(`Field: cannot find field type for ${key}`);
80
+ }
81
+
82
+ export function hasChanged(initialValue, currentValue) {
83
+ const initialType = typeof initialValue;
84
+ const currentType = typeof currentValue;
85
+
86
+ if (initialType !== currentType) return true;
87
+
88
+ if (Array.isArray(currentValue)) {
89
+ if (initialValue.length !== currentValue.length) {
90
+ return true;
91
+ }
92
+
93
+ for (let i = 0; i < currentValue.length; i++) {
94
+ if (currentValue[i] !== initialValue[i]) {
95
+ return true;
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+
101
+ if (initialType === 'object') {
102
+ const keys1 = Object.keys(initialValue);
103
+ const keys2 = Object.keys(currentValue);
104
+
105
+ if (
106
+ keys1.length !== keys2.length ||
107
+ !keys1.every((key) => keys2.includes(key))
108
+ ) {
109
+ return true;
110
+ }
111
+
112
+ for (const key of keys1) {
113
+ const value1 = initialValue[key];
114
+ const value2 = currentValue[key];
115
+
116
+ if (typeof value1 === 'object' && typeof value2 === 'object') {
117
+ // If both values are objects, recursively compare them
118
+ if (hasChanged(value1, value2)) {
119
+ return true;
120
+ }
121
+ } else if (value1 !== value2) {
122
+ // If values are not objects, directly compare them
123
+ return true;
124
+ }
125
+
126
+ return false;
127
+ }
128
+ }
129
+
130
+ return initialValue !== currentValue;
131
+ }