fragment-tools 0.1.20 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/bin/index.js +2 -2
  2. package/package.json +5 -6
  3. package/src/cli/build.js +1 -1
  4. package/src/cli/run.js +1 -1
  5. package/src/cli/templates/three-fragment/index.js +6 -6
  6. package/src/cli/templates/three-orthographic/index.js +3 -3
  7. package/src/cli/templates/three-perspective/index.js +3 -3
  8. package/src/client/app/actions/resize.js +14 -0
  9. package/src/client/app/components/HintLoading.svelte +94 -0
  10. package/src/client/app/components/HintPaused.svelte +88 -0
  11. package/src/client/app/components/HintRecord.svelte +62 -0
  12. package/src/client/app/components/IconLocked.svelte +51 -0
  13. package/src/client/app/components/IconTriggers.svelte +48 -0
  14. package/src/client/app/components/Init.svelte +14 -27
  15. package/src/client/app/components/KeyBinding.svelte +3 -6
  16. package/src/client/app/helpers.js +4 -40
  17. package/src/client/app/hooks.js +41 -17
  18. package/src/client/app/inputs/MIDI.js +2 -1
  19. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +6 -1
  20. package/src/client/app/lib/gl/Renderer.js +1 -0
  21. package/src/client/app/lib/svelte-json-tree/ErrorNode.svelte +28 -0
  22. package/src/client/app/lib/svelte-json-tree/ErrorStack.svelte +31 -0
  23. package/src/client/app/lib/svelte-json-tree/Expandable.svelte +25 -0
  24. package/src/client/app/lib/svelte-json-tree/JSONArrayNode.svelte +38 -0
  25. package/src/client/app/lib/svelte-json-tree/JSONArrow.svelte +47 -0
  26. package/src/client/app/lib/svelte-json-tree/JSONFunctionNode.svelte +114 -0
  27. package/src/client/app/lib/svelte-json-tree/JSONIterableArrayNode.svelte +60 -0
  28. package/src/client/app/lib/svelte-json-tree/JSONIterableMapNode.svelte +87 -0
  29. package/src/client/app/lib/svelte-json-tree/JSONNested.svelte +94 -0
  30. package/src/client/app/lib/svelte-json-tree/JSONNode.svelte +91 -0
  31. package/src/client/app/lib/svelte-json-tree/JSONObjectNode.svelte +40 -0
  32. package/src/client/app/lib/svelte-json-tree/JSONStringNode.svelte +31 -0
  33. package/src/client/app/lib/svelte-json-tree/JSONValueNode.svelte +31 -0
  34. package/src/client/app/lib/svelte-json-tree/PreviewList.svelte +38 -0
  35. package/src/client/app/lib/svelte-json-tree/RegExpNode.svelte +42 -0
  36. package/src/client/app/lib/svelte-json-tree/Root.svelte +75 -0
  37. package/src/client/app/lib/svelte-json-tree/Summary.svelte +9 -0
  38. package/src/client/app/lib/svelte-json-tree/TypedArrayNode.svelte +56 -0
  39. package/src/client/app/lib/svelte-json-tree/index.js +1 -0
  40. package/src/client/app/lib/svelte-json-tree/utils.js +57 -0
  41. package/src/client/app/modules/Console/ConsoleLine.svelte +12 -11
  42. package/src/client/app/modules/Console.svelte +82 -17
  43. package/src/client/app/modules/Exports.svelte +48 -48
  44. package/src/client/app/modules/MidiPanel.svelte +12 -19
  45. package/src/client/app/modules/Monitor.svelte +147 -55
  46. package/src/client/app/modules/Params.svelte +127 -80
  47. package/src/client/app/renderers/2DRenderer.js +1 -0
  48. package/src/client/app/renderers/FragmentRenderer.js +1 -1
  49. package/src/client/app/renderers/P5GLRenderer.js +11 -5
  50. package/src/client/app/renderers/P5Renderer.js +7 -3
  51. package/src/client/app/renderers/THREERenderer.js +42 -79
  52. package/src/client/app/state/Sketch.svelte.js +538 -0
  53. package/src/client/app/state/errors.svelte.js +17 -0
  54. package/src/client/app/state/exports.svelte.js +152 -0
  55. package/src/client/app/state/layout.svelte.js +205 -0
  56. package/src/client/app/state/monitors.svelte.js +36 -0
  57. package/src/client/app/state/renderers.svelte.js +77 -0
  58. package/src/client/app/state/rendering.svelte.js +697 -0
  59. package/src/client/app/state/sketches.svelte.js +73 -0
  60. package/src/client/app/state/utils.svelte.js +65 -0
  61. package/src/client/app/ui/Build.svelte +53 -60
  62. package/src/client/app/ui/ErrorOverlay.svelte +2 -2
  63. package/src/client/app/ui/Field.svelte +63 -189
  64. package/src/client/app/ui/FieldGroup.svelte +4 -5
  65. package/src/client/app/ui/FieldSection.svelte +14 -9
  66. package/src/client/app/ui/FieldSpace.svelte +1 -1
  67. package/src/client/app/ui/FieldTrigger.svelte +86 -84
  68. package/src/client/app/ui/FieldTriggers.svelte +25 -24
  69. package/src/client/app/ui/FloatingParams.svelte +50 -12
  70. package/src/client/app/ui/Layout.svelte +24 -13
  71. package/src/client/app/ui/LayoutColumn.svelte +2 -2
  72. package/src/client/app/ui/LayoutComponent.svelte +86 -195
  73. package/src/client/app/ui/LayoutResizer.svelte +25 -37
  74. package/src/client/app/ui/LayoutRoot.svelte +3 -5
  75. package/src/client/app/ui/LayoutRow.svelte +2 -2
  76. package/src/client/app/ui/LayoutToolbar.svelte +17 -76
  77. package/src/client/app/ui/Module.svelte +31 -35
  78. package/src/client/app/ui/ModuleHeaderAction.svelte +23 -16
  79. package/src/client/app/ui/ModuleHeaderButton.svelte +3 -3
  80. package/src/client/app/ui/ModuleHeaderSelect.svelte +4 -12
  81. package/src/client/app/ui/ModuleRenderer.svelte +84 -22
  82. package/src/client/app/ui/ParamsOutput.svelte +61 -77
  83. package/src/client/app/ui/Preview.svelte +15 -4
  84. package/src/client/app/ui/SelectChevrons.svelte +1 -2
  85. package/src/client/app/ui/SketchRenderer.svelte +89 -701
  86. package/src/client/app/ui/SketchSelect.svelte +14 -49
  87. package/src/client/app/ui/fields/ButtonInput.svelte +14 -11
  88. package/src/client/app/ui/fields/CheckboxInput.svelte +5 -12
  89. package/src/client/app/ui/fields/ColorInput.svelte +46 -121
  90. package/src/client/app/ui/fields/FieldInputRow.svelte +5 -1
  91. package/src/client/app/ui/fields/ImageInput.svelte +14 -14
  92. package/src/client/app/ui/fields/Input.svelte +19 -25
  93. package/src/client/app/ui/fields/IntervalInput.svelte +22 -22
  94. package/src/client/app/ui/fields/NumberInput.svelte +32 -38
  95. package/src/client/app/ui/fields/ProgressInput.svelte +14 -13
  96. package/src/client/app/ui/fields/Select.svelte +34 -45
  97. package/src/client/app/ui/fields/TextInput.svelte +10 -6
  98. package/src/client/app/ui/fields/VectorInput.svelte +25 -30
  99. package/src/client/app/utils/canvas.utils.js +8 -8
  100. package/src/client/app/utils/color.utils.js +46 -13
  101. package/src/client/app/utils/fields.utils.js +1 -1
  102. package/src/client/app/utils/glsl.utils.js +1 -1
  103. package/src/client/app/utils/glslErrors.js +1 -1
  104. package/src/client/main.js +2 -2
