fragment-tools 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.
Files changed (192) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +101 -0
  3. package/bin/index.js +19 -0
  4. package/docs/README.md +18 -0
  5. package/docs/api/CLI.md +44 -0
  6. package/docs/api/renderers.md +80 -0
  7. package/docs/api/sketch.md +216 -0
  8. package/docs/api/triggers.md +101 -0
  9. package/docs/guide/about.md +16 -0
  10. package/docs/guide/exports.md +86 -0
  11. package/docs/guide/external-dependencies.md +22 -0
  12. package/docs/guide/getting-started.md +113 -0
  13. package/docs/guide/hot-shader-reloading.md +20 -0
  14. package/docs/guide/shortcuts.md +12 -0
  15. package/docs/guide/triggers.png +0 -0
  16. package/docs/guide/using-triggers.md +39 -0
  17. package/examples/cube-three.js +34 -0
  18. package/examples/ellipse-p5.js +26 -0
  19. package/examples/icon.fs +96 -0
  20. package/examples/icon.js +63 -0
  21. package/examples/icon.png +0 -0
  22. package/examples/icon.transparent.png +0 -0
  23. package/examples/package-lock.json +40 -0
  24. package/examples/package.json +15 -0
  25. package/examples/shape-2d.js +45 -0
  26. package/examples/shape-three.js +49 -0
  27. package/examples/shape-tree.fs +3 -0
  28. package/package.json +37 -0
  29. package/screenshot.png +0 -0
  30. package/src/cli/db.js +17 -0
  31. package/src/cli/index.js +198 -0
  32. package/src/cli/log.js +26 -0
  33. package/src/cli/plugins/check-dependencies.js +77 -0
  34. package/src/cli/plugins/db.js +12 -0
  35. package/src/cli/plugins/hot-shader-reload.js +86 -0
  36. package/src/cli/plugins/hot-sketch-reload.js +39 -0
  37. package/src/cli/plugins/screenshot.js +31 -0
  38. package/src/cli/server.js +140 -0
  39. package/src/cli/templates/2d.js +15 -0
  40. package/src/cli/templates/fragment.fs +10 -0
  41. package/src/cli/templates/fragment.js +18 -0
  42. package/src/cli/templates/index.js +24 -0
  43. package/src/cli/templates/p5.js +13 -0
  44. package/src/cli/templates/three-fragment.js +53 -0
  45. package/src/cli/templates/three-orthographic.js +23 -0
  46. package/src/cli/templates/three-perspective.js +20 -0
  47. package/src/cli/ws.js +92 -0
  48. package/src/client/app/App.svelte +8 -0
  49. package/src/client/app/client.js +68 -0
  50. package/src/client/app/components/IconCross.svelte +29 -0
  51. package/src/client/app/components/Init.svelte +13 -0
  52. package/src/client/app/components/KeyBinding.svelte +32 -0
  53. package/src/client/app/inputs/Input.js +15 -0
  54. package/src/client/app/inputs/Keyboard.js +21 -0
  55. package/src/client/app/inputs/MIDI.js +144 -0
  56. package/src/client/app/inputs/Mouse.js +5 -0
  57. package/src/client/app/inputs/Webcam.js +98 -0
  58. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +88 -0
  59. package/src/client/app/lib/canvas-recorder/FFMPEGRecorder.js +56 -0
  60. package/src/client/app/lib/canvas-recorder/FrameRecorder.js +40 -0
  61. package/src/client/app/lib/canvas-recorder/GIFRecorder.js +52 -0
  62. package/src/client/app/lib/canvas-recorder/MP4Recorder.js +46 -0
  63. package/src/client/app/lib/canvas-recorder/WebMRecorder.js +30 -0
  64. package/src/client/app/lib/canvas-recorder/mp4.js +20 -0
  65. package/src/client/app/lib/canvas-recorder/mp4.wasm +0 -0
  66. package/src/client/app/lib/canvas-recorder/utils.js +22 -0
  67. package/src/client/app/lib/gl/Geometry.js +39 -0
  68. package/src/client/app/lib/gl/Program.js +130 -0
  69. package/src/client/app/lib/gl/Renderer.js +148 -0
  70. package/src/client/app/lib/gl/Texture.js +114 -0
  71. package/src/client/app/lib/gl/index.js +109 -0
  72. package/src/client/app/lib/gl/utils.js +5 -0
  73. package/src/client/app/lib/helpers/frameDebounce.js +40 -0
  74. package/src/client/app/lib/loader/index.js +20 -0
  75. package/src/client/app/lib/loader/loadImage.js +19 -0
  76. package/src/client/app/lib/loader/loadScript.js +14 -0
  77. package/src/client/app/lib/paper-sizes.js +104 -0
  78. package/src/client/app/lib/presets.js +12 -0
  79. package/src/client/app/lib/tempo/Analyser.js +165 -0
  80. package/src/client/app/lib/tempo/Range.js +97 -0
  81. package/src/client/app/lib/tempo/index.js +138 -0
  82. package/src/client/app/modules/AudioAnalyser/Range.svelte +93 -0
  83. package/src/client/app/modules/AudioAnalyser/Spectrum.svelte +31 -0
  84. package/src/client/app/modules/AudioAnalyser.svelte +70 -0
  85. package/src/client/app/modules/Console/ConsoleLine.svelte +254 -0
  86. package/src/client/app/modules/Console.svelte +82 -0
  87. package/src/client/app/modules/Exports.svelte +105 -0
  88. package/src/client/app/modules/MidiPanel.svelte +106 -0
  89. package/src/client/app/modules/Monitor.svelte +62 -0
  90. package/src/client/app/modules/Params.svelte +112 -0
  91. package/src/client/app/renderers/2DRenderer.js +5 -0
  92. package/src/client/app/renderers/FragmentRenderer.js +62 -0
  93. package/src/client/app/renderers/OGLRenderer.js +0 -0
  94. package/src/client/app/renderers/P5Renderer.js +39 -0
  95. package/src/client/app/renderers/THREERenderer.js +128 -0
  96. package/src/client/app/stores/audioAnalysis.js +10 -0
  97. package/src/client/app/stores/console.js +76 -0
  98. package/src/client/app/stores/errors.js +25 -0
  99. package/src/client/app/stores/exports.js +28 -0
  100. package/src/client/app/stores/index.js +2 -0
  101. package/src/client/app/stores/layout.js +187 -0
  102. package/src/client/app/stores/multisampling.js +16 -0
  103. package/src/client/app/stores/props.js +44 -0
  104. package/src/client/app/stores/renderers.js +60 -0
  105. package/src/client/app/stores/rendering.js +111 -0
  106. package/src/client/app/stores/sketches.js +40 -0
  107. package/src/client/app/stores/time.js +27 -0
  108. package/src/client/app/stores/utils.js +66 -0
  109. package/src/client/app/transitions/fade.js +17 -0
  110. package/src/client/app/transitions/index.js +12 -0
  111. package/src/client/app/transitions/splitX.js +16 -0
  112. package/src/client/app/transitions/splitY.js +16 -0
  113. package/src/client/app/triggers/Keyboard.js +95 -0
  114. package/src/client/app/triggers/MIDI.js +122 -0
  115. package/src/client/app/triggers/Mouse.js +96 -0
  116. package/src/client/app/triggers/Trigger.js +71 -0
  117. package/src/client/app/triggers/index.js +19 -0
  118. package/src/client/app/triggers/shared.js +37 -0
  119. package/src/client/app/ui/Build.svelte +96 -0
  120. package/src/client/app/ui/ErrorOverlay.svelte +130 -0
  121. package/src/client/app/ui/Field.svelte +262 -0
  122. package/src/client/app/ui/FieldGroup.svelte +103 -0
  123. package/src/client/app/ui/FieldSection.svelte +123 -0
  124. package/src/client/app/ui/FieldSpace.svelte +37 -0
  125. package/src/client/app/ui/FieldTrigger.svelte +263 -0
  126. package/src/client/app/ui/FieldTriggers.svelte +58 -0
  127. package/src/client/app/ui/FloatingParams.svelte +49 -0
  128. package/src/client/app/ui/Layout.svelte +50 -0
  129. package/src/client/app/ui/LayoutColumn.svelte +9 -0
  130. package/src/client/app/ui/LayoutComponent.svelte +279 -0
  131. package/src/client/app/ui/LayoutResizer.svelte +218 -0
  132. package/src/client/app/ui/LayoutRoot.svelte +11 -0
  133. package/src/client/app/ui/LayoutRow.svelte +9 -0
  134. package/src/client/app/ui/LayoutToolbar.svelte +264 -0
  135. package/src/client/app/ui/Module.svelte +154 -0
  136. package/src/client/app/ui/ModuleHeaderAction.svelte +87 -0
  137. package/src/client/app/ui/ModuleHeaderButton.svelte +21 -0
  138. package/src/client/app/ui/ModuleHeaderSelect.svelte +50 -0
  139. package/src/client/app/ui/ModuleRenderer.svelte +38 -0
  140. package/src/client/app/ui/OutputRenderer.svelte +149 -0
  141. package/src/client/app/ui/ParamsMultisampling.svelte +109 -0
  142. package/src/client/app/ui/ParamsOutput.svelte +139 -0
  143. package/src/client/app/ui/Preview.svelte +15 -0
  144. package/src/client/app/ui/SelectChevrons.svelte +25 -0
  145. package/src/client/app/ui/SketchRenderer.svelte +672 -0
  146. package/src/client/app/ui/SketchSelect.svelte +49 -0
  147. package/src/client/app/ui/fields/ButtonInput.svelte +54 -0
  148. package/src/client/app/ui/fields/CheckboxInput.svelte +70 -0
  149. package/src/client/app/ui/fields/ColorInput.svelte +187 -0
  150. package/src/client/app/ui/fields/FieldInputRow.svelte +13 -0
  151. package/src/client/app/ui/fields/ImageInput.svelte +145 -0
  152. package/src/client/app/ui/fields/Input.svelte +120 -0
  153. package/src/client/app/ui/fields/ListInput.svelte +106 -0
  154. package/src/client/app/ui/fields/NumberInput.svelte +114 -0
  155. package/src/client/app/ui/fields/ProgressInput.svelte +90 -0
  156. package/src/client/app/ui/fields/Select.svelte +116 -0
  157. package/src/client/app/ui/fields/TextInput.svelte +18 -0
  158. package/src/client/app/ui/fields/Vec2Input.svelte +5 -0
  159. package/src/client/app/ui/fields/Vec3Input.svelte +6 -0
  160. package/src/client/app/ui/fields/VectorInput.svelte +102 -0
  161. package/src/client/app/utils/canvas.utils.js +229 -0
  162. package/src/client/app/utils/color.utils.js +427 -0
  163. package/src/client/app/utils/file.utils.js +77 -0
  164. package/src/client/app/utils/glsl.utils.js +14 -0
  165. package/src/client/app/utils/glslErrors.js +154 -0
  166. package/src/client/app/utils/index.js +39 -0
  167. package/src/client/app/utils/math.utils.js +23 -0
  168. package/src/client/app/utils/props.utils.js +53 -0
  169. package/src/client/index.html +18 -0
  170. package/src/client/main.js +9 -0
  171. package/src/client/public/css/global.css +115 -0
  172. package/src/client/public/favicon.ico +0 -0
  173. package/src/client/public/fonts/Inter-Bold.woff2 +0 -0
  174. package/src/client/public/fonts/Inter-Italic.woff2 +0 -0
  175. package/src/client/public/fonts/Inter-Regular.woff2 +0 -0
  176. package/src/client/public/fonts/Inter-SemiBold.woff2 +0 -0
  177. package/src/client/public/fonts/JetBrainsMono-Regular.woff2 +0 -0
  178. package/src/client/public/icons/chevron-bottom.svg +3 -0
  179. package/src/client/public/icons/chevron-right.svg +3 -0
  180. package/src/client/public/icons/chevron-top.svg +3 -0
  181. package/src/client/public/icons/columns-horizontal.svg +4 -0
  182. package/src/client/public/icons/columns-vertical.svg +4 -0
  183. package/src/client/public/icons/folder-plus.svg +6 -0
  184. package/src/client/public/icons/lock.svg +4 -0
  185. package/src/client/public/icons/picture-in-picture.svg +4 -0
  186. package/src/client/public/icons/trash.svg +5 -0
  187. package/src/client/public/icons/trigger.svg +8 -0
  188. package/src/client/public/icons/unlock.svg +4 -0
  189. package/src/client/public/js/ffmpeg.min.js +2 -0
  190. package/src/client/public/js/ffmpeg.min.js.map +1 -0
  191. package/src/client/public/js/gif.js +2 -0
  192. package/src/client/public/js/gif.worker.js +2 -0
