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
@@ -0,0 +1,260 @@
1
+ import { ConfirmPrompt, SelectPrompt, TextPrompt } from '@clack/core';
2
+ import isUnicodeSupported from 'is-unicode-supported';
3
+ import * as color from 'kleur/colors';
4
+
5
+ const unicode = isUnicodeSupported();
6
+
7
+ /**
8
+ * @param {string} c
9
+ * @param {string} fallback
10
+ * @returns {string}
11
+ */
12
+ const s = (c, fallback) => (unicode ? c : fallback);
13
+
14
+ const S_RADIO_ACTIVE = s('●', '>');
15
+ const S_RADIO_INACTIVE = s('○', ' ');
16
+
17
+ const S_BAR_H = s('─', '-');
18
+ const S_CORNER_TOP_LEFT = s('╭', '+');
19
+ const S_CORNER_TOP_RIGHT = s('╮', '+');
20
+ const S_CORNER_BOTTOM_RIGHT = s('╯', '+');
21
+ const S_CORNER_BOTTOM_LEFT = s('╰', '+');
22
+ const S_BAR = s('│', '|');
23
+
24
+ /**
25
+ * @param {object} opts
26
+ * @param {string} opts.active
27
+ * @param {string} opts.inactive
28
+ * @param {boolean} opts.initialValue
29
+ * @returns {Promise<boolean|symbol>}
30
+ */
31
+ export const confirm = (opts) => {
32
+ const active = opts.active ?? 'Yes';
33
+ const inactive = opts.inactive ?? 'No';
34
+
35
+ return new ConfirmPrompt({
36
+ active,
37
+ inactive,
38
+ initialValue: opts.initialValue ?? true,
39
+ render() {
40
+ const title = `${opts.message}\n`;
41
+ const value = this.value ? active : inactive;
42
+
43
+ switch (this.state) {
44
+ case 'submit':
45
+ return `${color.dim(title)} ${color.green(value)}\n`;
46
+ case 'cancel':
47
+ return `${title}${color.strikethrough(color.dim(value))}\n`;
48
+ default: {
49
+ return `${title} ${
50
+ this.value
51
+ ? `${S_RADIO_ACTIVE} ${active}`
52
+ : `${color.dim(S_RADIO_INACTIVE)} ${color.dim(active)}`
53
+ } ${color.dim('/')} ${
54
+ !this.value
55
+ ? `${S_RADIO_ACTIVE} ${inactive}`
56
+ : `${color.dim(S_RADIO_INACTIVE)} ${color.dim(inactive)}`
57
+ }\n`;
58
+ }
59
+ }
60
+ },
61
+ }).prompt();
62
+ };
63
+
64
+ /**
65
+ * @param {object} opts
66
+ * @param {string} opts.message
67
+ * @param {string} [opts.placeholder]
68
+ * @param {string} [opts.defaultValue]
69
+ * @param {string} [opts.initialValue]
70
+ * @param {string} [opts.initialValue]
71
+ * @param {function} [opts.validate]
72
+ * @returns {Promise<string|symbol>}
73
+ */
74
+ export const text = (opts) => {
75
+ const { hint = '' } = opts;
76
+
77
+ return new TextPrompt({
78
+ validate: opts.validate,
79
+ placeholder: opts.placeholder,
80
+ defaultValue: opts.defaultValue,
81
+ initialValue: opts.initialValue,
82
+ render() {
83
+ const title = `${opts.message}\n`;
84
+ const placeholder = opts.placeholder
85
+ ? color.inverse(opts.placeholder[0]) +
86
+ color.dim(opts.placeholder.slice(1))
87
+ : color.inverse(color.hidden('_'));
88
+ const value = !this.value
89
+ ? `${placeholder} ${color.dim(hint)}`.trim()
90
+ : this.valueWithCursor;
91
+
92
+ switch (this.state) {
93
+ case 'error':
94
+ return `${title.trim()}\n${value}\n ${color.yellow(this.error)}\n`;
95
+ case 'submit':
96
+ return `${color.dim(`${title}`)} ${color.green(this.value || opts.placeholder)}\n`;
97
+ case 'cancel':
98
+ return `${title} ${color.strikethrough(
99
+ color.dim(this.value ?? placeholder),
100
+ )}\n`;
101
+ default:
102
+ return `${title} ${value}\n`;
103
+ }
104
+ },
105
+ }).prompt();
106
+ };
107
+
108
+ const limitOptions = (params) => {
109
+ const { cursor, options, style } = params;
110
+
111
+ // We clamp to minimum 5 because anything less doesn't make sense UX wise
112
+ const maxItems =
113
+ params.maxItems === undefined ? Infinity : Math.max(params.maxItems, 5);
114
+ let slidingWindowLocation = 0;
115
+
116
+ if (cursor >= slidingWindowLocation + maxItems - 3) {
117
+ slidingWindowLocation = Math.max(
118
+ Math.min(cursor - maxItems + 3, options.length - maxItems),
119
+ 0,
120
+ );
121
+ } else if (cursor < slidingWindowLocation + 2) {
122
+ slidingWindowLocation = Math.max(cursor - 2, 0);
123
+ }
124
+
125
+ const shouldRenderTopEllipsis =
126
+ maxItems < options.length && slidingWindowLocation > 0;
127
+ const shouldRenderBottomEllipsis =
128
+ maxItems < options.length &&
129
+ slidingWindowLocation + maxItems < options.length;
130
+
131
+ return options
132
+ .slice(slidingWindowLocation, slidingWindowLocation + maxItems)
133
+ .map((option, i, arr) => {
134
+ const isTopLimit = i === 0 && shouldRenderTopEllipsis;
135
+ const isBottomLimit =
136
+ i === arr.length - 1 && shouldRenderBottomEllipsis;
137
+ return isTopLimit || isBottomLimit
138
+ ? color.dim('...')
139
+ : style(option, i + slidingWindowLocation === cursor);
140
+ });
141
+ };
142
+
143
+ /**
144
+ * @typedef {string|boolean|number} Value
145
+ */
146
+
147
+ /**
148
+ * @typedef {Object} Option
149
+ * @property {string} value
150
+ * @property {string} [label]
151
+ * @property {string} [hint]
152
+ */
153
+
154
+ /**
155
+ * @param {object} opts
156
+ * @param {string} opts.message
157
+ * @param {Option<Value>[]} opts.options
158
+ * @param {Value} [opts.initialValue]
159
+ * @param {number} [opts.maxItems]
160
+ * @returns {Promise<boolean|symbol>}
161
+ */
162
+ export const select = (opts) => {
163
+ /**
164
+ *
165
+ * @param {Option<Value>} option
166
+ * @param {'inactive' | 'active' | 'selected' | 'cancelled'} state
167
+ * @returns {string}
168
+ */
169
+ const opt = (option, state) => {
170
+ const label = option.label ?? String(option.value);
171
+ switch (state) {
172
+ case 'selected':
173
+ return `${label}`;
174
+ case 'active':
175
+ return `${color.green(S_RADIO_ACTIVE)} ${label} ${
176
+ option.hint ? color.dim(`(${option.hint})`) : ''
177
+ }`;
178
+ case 'cancelled':
179
+ return `${color.strikethrough(color.dim(label))}`;
180
+ default:
181
+ return `${color.dim(S_RADIO_INACTIVE)} ${color.dim(label)}`;
182
+ }
183
+ };
184
+
185
+ return new SelectPrompt({
186
+ options: opts.options,
187
+ initialValue: opts.initialValue,
188
+ render() {
189
+ const title = `${opts.message}\n`;
190
+
191
+ switch (this.state) {
192
+ case 'submit':
193
+ return `${color.dim(title)} ${color.green(opt(this.options[this.cursor], 'selected'))}\n`;
194
+ case 'cancel':
195
+ return `${title} ${opt(
196
+ this.options[this.cursor],
197
+ 'cancelled',
198
+ )}\n`;
199
+ default: {
200
+ return `${title} ${limitOptions({
201
+ cursor: this.cursor,
202
+ options: this.options,
203
+ maxItems: opts.maxItems,
204
+ style: (item, active) =>
205
+ opt(item, active ? 'active' : 'inactive'),
206
+ }).join(`\n`)}\n`;
207
+ }
208
+ }
209
+ },
210
+ }).prompt();
211
+ };
212
+
213
+ function ansiRegex() {
214
+ const pattern = [
215
+ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
216
+ '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))',
217
+ ].join('|');
218
+
219
+ return new RegExp(pattern, 'g');
220
+ }
221
+
222
+ /**
223
+ * @param {string} str
224
+ * @returns {string}
225
+ */
226
+ const strip = (str) => str.replace(ansiRegex(), '');
227
+
228
+ /**
229
+ * @param {string} message
230
+ * @param {string} title
231
+ */
232
+ export const note = (message = '', title = '') => {
233
+ const lines = `\n${message}\n`.split('\n');
234
+ const titleLen = strip(title).length;
235
+ const len =
236
+ Math.max(
237
+ lines.reduce((sum, ln) => {
238
+ ln = strip(ln);
239
+ return ln.length > sum ? ln.length : sum;
240
+ }, 0),
241
+ titleLen,
242
+ ) + 2;
243
+ const msg = lines
244
+ .map(
245
+ (ln) =>
246
+ `${color.gray(S_BAR)} ${ln}${' '.repeat(len - strip(ln).length)}${color.gray(
247
+ S_BAR,
248
+ )}`,
249
+ )
250
+ .join('\n');
251
+
252
+ const head = title ? ` ${title} ` : `${color.gray(S_BAR_H.repeat(2))}`;
253
+
254
+ process.stdout.write(
255
+ `${color.gray(S_CORNER_TOP_LEFT + S_BAR_H)}${head}${color.gray(
256
+ S_BAR_H.repeat(Math.max(len - titleLen - 1, 1)) +
257
+ S_CORNER_TOP_RIGHT,
258
+ )}\n${msg}\n${color.gray(S_CORNER_BOTTOM_LEFT + S_BAR_H.repeat(len + 2) + S_CORNER_BOTTOM_RIGHT)}\n`,
259
+ );
260
+ };
package/src/cli/run.js ADDED
@@ -0,0 +1,131 @@
1
+ import { createServer, mergeConfig } from 'vite';
2
+ import { createConfig } from './createConfig.js';
3
+ import { createFragmentFile } from './createFragmentFile.js';
4
+ import { getEntries } from './getEntries.js';
5
+ import { log, magenta, bold, cyan, red } from './log.js';
6
+ import save from './plugins/save.js';
7
+ import * as p from './prompts.js';
8
+ import { prettifyTime } from './utils.js';
9
+ import { start as startWebSocketServer } from './ws.js';
10
+ import hotSketchReload from './plugins/hot-sketch-reload.js';
11
+ import hotShaderReplacement from './plugins/hot-shader-replacement.js';
12
+
13
+ /**
14
+ * Run a sketch
15
+ * @param {string} entry
16
+ * @param {object} options
17
+ * @param {boolean} options.development
18
+ * @param {number} options.port
19
+ * @param {number} options.exportDir
20
+ */
21
+ export async function run(entry, options = {}) {
22
+ let fragmentServer;
23
+
24
+ const cwd = process.cwd();
25
+ const command = `run`;
26
+ const prefix = log.prefix(command);
27
+ const exit = () => {
28
+ process.off('SIGTERM', exit);
29
+ process.off('exit', exit);
30
+
31
+ if (fragmentServer) {
32
+ fragmentServer.close();
33
+ }
34
+
35
+ console.log();
36
+ };
37
+
38
+ process.once('SIGTERM', exit);
39
+ process.on('exit', exit);
40
+
41
+ const startTime = Date.now();
42
+
43
+ try {
44
+ const entries = await getEntries(entry, cwd, command, prefix);
45
+
46
+ if (!entries.length) return;
47
+
48
+ log.message(
49
+ `Starting ${entries.length > 1 ? `${entries.length} sketches in ${entry}` : magenta(entries[0])}\n`,
50
+ prefix,
51
+ );
52
+
53
+ if (entries.length > 1) {
54
+ log.message(
55
+ `${entries.map((entry) => `- ${magenta(entry)}`).join('\n')}\n`,
56
+ );
57
+ }
58
+
59
+ const fragmentFilepath = await createFragmentFile(entries, cwd);
60
+
61
+ fragmentServer = await startWebSocketServer({
62
+ cwd,
63
+ });
64
+
65
+ const config = createConfig(
66
+ entries,
67
+ fragmentFilepath,
68
+ {
69
+ dev: options.development,
70
+ build: false,
71
+ },
72
+ cwd,
73
+ );
74
+
75
+ log.info(`Starting Vite server...`);
76
+
77
+ const server = await createServer(
78
+ mergeConfig(config, {
79
+ server: {
80
+ port: options.port,
81
+ host: true,
82
+ fs: {
83
+ strict: false,
84
+ allow: ['..'],
85
+ },
86
+ },
87
+ define: {
88
+ __FRAGMENT_PORT__: fragmentServer.port,
89
+ },
90
+ plugins: [
91
+ hotSketchReload({
92
+ cwd,
93
+ }),
94
+ hotShaderReplacement({ cwd, wss: fragmentServer }),
95
+ save({ cwd, inlineExportDir: options.exportDir }),
96
+ ],
97
+ }),
98
+ );
99
+ await server.listen();
100
+
101
+ // line break after logs
102
+ log.message();
103
+
104
+ log.success(
105
+ `Started in ${prettifyTime(Date.now() - startTime)}\n`,
106
+ prefix,
107
+ );
108
+
109
+ const { resolvedUrls } = server;
110
+
111
+ let urls = [
112
+ ...resolvedUrls.local.map(
113
+ (url) => `${bold('Local')}: ${bold(cyan(url))}`,
114
+ ),
115
+ ...resolvedUrls.network.map(
116
+ (url) => `${bold('Network')}: ${bold(cyan(url))}`,
117
+ ),
118
+ ];
119
+ p.note(urls.join(`\n`));
120
+
121
+ // line break before fragment logs
122
+ log.message();
123
+
124
+ return server;
125
+ } catch (error) {
126
+ // line break before error
127
+ log.message();
128
+ log.error(`Error\n`, prefix);
129
+ console.error(error);
130
+ }
131
+ }
@@ -0,0 +1,33 @@
1
+ export let props = {};
2
+
3
+ /**
4
+ * @param {object} params
5
+ * @param {HTMLCanvasElement} params.canvas
6
+ * @param {number} params.width
7
+ * @param {number} params.height
8
+ * @param {number} params.pixelRatio
9
+ */
10
+ export let init = ({ canvas, width, height, pixelRatio }) => {};
11
+
12
+ /**
13
+ * @param {object} params
14
+ * @param {HTMLCanvasElement} params.canvas
15
+ * @param {number} params.width
16
+ * @param {number} params.height
17
+ * @param {number} params.pixelRatio
18
+ * @param {number} params.time
19
+ * @param {number} params.deltaTime
20
+ * @param {number} params.frame
21
+ * @param {number} params.playhead
22
+ * @param {number} params.playcount
23
+ */
24
+ export let update = ({ width, height, time, deltaTime }) => {};
25
+
26
+ /**
27
+ * @param {object} params
28
+ * @param {HTMLCanvasElement} params.canvas
29
+ * @param {number} params.width
30
+ * @param {number} params.height
31
+ * @param {number} params.pixelRatio
32
+ */
33
+ export let resize = ({ width, height, pixelRatio }) => {};
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "blank",
3
+ "description": "An empty sketch"
4
+ }
@@ -0,0 +1,39 @@
1
+ export let props = {};
2
+
3
+ /**
4
+ * @param {object} params
5
+ * @param {HTMLCanvasElement} params.canvas
6
+ * @param {CanvasRenderingContext2D} params.context
7
+ * @param {number} params.width
8
+ * @param {number} params.height
9
+ * @param {number} params.pixelRatio
10
+ */
11
+ export let init = ({ canvas, context, width, height }) => {};
12
+
13
+ /**
14
+ * @param {object} params
15
+ * @param {HTMLCanvasElement} params.canvas
16
+ * @param {CanvasRenderingContext2D} params.context
17
+ * @param {number} params.width
18
+ * @param {number} params.height
19
+ * @param {number} params.pixelRatio
20
+ * @param {number} params.time
21
+ * @param {number} params.deltaTime
22
+ * @param {number} params.frame
23
+ * @param {number} params.playhead
24
+ * @param {number} params.playcount
25
+ */
26
+ export let update = ({ context, width, height, time, deltaTime }) => {
27
+ context.clearRect(0, 0, width, height);
28
+ };
29
+
30
+ /**
31
+ * @param {object} params
32
+ * @param {HTMLCanvasElement} params.canvas
33
+ * @param {number} params.width
34
+ * @param {number} params.height
35
+ * @param {number} params.pixelRatio
36
+ */
37
+ export let resize = ({ width, height }) => {};
38
+
39
+ export let rendering = '2d';
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "2d",
3
+ "description": "An empty sketch with a CanvasRenderingContext2D",
4
+ "isDefault": true
5
+ }
@@ -0,0 +1,37 @@
1
+ import fragmentShader from './fragment.fs';
2
+
3
+ let uniforms = {
4
+ uTime: { value: 0, type: 'float' },
5
+ };
6
+
7
+ /**
8
+ * @param {object} params
9
+ * @param {HTMLCanvasElement} params.canvas
10
+ * @param {number} params.width
11
+ * @param {number} params.height
12
+ * @param {number} params.pixelRatio
13
+ */
14
+ export let init = ({ frag }) => {
15
+ frag.uniforms = uniforms;
16
+ frag.shader = fragmentShader;
17
+ };
18
+
19
+ /**
20
+ * @param {object} params
21
+ * @param {HTMLCanvasElement} params.canvas
22
+ * @param {number} params.width
23
+ * @param {number} params.height
24
+ * @param {number} params.pixelRatio
25
+ * @param {number} params.time
26
+ * @param {number} params.deltaTime
27
+ * @param {number} params.frame
28
+ * @param {number} params.playhead
29
+ * @param {number} params.playcount
30
+ */
31
+ export let update = ({ frag, deltaTime }) => {
32
+ uniforms.uTime.value += deltaTime;
33
+
34
+ frag.render();
35
+ };
36
+
37
+ export let rendering = 'fragment';
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "fragment-gl",
3
+ "description": "A fullscreen fragment shader with fragment-gl"
4
+ }
@@ -0,0 +1,32 @@
1
+ import p5 from 'p5';
2
+
3
+ export let props = {};
4
+
5
+ /**
6
+ * @param {object} params
7
+ * @param {HTMLCanvasElement} params.canvas
8
+ * @param {p5} params.p
9
+ * @param {number} params.width
10
+ * @param {number} params.height
11
+ * @param {number} params.pixelRatio
12
+ */
13
+ export function setup({ p, width, height }) {}
14
+
15
+ /**
16
+ * @param {object} params
17
+ * @param {HTMLCanvasElement} params.canvas
18
+ * @param {p5} params.p
19
+ * @param {number} params.width
20
+ * @param {number} params.height
21
+ * @param {number} params.pixelRatio
22
+ * @param {number} params.time
23
+ * @param {number} params.deltaTime
24
+ * @param {number} params.frame
25
+ * @param {number} params.playhead
26
+ * @param {number} params.playcount
27
+ */
28
+ export function draw({ p }) {
29
+ p.background(255, 0, 0);
30
+ }
31
+
32
+ export let rendering = 'p5';
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "p5",
3
+ "description": "An empty sketch with p5.js",
4
+ "dependencies": ["p5"]
5
+ }
@@ -0,0 +1,14 @@
1
+ precision mediump float;
2
+
3
+ #define PI 3.141592653589793
4
+
5
+ uniform float uTime;
6
+
7
+ varying vec2 vUv;
8
+
9
+ void main() {
10
+ vec2 uv = vUv;
11
+ vec3 color = vec3(sin(uv.x * PI * 10. + uTime * 10.));
12
+
13
+ gl_FragColor = vec4(color, 1.0);
14
+ }
@@ -0,0 +1,67 @@
1
+ import p5 from 'p5';
2
+ import fragmentShader from './fragment.fs';
3
+
4
+ export let props = {
5
+ backgroundColor: {
6
+ value: 'rgb(255, 0, 0)',
7
+ },
8
+ };
9
+
10
+ let shader;
11
+
12
+ /**
13
+ * @param {object} params
14
+ * @param {HTMLCanvasElement} params.canvas
15
+ * @param {p5} params.p
16
+ * @param {number} params.width
17
+ * @param {number} params.height
18
+ * @param {number} params.pixelRatio
19
+ */
20
+ export let setup = ({ p, width, height }) => {
21
+ shader = p.createShader(
22
+ /* glsl */ `
23
+ attribute vec3 aPosition;
24
+ attribute vec2 aTexCoord;
25
+
26
+ uniform mat4 uProjectionMatrix;
27
+ uniform mat4 uModelViewMatrix;
28
+
29
+ varying vec2 vUv;
30
+
31
+ void main() {
32
+ vUv = aTexCoord;
33
+
34
+ vec3 transformed = aPosition;
35
+ transformed.xy = transformed.xy - 1.;
36
+
37
+ gl_Position = vec4(transformed, 1.);
38
+ }
39
+ `,
40
+ fragmentShader,
41
+ );
42
+ };
43
+
44
+ /**
45
+ * @param {object} params
46
+ * @param {HTMLCanvasElement} params.canvas
47
+ * @param {p5} params.p
48
+ * @param {number} params.width
49
+ * @param {number} params.height
50
+ * @param {number} params.pixelRatio
51
+ * @param {number} params.time
52
+ * @param {number} params.deltaTime
53
+ * @param {number} params.frame
54
+ * @param {number} params.playhead
55
+ * @param {number} params.playcount
56
+ */
57
+ export function draw({ p, width, height, time }) {
58
+ p.background(props.backgroundColor.value);
59
+
60
+ p.shader(shader);
61
+
62
+ shader.setUniform('uTime', time / 1000);
63
+
64
+ p.rect(0, 0, width, height);
65
+ }
66
+
67
+ export let rendering = 'p5-webgl';
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "p5-webgl",
3
+ "description": "An empty sketch with p5.js in WebGL mode",
4
+ "dependencies": ["p5"]
5
+ }
@@ -0,0 +1,10 @@
1
+ precision highp float;
2
+
3
+ uniform float uTime;
4
+ uniform vec2 uResolution;
5
+
6
+ varying vec2 vUv;
7
+
8
+ void main() {
9
+ gl_FragColor = vec4(1., 0., 0., 1.);
10
+ }