@@ -1,712 +1,152 @@
1
1
  <script>
2
- import { onMount, onDestroy } from 'svelte';
3
- import { derived } from 'svelte/store';
2
+ import { sketchesManager } from '../state/sketches.svelte.js';
3
+ import { layout } from '../state/layout.svelte.js';
4
+ import { Render, rendering, SIZES } from '../state/rendering.svelte';
5
+ import Sketch from '../state/Sketch.svelte.js';
6
+ import { exports } from '../state/exports.svelte.js';
7
+ import HintRecord from '../components/HintRecord.svelte';
8
+ import HintPaused from '../components/HintPaused.svelte';
4
9
  import KeyBinding from '../components/KeyBinding.svelte';
5
- import { sketches, sketchesKeys } from '../stores/sketches.js';
6
- import { layout } from '../stores/layout.js';
7
- import { rendering, SIZES, sync, monitors } from '../stores/rendering.js';
8
- import { errors, displayError, clearError } from '../stores/errors.js';
9
- import { exports, props } from '../stores/index.js';
10
- import { findRenderer } from '../stores/renderers';
11
- import { map } from '../utils/math.utils';
12
- import {
13
- recording,
14
- capturing,
15
- beforeCapture,
16
- afterCapture,
17
- beforeRecord,
18
- afterRecord,
19
- } from '../stores/exports.js';
20
- import { removeHotListeners } from '../triggers/index.js';
21
- import { removeHooksFrom } from '../hooks';
22
- import {
23
- checkForTriggersDown,
24
- checkForTriggersMove,
25
- checkForTriggersUp,
26
- checkForTriggersClick,
27
- } from '../triggers/Mouse.js';
28
- import { client } from '../client';
29
- import { recordCanvas, screenshotCanvas } from '../utils/canvas.utils.js';
30
- import ErrorOverlay from './ErrorOverlay.svelte';
31
- import { resetProps } from '../stores/props';
32
-
33
- export let key;
34
- export let id = 0;
35
- export let paused = false;
36
- export let visible = true;
37
-
38
- let node;
39
- /** @type {HTMLDivElement} */
40
- let container;
41
- let framerate = 60;
42
- let elapsed = 0;
43
- let elapsedRenderingTime = 0;
44
- let now = performance.now(),
45
- then = performance.now(),
46
- dt = 0,
47
- lastTime = performance.now();
48
- let canvas;
49
- let _raf;
50
- let _key = key;
51
-
52
- let sketch;
53
- let _created = false,
54
- _errored = false;
55
- let renderer;
56
- let noop = () => {};
57
- let _renderSketch = noop;
58
- let backgroundColor = 'inherit';
59
-
60
- $: beforeCaptureCallbacks = $beforeCapture.get(key) || [];
61
- $: afterCaptureCallbacks = $afterCapture.get(key) || [];
62
- $: beforeRecordCallbacks = $beforeRecord.get(key) || [];
63
- $: afterRecordCallbacks = $afterRecord.get(key) || [];
64
-
65
- function checkForResize(resizing = $rendering.resizing) {
66
- if (!node) return;
67
-
68
- let isWindowResize = resizing === SIZES.WINDOW;
69
- let isAspectResize = resizing === SIZES.ASPECT_RATIO;
70
- let canUpdate = isWindowResize || isAspectResize;
71
-
72
- if (canUpdate) {
73
- let newWidth, newHeight;
74
-
75
- if (isWindowResize) {
76
- newWidth = node.offsetWidth;
77
- newHeight = node.offsetHeight;
78
- } else if (isAspectResize) {
79
- const { offsetWidth, offsetHeight } = node;
80
- const aspectRatio = $rendering.aspectRatio;
81
- const monitorRatio = offsetWidth / offsetHeight;
82
-
83
- if (aspectRatio < monitorRatio) {
84
- newHeight = offsetHeight;
85
- newWidth = newHeight * aspectRatio;
86
- } else {
87
- newWidth = offsetWidth;
88
- newHeight = newWidth / aspectRatio;
89
- }
90
- }
91
-
92
- let needsUpdate =
93
- newWidth !== $rendering.width ||
94
- newHeight !== $rendering.height;
95
-
96
- if (needsUpdate) {
97
- rendering.update((curr) => {
98
- return {
99
- ...curr,
100
- width: newWidth,
101
- height: newHeight,
102
- };
103
- });
104
- }
105
- }
106
- }
107
-
108
- let resizeObserver = new ResizeObserver(() => {
109
- checkForResize();
110
- });
111
-
112
- let params = {};
10
+ import HintLoading from '../components/HintLoading.svelte';
11
+ import { untrack } from 'svelte';
113
12
 