@@ -0,0 +1,427 @@
1
+ /**
2
+ *
3
+ * @param {string} colorName
4
+ */
5
+ export function nameToComponents(colorName, element = "temp") {
6
+ if (colorName.toLowerCase() === "transparent") return [0, 0, 0, 0];
7
+
8
+ let temp = document.createElement(element);
9
+ document.body.appendChild(temp);
10
+
11
+ const removeChild = () => temp.parentNode.removeChild(temp);
12
+
13
+ let flag = 'rgb(1, 2, 3)';
14
+ temp.style.color = flag;
15
+ if (temp.style.color !== flag) {
16
+ removeChild();
17
+ return;
18
+ }
19
+ temp.style.color = colorName;
20
+
21
+ // parse failed
22
+ if (temp.style.color === flag || temp.style.color === '') {
23
+ removeChild();
24
+ return;
25
+ }
26
+
27
+ let color = getComputedStyle(temp).color;
28
+ removeChild();
29
+
30
+ return stringToComponents(color);
31
+ }
32
+
33
+ export function nameToHex(color) {
34
+ return componentsToHex(nameToComponents(color));
35
+ }
36
+
37
+ /**
38
+ *
39
+ * @param {string} value
40
+ * @return {array}
41
+ */
42
+ export function stringToComponents(color) {
43
+ const match = color.match(/rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d*(?:\.?\d*?))\))?/);
44
+
45
+ if (match) {
46
+ return [
47
+ parseInt(match[1]),
48
+ parseInt(match[2]),
49
+ parseInt(match[3]),
50
+ match[4] ? Number(match[4]) : 1];
51
+ }
52
+
53
+ return [];
54
+ }
55
+
56
+ export function stringToHex(color) {
57
+ return componentsToHex(stringToComponents(color));
58
+ }
59
+
60
+ export function vecToComponents(color) {
61
+ const match = color.match(/vec[3-4]?\((\d*(?:\.\d*?)), ?(\d*(?:\.\d*?)), ?(\d*(?:\.\d*))?(?:, ?(\d*(?:\.?\d*?))\))?/);
62
+
63
+ if (match) {
64
+ return [
65
+ Math.min(255, Math.max(Math.round(Number(match[1]) * 255), 0)),
66
+ Math.min(255, Math.max(Math.round(Number(match[2]) * 255), 0)),
67
+ Math.min(255, Math.max(Math.round(Number(match[3]) * 255), 0)),
68
+ match[4] ? Math.min(1, Math.max(Number(match[4]), 0)) : 1];
69
+ }
70
+
71
+ console.error(`color.vecToComponents :: cannot parse color`, color);
72
+
73
+ return [];
74
+ }
75
+
76
+ export function vecToHex(color) {
77
+ return componentsToHex(vecToComponents(color));
78
+ }
79
+
80
+ // https://stackoverflow.com/questions/39118528/rgb-to-hsl-conversion
81
+ export function rgbTohsl(r,g,b) {
82
+
83
+ }
84
+
85
+ export function hslToHSLComponents(color) {
86
+ const match = color.match(/hsla?\((\d{1,3}), ?(\d{1,3})\%, ?(\d{1,3})\%\)?(?:, ?(\d*(?:\.?\d*?))\))?/);
87
+
88
+ if (match) {
89
+ const h = Math.min(360, Math.max(Number(match[1]), 0));
90
+ const l = Math.min(100, Math.max(Number(match[2]), 0));
91
+ const s = Math.min(100, Math.max(Number(match[3]), 0));
92
+ const a = match[4] ? Math.min(1, Math.max(Number(match[4]), 0)) : 1;
93
+
94
+ return [h, s, l, a];
95
+ }
96
+
97
+ console.error(`color.hslToHSLComponents :: cannot parse color`, color);
98
+ return [];
99
+ }
100
+
101
+ export function hslToComponents(color) {
102
+ const [h, s, l, a] = hslToHSLComponents(color);
103
+
104
+ // monochromatic
105
+ if (s === 0) {
106
+ const tl = l / 100 * 255;
107
+
108
+ return [tl, tl, tl, a];
109
+ } else {
110
+ const hue2rgb = (p, q, t) => {
111
+ if (t < 0) t += 1;
112
+ if (t > 1) t -= 1;
113
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
114
+ if (t < 1 / 2) return q;
115
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
116
+ return p;
117
+ };
118
+
119
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
120
+ const p = 2 * l - q;
121
+
122
+ return [
123
+ hue2rgb(p, q, h + 1 / 3),
124
+ hue2rgb(p, q, h),
125
+ hue2rgb(p, q, h - 1 / 3),
126
+ a,
127
+ ];
128
+ }
129
+ }
130
+
131
+ export function hlsToHex(color) {
132
+ return componentsToHex(hslToComponents(color));
133
+ };
134
+
135
+ export function hexToComponents(color) {
136
+ if (color.length < 7){
137
+ const R = color[1];
138
+ const G = color[2];
139
+ const B = color[3];
140
+
141
+ if (color.length > 4) {
142
+ const A = color[4];
143
+
144
+ color = `#${R}${R}${G}${G}${B}${B}${A}${A}`;
145
+ } else {
146
+ color = `#${R}${R}${G}${G}${B}${B}`;
147
+ }
148
+ }
149
+
150
+ return [
151
+ parseInt(color.substr(1, 2), 16),
152
+ parseInt(color.substr(3, 2), 16),
153
+ parseInt(color.substr(5, 2), 16),
154
+ color.length > 7 ? parseInt(color.substr(7, 2), 16)/255 : 1
155
+ ];
156
+ }
157
+
158
+ /**
159
+ * Convert a hexadecimal string to
160
+ * @param {string} color
161
+ * @returns
162
+ */
163
+ export function hexToVec3String(color) {
164
+ return componentsToVec3String(hexToComponents(color));
165
+ }
166
+
167
+ export function hexToVec4String(color) {
168
+ return componentsToVec4String(hexToComponents(color));
169
+ }
170
+
171
+ export function hexToHSLString(color) {
172
+ return componentsToHSLString(hexToComponents(color));
173
+ }
174
+
175
+ export function hexToHSLAString(color) {
176
+ return componentsToHSLAString(hexToComponents(color));
177
+ }
178
+
179
+ export function toComponents(color) {
180
+ if (isHexString(color)) return hexToComponents(color);
181
+ if (isRGBAString(color) || isRGBString(color)) return stringToComponents(color);
182
+ if (isVec3String(color) || isVec4String(color)) return vecToComponents(color);
183
+
184
+ if (typeof color === "string") return nameToComponents(color);
185
+
186
+ console.error(`color.toComponents :: cannot parse color`, color);
187
+ }
188
+
189
+ export function toVec3String(color) {
190
+ return componentsToVec3String(toComponents(color));
191
+ }
192
+
193
+ export function toVec4String(color) {
194
+ return componentsToVec4String(toComponents(color));
195
+ }
196
+
197
+ export function componentsToVec3String(components = []) {
198
+ const [ r = 0, g = 0, b = 0] = components;
199
+
200
+ let rn = `${Math.round(r / 255 * 100000) / 100000}`;
201
+ let gn = `${Math.round(g / 255 * 100000) / 100000}`;
202
+ let bn = `${Math.round(b / 255 * 100000) / 100000}`;
203
+
204
+ if (r === 255 || r === 0) {
205
+ rn = `${rn}.0`;
206
+ }
207
+
208
+ if (g === 255 || g === 0) {
209
+ gn = `${gn}.0`;
210
+ }
211
+
212
+ if (b === 255 || b === 0) {
213
+ bn = `${bn}.0`;
214
+ }
215
+
216
+ return `vec3(${rn}, ${gn}, ${bn})`;
217
+ }
218
+
219
+ export function componentsToVec4String(components = []) {
220
+ const [ r = 0, g = 0, b = 0, a = 1] = components;
221
+
222
+ let rn = `${Math.round(r / 255 * 100000) / 100000}`;
223
+ let gn = `${Math.round(g / 255 * 100000) / 100000}`;
224
+ let bn = `${Math.round(b / 255 * 100000) / 100000}`;
225
+ let an = `${a}`;
226
+
227
+ if (r === 255 || r === 0) {
228
+ rn = `${rn}.0`;
229
+ }
230
+
231
+ if (g === 255 || g === 0) {
232
+ gn = `${gn}.0`;
233
+ }
234
+
235
+ if (b === 255 || b === 0) {
236
+ bn = `${bn}.0`;
237
+ }
238
+
239
+ if (a === 1 || a === 0) {
240
+ an = `${an}.0`;
241
+ }
242
+
243
+ return `vec4(${rn}, ${gn}, ${bn}, ${an})`;
244
+ }
245
+
246
+ export function toHex(color) {
247
+ if (isHexString(color)) return color;
248
+ if (isRGBString(color)) return stringToHex(color);
249
+ if (isRGBAString(color)) return stringToHex(color);
250
+ if (isVec3String(color)) return vecToHex(color);
251
+ if (isVec4String(color)) return vecToHex(color);
252
+ if (!color.includes('rgb')) return nameToHex(color);
253
+
254
+ console.error(`color.toHex :: cannot parse color`, color);
255
+ }
256
+
257
+ export function toRGBString(color) {
258
+ const [r, g, b] = toComponents(color);
259
+
260
+ return componentsToRGBString([r, g, b]);
261
+ }
262
+
263
+ export function toRGBAString(color) {
264
+ return componentsToRGBAString(toComponents(color));
265
+ }
266
+
267
+ export function hexToRGBString(color) {
268
+ return componentsToRGBString(hexToComponents(color));
269
+ }
270
+
271
+ export function hexToRGBAString(color) {
272
+ return componentsToRGBString(hexToComponents(color));
273
+ }
274
+
275
+ export function componentsToRGBString(components) {
276
+ const [ r, g, b ] = components;
277
+
278
+ return `rgb(${r}, ${g}, ${b})`;
279
+ }
280
+
281
+ export function componentsToRGBAString(components = []) {
282
+ const [ r = 0, g = 0, b = 0, a = 1 ] = components;
283
+
284
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
285
+ }
286
+
287
+ export function componentsToHSLComponents(components = []) {
288
+ const [ r = 0, g = 0, b = 0 ] = components;
289
+
290
+ let v = Math.max(r,g,b);
291
+ let c = v-Math.min(r,g,b);
292
+ let f = (1-Math.abs(v+v-c-1));
293
+ let h = c && ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c));
294
+ h = 60*(h<0?h+6:h);
295
+
296
+ let l = (f ? c/f : 0);
297
+ let s = (v+v-c)/2;
298
+
299
+ return [h, s, l];
300
+ }
301
+
302
+ export function hslToHSLString(components) {
303
+ const [ h = 0, s = 0, l = 0] = components;
304
+
305
+ return `hsl(${h}, ${s}%, ${l}%)`;
306
+ }
307
+
308
+ export function hslaToHSLAString(components) {
309
+ const [ h = 0, s = 0, l = 0, a = 1] = components;
310
+
311
+ return `hsla(${h}, ${s}%, ${l}%, ${a})`;
312
+ }
313
+
314
+ export function componentsToHSLString(components = []) {
315
+ const [ r = 0, g = 0, b = 0, a = 1 ] = components;
316
+ return hslToHSLString(componentsToHSLComponents([r, g, b]));
317
+ }
318
+
319
+ export function componentsToHSLAString(components = []) {
320
+ const [ r = 0, g = 0, b = 0, a = 1 ] = components;
321
+ return hslaToHSLAString(componentsToHSLComponents([r, g, b]));
322
+ }
323
+
324
+ export function componentToHex(c) {
325
+ return c.toString(16).padStart(2, 0);
326
+ }
327
+
328
+ export function componentsToHex(components = []) {
329
+ const [ r = 0, g = 0, b = 0 ] = components;
330
+
331
+ return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
332
+ }
333
+
334
+ export function isHexString(color, isString = typeof color === "string") {
335
+ return isString && color[0] === "#";
336
+ }
337
+
338
+ export function isRGBAString(color, isString = typeof color === "string") {
339
+ return isString && color.includes("rgba");
340
+ }
341
+
342
+ export function isRGBString(color, isString = typeof color === "string") {
343
+ return isString && color.includes("rgb");
344
+ }
345
+
346
+ export function isHSLAString(color, isString = typeof color === "string") {
347
+ return isString && color.includes("hsla");
348
+ }
349
+
350
+ export function isHSLString(color, isString = typeof color === "string") {
351
+ return isString && color.includes("hsl");
352
+ }
353
+
354
+ export function isVec3String(color, isString = typeof color === "string") {
355
+ return isString && color.includes("vec3(");
356
+ }
357
+
358
+ export function isVec4String(color, isString = typeof color === "string") {
359
+ return isString && color.includes("vec4(");
360
+ }
361
+
362
+ export function isRGBAArray(value) {
363
+ return Array.isArray(value) && value.length === 4 && value.every((c, i) => i < 3 ? (c <= 255) : (c <= 1));
364
+ }
365
+
366
+ export function isRGBArray(value) {
367
+ return Array.isArray(value) && value.length === 3 && value.every(c => c <= 255);
368
+ }
369
+
370
+ export function isName(value) {
371
+ const components = nameToComponents(value);
372
+
373
+ return components && components.length > 0;
374
+ }
375
+
376
+ export function isTHREE(value) {
377
+ return value && value.isColor;
378
+ }
379
+
380
+ export function threeToHexString(value) {
381
+ if (!isTHREE(value)) {
382
+ console.error(`color.threeToHexString() : value is not an instance of THREE.Color`);
383
+ }
384
+
385
+ return `#${value.getHexString()}`;
386
+ }
387
+
388
+ export function isColor(value) {
389
+ let isString = typeof value === "string";
390
+
391
+ if (isHexString(value, isString)) return true;
392
+ if (isRGBString(value, isString)) return true;
393
+ if (isVec3String(value, isString)) return true;
394
+ if (isVec4String(value, isString)) return true;
395
+ if (isHSLString(value, isString)) return true;
396
+ if (isRGBArray(value)) return true;
397
+ if (isRGBAArray(value)) return true;
398
+ if (isName(value)) return true;
399
+
400
+ return false;
401
+ }
402
+
403
+ export const FORMATS = {
404
+ HEX_STRING: "hex-string",
405
+ RGB_STRING: "rgb-string",
406
+ RGBA_STRING: "rgba-string",
407
+ HSL_STRING: "hsl-string",
408
+ HSLA_STRING: "hsla-string",
409
+ RGB_ARRAY: "rgb-array",
410
+ RGBA_ARRAY: "rgba-array",
411
+ VEC3_STRING: "vec3-string",
412
+ VEC4_STRING: "vec4-string",
413
+ THREE: "three",
414
+ };
415
+
416
+ export function getColorFormat(value) {
417
+ if (isTHREE(value)) return FORMATS.THREE;
418
+ if (isHexString(value)) return FORMATS.HEX_STRING;
419
+ if (isRGBAString(value)) return FORMATS.RGBA_STRING;
420
+ if (isRGBString(value)) return FORMATS.RGB_STRING;
421
+ if (isRGBArray(value)) return FORMATS.RGB_ARRAY;
422
+ if (isRGBAArray(value)) return FORMATS.RGBA_ARRAY;
423
+ if (isVec3String(value)) return FORMATS.VEC3_STRING;
424
+ if (isVec4String(value)) return FORMATS.VEC4_STRING;
425
+ if (isHSLAString(value)) return FORMATS.HSLA_STRING;
426
+ if (isHSLString(value)) return FORMATS.HSL_STRING;
427
+ };
@@ -0,0 +1,77 @@
1
+ export function createBlobFromDataURL(dataURL) {
2
+ return new Promise((resolve) => {
3
+ const splitIndex = dataURL.indexOf(',');
4
+
5
+ if (splitIndex === -1) {
6
+ reject(new Error(`createBlobFromDataURL: dataURL doesn't contain extension data.`))
7
+ return;
8
+ }
9
+
10
+ const base64 = dataURL.slice(splitIndex + 1);
11
+ const byteString = window.atob(base64);
12
+ const type = dataURL.slice(0, splitIndex);
13
+ const mimeMatch = /data:([^;]+)/.exec(type);
14
+ const mime = (mimeMatch ? mimeMatch[1] : '') || undefined;
15
+ const ab = new ArrayBuffer(byteString.length);
16
+ const ia = new Uint8Array(ab);
17
+ for (var i = 0; i < byteString.length; i++) {
18
+ ia[i] = byteString.charCodeAt(i);
19
+ }
20
+
21
+ resolve(new window.Blob([ ab ], { type: mime }));
22
+ });
23
+ }
24
+
25
+ export function download(data, filename) {
26
+ let extension = getFileExtension(filename);
27
+
28
+ if (typeof data === "object" && ["json", "txt"].includes(extension)) {
29
+ data = JSON.stringify(data, undefined, 4);
30
+ }
31
+
32
+ let type = getMimeType(extension);
33
+ let blob = new Blob([data], { type });
34
+
35
+ downloadBlob(blob, { filename });
36
+ }
37
+
38
+ export function downloadBlob(blob, { filename = "untitled" } = {}) {
39
+ let a = document.createElement('a');
40
+ a.style.visibility = 'hidden';
41
+ a.target = '_blank';
42
+
43
+ a.download = filename;
44
+ a.href = window.URL.createObjectURL(blob);
45
+ // a.dataset.downloadurl = [type, a.download, a.href].join(':');
46
+
47
+ a.onclick = () => {
48
+ a.onclick = () => {};
49
+ setTimeout(() => {
50
+ window.URL.revokeObjectURL(blob);
51
+ if (a.parentElement) a.parentElement.removeChild(a);
52
+ a.removeAttribute('href');
53
+ });
54
+ };
55
+
56
+ a.click();
57
+ }
58
+
59
+ export function getFileExtension(path) {
60
+ const match = path.match(/[^\\/]\.([^.\\/]+)$/);
61
+
62
+ if (match && match.length > 1) {
63
+ return match[1];
64
+ }
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @param {string} extension
70
+ * @returns {string} mimeType
71
+ */
72
+ export function getMimeType(extension) {
73
+ if (extension === "json") return "application/json";
74
+ if (extension === "txt") return "text";
75
+ if (extension === "png") return "image/png";
76
+ if (extension === "jpeg" || extension === "jpg") return "image/jpeg";
77
+ }
@@ -0,0 +1,14 @@
1
+ const regex = /<filepath:\/\/(.*)>/;
2
+
3
+ export function getShaderPath(shader) {
4
+ const match = shader.match(/<filepath:\/\/(.*)>/);
5
+ return match && match[1];
6
+ };
7
+
8
+ export function removeShaderPath(shader, filepath = getShaderPath(shader)) {
9
+ if (filepath) {
10
+ return shader.replace(`// <filepath://${filepath}>`, "");
11
+ }
12
+
13
+ return shader;
14
+ }
@@ -0,0 +1,154 @@
1
+ import { displayError } from "../stores/errors";
2
+ import { getShaderPath, removeShaderPath } from "./glsl.utils";
3
+
4
+ const methods = ['attachShader'];
5
+
6
+ const contexts = [WebGLRenderingContext, WebGL2RenderingContext];
7
+ const references = {};
8
+
9
+ for (let i = 0; i < methods.length; i++) {
10
+ const method = methods[i];
11
+ references[method] = contexts.map((context) => context.prototype[method]);
12
+ }
13
+
14
+ function createUUID() {
15
+ function s4() {
16
+ return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
17
+ }
18
+
19
+ return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
20
+ };
21
+
22
+ function e(method, fn) {
23
+ contexts.forEach(context => {
24
+ const f = context.prototype[method];
25
+
26
+ context.prototype[method] = function() {
27
+ var res = f.apply( this, arguments );
28
+ res = fn.apply( this, [ res, arguments ] ) || res;
29
+ return res;
30
+ }
31
+ })
32
+ }
33
+
34
+ const FRAGMENT_SHADER = 35632;
35
+ const VERTEX_SHADER = 35633;
36
+
37
+ class ShaderCompileError extends Error {
38
+
39
+ constructor({
40
+ source,
41
+ filename = "",
42
+ lineNumber,
43
+ message = `Cannot compile ${filename !== "" ? filename : "shader"}`
44
+ } = {}) {
45
+ super(message, filename, lineNumber);
46
+
47
+ this.name = "ShaderCompileError";
48
+ this.source = source;
49
+ this.lineNumber = lineNumber;
50
+
51
+ this.stack = `at (${filename}:${lineNumber})`;
52
+ }
53
+ }
54
+
55
+ e('createShader', function(res, args) {
56
+ if (!this.__uuid) {
57
+ this.__uuid = createUUID();
58
+ }
59
+
60
+ res.__uuid = createUUID();
61
+ res.__type = args[0];
62
+ });
63
+
64
+ e('attachShader', function(res, args) {
65
+ const program = args[0];
66
+ const shader = args[1];
67
+
68
+ if (shader.__type === FRAGMENT_SHADER) {
69
+ program.__fragmentShader = shader;
70
+ } else if (shader.__type === VERTEX_SHADER) {
71
+ program.__vertexShader = shader;
72
+ }
73
+ });
74
+
75
+ e('shaderSource', function(res, args) {
76
+ const shader = args[0];
77
+ const source = args[1];
78
+
79
+ shader.__source = source;
80
+
81
+ const filepath = getShaderPath(source);
82
+
83
+ if (filepath) {
84
+ const filename = filepath.replace(`${__CWD__}/`, "");
85
+
86
+ shader.__filepath = filepath;
87
+ shader.__filename = filename;
88
+ }
89
+ });
90
+
91
+ e('createProgram', function(res, args) {
92
+ res.__uuid = createUUID();
93
+ });
94
+
95
+ e('compileShader', function(res, args) {
96
+ const gl = this;
97
+ const shader = args[0];
98
+ const filename = shader.__filename;
99
+
100
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
101
+ const { source, lineNumber, message } = getShaderError(gl, shader, shader.__type);
102
+
103
+ const error = new ShaderCompileError({
104
+ source,
105
+ message,
106
+ filename,
107
+ lineNumber,
108
+ });
109
+
110
+ displayError(error, this.__uuid);
111
+ }
112
+ });
113
+
114
+ function getShaderError(gl, shader, type) {
115
+ const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
116
+ const errors = gl.getShaderInfoLog(shader).trim();
117
+
118
+ if (status && errors === '') return '';
119
+
120
+ const errorMatches = errors.match(/ERROR: 0:(\d+):([\s\S]*$)/);
121
+
122
+ if (errorMatches) {
123
+ const lineNumber = parseInt(errorMatches[1]);
124
+ const message = errorMatches[2];
125
+ const shaderSource = gl.getShaderSource(shader);
126
+ const source = handleSource(shaderSource, lineNumber);
127
+
128
+ return {
129
+ message,
130
+ source: source,
131
+ lineNumber,
132
+ };
133
+ } else {
134
+ return errors;
135
+ }
136
+ }
137
+
138
+ function handleSource(source, errorLine) {
139
+ const hasPath = getShaderPath(source);
140
+
141
+ const lines = (hasPath ? removeShaderPath(source) : source).split('\n');
142
+ const lines2 = [];
143
+
144
+ const from = Math.max( errorLine - 6, 0 );
145
+ const to = Math.min( errorLine + 6, lines.length );
146
+
147
+ for ( let i = from; i < to; i ++ ) {
148
+ const line = i + 1;
149
+
150
+ lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );
151
+ }
152
+
153
+ return lines2.join( '\n' );
154
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ *
3
+ * @param {Map} map
4
+ * @param {string} key
5
+ * @param {any} find
6
+ */
7
+ export const addToMapArray = (map, key, item) => {
8
+ if (map.has(key)) {
9
+ map.set(key, [...map.get(key), item]);
10
+ } else {
11
+ map.set(key, [item]);
12
+ }
13
+ }
14
+
15
+ /**
16
+ *
17
+ * @param {Map} map
18
+ * @param {string} key
19
+ * @param {function} findIndex
20
+ */
21
+ export const removeFromMapArray = (map, key, findIndex) => {
22
+ if (map.has(key)) {
23
+ const items = map.get(key);
24
+ const index = items.findIndex(findIndex);
25
+
26
+ if (index >= 0) {
27
+ const newItems = [...items];
28
+ newItems.splice(index, 1);
29
+
30
+ if (newItems.length > 0) {
31
+ map.set(key, newItems);
32
+ } else {
33
+ map.delete(key);
34
+ }
35
+ }
36
+ } else {
37
+ console.error(`removeFromMapArray: key ${key} doesn't exist in Map.`, map);
38
+ }
39
+ };