114
- let sketchProps = derived(props, () => {
115
- return $props[key];
116
- });
13
+ let { key, id, visible = true } = $props();
117
14
 
118
- let needsRender = false;
15
+ /** @type {HTMLDivElement} */
16
+ let container;
119
17
 
120
- sketchProps.subscribe(() => {
121
- if (framerate === 0) {
122
- // ensure we don't double render from createSketch
123
- requestAnimationFrame(() => {
124
- needsRender = true;
125
- });
126
- }
127
- });
18
+ /** @type {Sketch} */
19
+ let sketch = $derived(sketchesManager.sketches[key]);
128
20
 
129
- layout.subscribe(() => {
130
- setBackgroundColor();
131
- });
21
+ /** @type {Render} */
22
+ let render = $derived(rendering.renders.find((r) => r.id === id));
132
23
 
133
- function createCanvas(canvas = document.createElement('canvas')) {
134
- canvas.onmousedown = (event) => checkForTriggersDown(event, key);
135
- canvas.onmousemove = (event) => checkForTriggersMove(event, key);
136
- canvas.onmouseup = (event) => checkForTriggersUp(event, key);
137
- canvas.onclick = (event) => checkForTriggersClick(event, key);
24
+ let loaded = $derived(
25
+ rendering.renders.find((r) => r.id === id)?.loaded ?? false,
26
+ );
138
27
 
139
- container.appendChild(canvas);
28
+ let paused = $derived(
29
+ (render?.paused ?? false) &&
30
+ !exports.recording &&
31
+ !__BUILD__ &&
32
+ !layout.previewing,
33
+ );
140
34
 
141
- $monitors = $monitors.map((monitor) => {
142
- if (monitor.id === id) {
143
- return { ...monitor, canvas };
144
- }
35
+ $effect(() => {
36
+ if (!sketch) return;
145
37
 
146
- return monitor;
38
+ const renderer = rendering.findRenderer({
39
+ renderingMode: sketch.instance.rendering,
147
40
  });
148
41
 
149
- return canvas;
150
- }
151
-
152
- function destroyCanvas(canvas) {
153
- canvas.onmousedown = null;
154
- canvas.onmousemove = null;
155
- canvas.onmouseup = null;
156
- canvas.onclick = null;
157
-
158
- if (canvas.parentNode === container) {
159
- canvas.parentNode.removeChild(canvas);
160
- }
161
-
162
- canvas = null;
163
- }
164
-
165
- function setBackgroundColor() {
166
- if (sketch) {
167
- if (
168
- ($layout.previewing || __BUILD__) &&
169
- sketch.buildConfig &&
170
- sketch.buildConfig.backgroundColor
171
- ) {
172
- backgroundColor = sketch.buildConfig.backgroundColor;
173
- } else if (!$layout.previewing && sketch.backgroundColor) {
174
- backgroundColor = sketch.backgroundColor;
175
- } else {
176
- backgroundColor = 'inherit';
177
- }
178
- } else {
179
- backgroundColor = 'inherit';
180
- }
181
- }
182
-
183
- async function createSketch(key) {
184
- _created = false;
185
-
186
- sketch?.dispose?.(params);
187
-
188
- sketch = $sketches[key];
189
-
190
- if (!key || !sketch) {
191
- _errored = true;
192
-
193
- if (_raf) {
194
- cancelAnimationFrame(_raf);
195
- _raf = null;
196
- }
197
-
198
- return;
199
- }
200
-
201
- clearError(key);
202
- setBackgroundColor();
203
-
204
- if (canvas) {
205
- if (renderer && typeof renderer.onDestroyPreview === 'function') {
206
- renderer.onDestroyPreview({ id, container, canvas });
207
- }
208
-
209
- destroyCanvas(canvas);
210
- }
211
-
212
- renderer = await findRenderer({
213
- rendering: sketch.rendering,
214
- renderer: sketch.renderer,
42
+ let render = new Render({
43
+ id,
44
+ container,
45
+ sketch,
46
+ renderer,
215
47
  });
216
48
 
217
- if (!container) return;
218
-
219
- canvas = createCanvas();
220
-
221
- if ($rendering.resizing === SIZES.SCALE) {
222
- canvas.style.transform = `scale(${$rendering.scale})`;
223
- } else {
224
- canvas.style.transform = null;
225
- }
226
-
227
- removeHotListeners(key);
228
- removeHooksFrom(key);
229
-
230
- let mountParams = {};
231
-
232
- if (renderer && typeof renderer.onMountPreview === 'function') {
233
- mountParams = renderer.onMountPreview({
234
- id,
235
- canvas,
236
- container,
237
- width: $rendering.width,
238
- height: $rendering.height,
239
- pixelRatio: $rendering.pixelRatio,
240
- });
241
- }
242
-
243
- if (mountParams.canvas && mountParams.canvas !== canvas) {
244
- destroyCanvas(canvas);
245
- canvas = createCanvas(mountParams.canvas);
246
- }
247
-
248
- params = {
249
- ...mountParams,
250
- canvas,
251
- publicPath: `@fs${__CWD__}`,
252
- };
253
-
254
- framerate = isFinite(sketch.fps) ? sketch.fps : 60;
255
-
256
- const init = sketch.setup || sketch.init || noop;
257
- const resize = sketch.resize || noop;
258
- const { width, height, pixelRatio } = $rendering;
49
+ untrack(() => rendering.renders.push(render));
259
50
 
260
- try {
261
- elapsedRenderingTime = 0;
51
+ return () => {
52
+ untrack(() => {
53
+ const index = rendering.renders.findIndex(
54
+ (r) => r.id === render.id,
55
+ );
262
56
 
263
- if (sketch.load) {
264
- await sketch.load({
265
- width,
266
- height,
267
- pixelRatio,
268
- props: $sketchProps,
269
- ...params,
270
- });
271
- }
272
-
273
- init({
274
- width,
275
- height,
276
- pixelRatio,
277
- props: $sketchProps,
278
- ...params,
279
- });
280
-
281
- resize({
282
- canvas,
283
- width,
284
- height,
285
- pixelRatio,
286
- props: $sketchProps,
287
- ...params,
288
- });
289
-
290
- _created = true;
291
- _errored = false;
292
-
293
- _renderSketch = createRenderLoop();
294
-
295
- requestAnimationFrame(() => {
296
- needsRender = true;
297
-
298
- if (!_raf) {
299
- render();
57
+ if (index >= 0) {
58
+ rendering.renders.splice(index, 1);
300
59
  }
301
60
  });
302
- } catch (error) {
303
- onError(error);
304
- }
305
- }
306
-
307
- /**
308
- *
309
- * @param {Error} error
310
- */
311
- function onError(error) {
312
- _errored = true;
313
- console.error(error);
314
-
315
- displayError(error, key);
316
-
317
- cancelAnimationFrame(_raf);
318
- _raf = null;
319
- }
320
-
321
- let record = $recording;
322
- let capture = $capturing;
323
-
324
- $: {
325
- const recordArgs = {
326
- encoding: $exports.videoFormat,
327
- quality: $exports.videoQuality,
328
- framerate: $exports.framerate,
329
- };
330
-
331
- function onRecordEnd() {
332
- record = null;
333
- paused = false;
334
-
335
- afterRecordCallbacks.forEach((callback) => {
336
- callback(recordArgs);
337
- });
338
-
339
- _renderSketch();
340
- }
341
-
342
- if ($recording && !record) {
343
- let recordOptions = {
344
- onTick: _renderSketch,
345
- framerate: $exports.framerate,
346
- filename: key,
347
- exportDir: sketch?.exportDir,
348
- pattern: sketch?.filenamePattern,
349
- format: $exports.videoFormat,
350
- imageEncoding: $exports.imageEncoding,
351
- quality: $exports.videoQuality,
352
- params: {
353
- props: sketch?.props,
354
- },
355
- onStart: () => {
356
- beforeRecordCallbacks.forEach((callback) => {
357
- callback(recordArgs);
358
- });
359
-
360
- elapsedRenderingTime = 0;
361
- paused = true;
362
- },
363
- onComplete: () => {
364
- $recording = false;
365
- onRecordEnd();
366
- },
367
- };
368
-
369
- if ($exports.useDuration) {
370
- recordOptions.duration = sketch.duration * $exports.loopCount;
371
- }
372
-
373
- record = recordCanvas(canvas, recordOptions);
374
- }
375
-
376
- if (record && !$recording) {
377
- record.stop();
378
- }
379
- }
380
-
381
- $: {
382
- if (!capture && $capturing) {
383
- save();
384
- }
385
- }
386
-
387
- function createRenderLoop() {
388
- const { width, height, pixelRatio } = $rendering;
389
- const draw = sketch.draw || sketch.update;
390
- const { duration } = sketch;
391
-
392
- let playhead = NaN;
393
- let playcount = NaN;
394
- let frame = NaN;
395
- let hasDuration = isFinite(duration);
396
-
397
- let onBeforeUpdatePreview =
398
- (renderer && renderer.onBeforeUpdatePreview) || noop;
399
- let onAfterUpdatePreview =
400
- (renderer && renderer.onAfterUpdatePreview) || noop;
401
-
402
- let frameLength = 1000 / framerate;
403
- let frameCount = framerate * duration;
404
- let interval = 1 / frameCount;
405
-
406
- return ({
407
- time = performance.now(),
408
- deltaTime = time - lastTime,
409
- } = {}) => {
410
- needsRender = false;
411
- lastTime = time;
412
-
413
- try {
414
- onBeforeUpdatePreview({ id, canvas, container });
415
-
416
- let t = !$sync
417
- ? elapsedRenderingTime
418
- : Math.floor(time / frameLength) * frameLength;
419
-
420
- if (hasDuration && framerate > 0) {
421
- playhead = t / 1000 / duration;
422
- playhead %= 1;
423
- playhead = Math.floor(playhead / interval) * interval;
424
- playcount = Math.floor(
425
- elapsedRenderingTime / 1000 / duration,
426
- );
427
-
428
- frame = Math.floor(map(playhead, 0, 1, 1, frameCount + 1));
429
- }
430
61
 
431
- draw({
432
- ...renderer,
433
- ...params,
434
- props: $sketchProps,
435
- playhead,
436
- playcount,
437
- frame,
438
- width,
439
- height,
440
- pixelRatio,
441
- time: t,
442
- deltaTime,
443
- });
444
- onAfterUpdatePreview({ id, canvas, container });
445
-
446
- elapsedRenderingTime += deltaTime;
447
- } catch (error) {
448
- onError(error);
449
- }
62
+ render.dispose();
450
63
  };
451
- }
452
-
453
- function render() {
454
- _raf = requestAnimationFrame(render);
455
-
456
- now = performance.now();
457
- dt = now - then;
458
- then = now;
459
-
460
- if (!paused) {
461
- elapsed += dt;
462
-
463
- if (!$sync) {
464
- if (elapsed >= (1 / framerate) * 1000 && _created) {
465
- elapsed = 0;
466
- _renderSketch();
467
- }
468
- } else {
469
- _renderSketch();
470
- }
471
- } else {
472
- lastTime = now;
473
- }
474
-
475
- if (needsRender && _created) {
476
- _renderSketch();
477
- }
478
- }
479
-
480
- $: {
481
- if (canvas && _key !== key) {
482
- if (_created) {
483
- clearError(_key);
484
- }
485
-
486
- _key = key;
487
- createSketch(key);
488
- }
489
- }
490
-
491
- async function save() {
492
- paused = true;
493
-
494
- const {
495
- imageCount = 1,
496
- imageEncoding,
497
- imageQuality,
498
- pixelsPerInch,
499
- } = $exports;
500
-
501
- const captureArgs = {
502
- encoding: imageEncoding,
503
- quality: imageQuality,
504
- pixelsPerInch,
505
- count: imageCount,
506
- };
507
-
508
- for (let i = 0; i < imageCount; i++) {
509
- beforeCaptureCallbacks.forEach((callback) => {
510
- callback({ ...captureArgs, index: i });
511
- });
512
-
513
- _renderSketch();
514
-
515
- await screenshotCanvas(canvas, {
516
- filename: key,
517
- pattern: sketch?.filenamePattern,
518
- exportDir: sketch?.exportDir,
519
- index: imageCount > 1 ? i : undefined,
520
- params: {
521
- props: sketch?.props,
522
- },
523
- });
524
- paused = false;
525
- $capturing = false;
526
-
527
- afterCaptureCallbacks.forEach((callback) => {
528
- callback({ ...captureArgs, index: i });
529
- });
64
+ });
530
65
 
531
- _renderSketch();
66
+ function checkForRefresh(event) {
67
+ if (!event.metaKey && !event.ctrlKey) {
68
+ event.preventDefault();
69
+ render.reset();
532
70
  }
533
71
  }
534
72
 
535
- sync.subscribe(() => {
536
- if (_created) {
537
- _renderSketch = createRenderLoop();
538
- }
539
- });
540
-
541
- onMount(() => {
542
- createSketch(key);
543
-
544
- sketches.subscribe(() => {
545
- if (_created || _errored) {
546
- createSketch(key);
547
- }
548
- });
549
-
550
- client.on('shader-update', () => {
551
- if (framerate === 0) {
552
- needsRender = true;
553
- }
554
- });
555
-
556
- resizeObserver.observe(node);
557
- });
558
-
559
73
  function checkForPause(event) {
560
- const keyboardEvent = event.detail;
561
-
562
- if (!keyboardEvent.metaKey || !keyboardEvent.ctrlKey) {
563
- keyboardEvent.preventDefault();
74
+ if (!event.metaKey || !event.ctrlKey) {
75
+ event.preventDefault();
564
76
 
565
- if (!$recording) {
566
- then = performance.now();
567
- paused = !paused;
77
+ if (!exports.recording) {
78
+ render.paused = !render.paused;
568
79
  } else {
569
- console.warn(`Cannot pause while recording.`);
80
+ console.warn(`Fragment can't be paused while recording.`);
570
81
  }
571
82
  }
572
83
  }
573
84
 
574
- function checkForSave(event) {
575
- const keyboardEvent = event.detail;
576
-
577
- if (keyboardEvent.metaKey || keyboardEvent.ctrlKey) {
578
- keyboardEvent.preventDefault();
85
+ function checkForScreenshot(event) {
86
+ if (event.metaKey || event.ctrlKey) {
87
+ event.preventDefault();
579
88
 
580
- if (!$recording) {
581
- save();
89
+ if (!exports.recording) {
90
+ render.screenshot();
582
91
  } else {
583
- console.warn(`Cannot save while recording.`);
92
+ console.warn(`Fragment can't screenshot while recording.`);
584
93
  }
585
94
  }
586
95
  }
587
96
 
588
97
  function checkForRecord(event) {
589
- const keyboardEvent = event.detail;
590
- keyboardEvent.preventDefault();
591
-
592
- $recording = !$recording;
593
- }
98
+ if (event.shiftKey) {
99
+ exports.recording = !exports.recording;
594
100
 
595
- function checkForRefresh(event) {
596
- const keyboardEvent = event.detail;
597
- if (!keyboardEvent.metaKey && !keyboardEvent.ctrlKey) {
598
- keyboardEvent.preventDefault();
599
- resetProps(key, {
600
- width: $rendering.width,
601
- height: $rendering.height,
602
- pixelRatio: $rendering.pixelRatio,
603
- });
604
- console.log(`[fragment] ${key} reloaded.`);
605
- createSketch(key);
101
+ if (exports.recording && !render.recording) {
102
+ render.startRecording();
103
+ } else if (render.recording && !exports.recording) {
104
+ render.stopRecording();
105
+ }
606
106
  }
607
107
  }
608
108
 
609
- onDestroy(() => {
610
- resizeObserver.unobserve(node);
611
- cancelAnimationFrame(_raf);
612
-
613
- if (renderer && typeof renderer.onDestroyPreview === 'function') {
614
- renderer.onDestroyPreview({ id, canvas, container });
615
- }
616
-
617
- renderer = null;
618
-
619
- if (canvas) {
620
- destroyCanvas(canvas);
109
+ let backgroundColor = $derived.by(() => {
110
+ if (layout.previewing) {
111
+ return sketch?.buildConfig?.backgroundColor ?? 'inherit';
621
112
  }
622
113
 
623
- _created = false;
114
+ return sketch?.backgroundColor ?? 'inherit';
624
115
  });
625
-
626
- $: {
627
- checkForResize();
628
-
629
- const { width, height, pixelRatio, resizing, scale } = $rendering;
630
-
631
- if (renderer && typeof renderer.onResizePreview === 'function') {
632
- renderer.onResizePreview({
633
- id,
634
- container,
635
- width,
636
- height,
637
- pixelRatio,
638
- ...params,
639
- });
640
- }
641
-
642
- if (canvas) {
643
- if (resizing === SIZES.SCALE) {
644
- canvas.style.transform = `scale(${scale})`;
645
- } else {
646
- canvas.style.transform = null;
647
- }
648
-
649
- if (_created) {
650
- sketch?.resize?.({
651
- canvas,
652
- width,
653
- height,
654
- pixelRatio,
655
- ...params,
656
- });
657
-
658
- _renderSketch = createRenderLoop();
659
- _renderSketch();
660
- }
661
- }
662
- }
663
-
664
- $: error =
665
- key && $errors.has(key)
666
- ? $errors.get(key) // display error if error context match current key
667
- : $errors.size === 1 &&
668
- ![...$errors.keys()].some((key) =>
669
- $sketchesKeys.includes(key),
670
- ) &&
671
- ($monitors.length === 1 || // if there's only one monitor
672
- !$monitors.some(
673
- (m) => m.selected === $errors.keys().next().value,
674
- )) // if none of current monitors match the key
675
- ? $errors.get($errors.keys().next().value)
676
- : null;
677
-
678
- $: isSquare = $rendering.width === $rendering.height;
679
- $: isLandscape = $rendering.width > $rendering.height;
680
- $: isPortrait = $rendering.width < $rendering.height;
681
116
  </script>
682
117
 
683
118
  <div
684
- bind:this={node}
685
119
  class="sketch-renderer"
686
120
  class:visible
687
- class:recording={$recording}
688
121
  style={`--background-color: ${backgroundColor}`}
689
122
  >
690
123
  <div
691
124
  class="canvas-container"
692
- style="--aspect-ratio: {$rendering.width} / {$rendering.height}; --aspect-ratio-inverse: {$rendering.height} / {$rendering.width}; --width: {$rendering.width}px; --height: {$rendering.height}px;"
125
+ style="--aspect-ratio: {rendering.width} / {rendering.height}; --aspect-ratio-inverse: {rendering.height} / {rendering.width}; --width: {rendering.width}px; --height: {rendering.height}px; {rendering.resizing ===
126
+ SIZES.SCALE
127
+ ? `--scale: ${rendering.scale}`
128
+ : ''}"
693
129
  bind:this={container}
694
- />
695
- {#if $recording}
696
- <span class="record">REC</span>
130
+ ></div>
131
+ {#if exports.recording}
132
+ <HintRecord />
133
+ {/if}
134
+ {#if paused}
135
+ <HintPaused />
136
+ {/if}
137
+ {#if !loaded}
138
+ <HintLoading />
697
139
  {/if}
698
140
  </div>
699
- <KeyBinding type="down" key=" " on:trigger={checkForPause} />
700
- <KeyBinding type="down" key="r" on:trigger={checkForRefresh} />
701
- <KeyBinding type="down" key="s" on:trigger={checkForSave} />
702
- <KeyBinding type="down" key="S" on:trigger={checkForRecord} />
703
141
 
704
- {#if error}
705
- <ErrorOverlay {error} />
706
- {/if}
142
+ <KeyBinding type="down" key="r" onTrigger={checkForRefresh} />
143
+ <KeyBinding type="down" key=" " onTrigger={checkForPause} />
144
+ <KeyBinding type="down" key="s" onTrigger={checkForScreenshot} />
145
+ <KeyBinding type="down" key="S" onTrigger={checkForRecord} />
707
146
 
708
147
  <style>
709
148
  .sketch-renderer {
149
+ position: relative;
710
150
  display: flex;
711
151
  width: 100%;
712
152
  height: 100%;
@@ -731,8 +171,6 @@
731
171
 
732
172
  width: var(--w);
733
173
  height: calc(var(--w) * var(--aspect-ratio-inverse));
734
-
735
- background-color: red;
736
174
  }
737
175
 
738
176
  :global(.canvas-container canvas) {
@@ -744,56 +182,6 @@
744
182
  height: 100% !important;
745
183
 
746
184
  background-color: var(--background-color, #000000);
747
- }
748
-
749
- .sketch-renderer.recording .canvas-container {
750
- opacity: 0.5;
751
- }
752
-
753
- .record {
754
- position: absolute;
755
- top: 4px;
756
- right: 4px;
757
- z-index: 2;
758
-
759
- display: flex;
760
- place-items: center;
761
-
762
- height: 16px;
763
- padding: 0 2px;
764
-
765
- color: var(--color-red);
766
- font-size: 10px;
767
-
768
- border: 1px solid var(--color-red);
769
- border-radius: 2px;
770
- }
771
-
772
- .record:before {
773
- --size: 6px;
774
- content: '';
775
-
776
- width: var(--size);
777
- height: var(--size);
778
- margin: 0 3px 0 1px;
779
-
780
- background-color: var(--color-red);
781
- border-radius: 50%;
782
-
783
- animation: fade 1s ease-in-out infinite;
784
- }
785
-
786
- @keyframes fade {
787
- 0% {
788
- opacity: 0;
789
- }
790
-
791
- 50% {
792
- opacity: 1;
793
- }
794
-
795
- 100% {
796
- opacity: 0;
797
- }
185
+ transform: scale(var(--scale));
798
186
  }
799
187
  </style>