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,112 @@
1
+ <script context="module">
2
+ import { writable } from "svelte/store";
3
+
4
+ export const params = writable([]);
5
+
6
+ let ID = 0;
7
+
8
+ </script>
9
+
10
+ <script>
11
+ import { onMount, onDestroy } from "svelte";
12
+ import { props } from "../stores";
13
+ import { sketches } from "../stores/sketches.js";
14
+ import { monitors } from "../stores/rendering";
15
+ import Module from "../ui/Module.svelte";
16
+ import Field from "../ui/Field.svelte";
17
+ import OutputParams from "../ui/ParamsOutput.svelte";
18
+ import ModuleHeaderAction from "../ui/ModuleHeaderAction.svelte";
19
+
20
+ export let mID;
21
+ export let hasHeader = true;
22
+ export let output = true;
23
+
24
+ let id = ID++;
25
+ let selected = id;
26
+ let sketch, sketchKey, sketchProps = {};
27
+ let monitor, showOutputParams;
28
+
29
+ onMount(() => {
30
+ $params = [
31
+ ...$params,
32
+ {
33
+ id,
34
+ }
35
+ ];
36
+ });
37
+
38
+ onDestroy(() => {
39
+ $params = $params.filter((p) => p.id !== id);
40
+ });
41
+
42
+ $: options = [
43
+ ...$monitors.map((monitor, index) => {
44
+ return { value: index, label: `monitor ${index + 1}`}
45
+ }),
46
+ ...$params.length > 1 ? [{ value: "output", label: "output"}] : [],
47
+ ];
48
+
49
+ monitors.subscribe((value) => {
50
+ monitor = $monitors[Math.min(selected, $monitors.length - 1)];
51
+ sketchKey = monitor ? monitor.selected : undefined;
52
+ });
53
+
54
+ $: {
55
+ sketch = $sketches[sketchKey];
56
+ sketchProps = $props[sketchKey];
57
+ }
58
+
59
+ $: showOutputParams = (monitor && monitor.selected === "output") ||
60
+ ($params.length === 1) ||
61
+ (selected === "output");
62
+
63
+ </script>
64
+
65
+ <Module {mID} {hasHeader} name={`Parameters`} slug="params" >
66
+ <div slot="header-right">
67
+ {#if options.length > 1 }
68
+ <ModuleHeaderAction
69
+ value={selected}
70
+ permanent
71
+ border
72
+ on:change={(event) => selected = event.detail}
73
+ options={options}
74
+ />
75
+ {/if }
76
+ </div>
77
+ {#if showOutputParams && output }
78
+ <OutputParams />
79
+ {/if}
80
+
81
+ {#if sketch }
82
+ {#if typeof props === "object"}
83
+ {#if output}
84
+ <Field key="framerate" value={isFinite(sketch.fps) ? sketch.fps : 60} params={{disabled: true}}/>
85
+ {/if}
86
+ {#if sketch.duration && sketch.duration > 0 && output }
87
+ <Field key="duration" value={sketch.duration} params={{disabled: true, suffix: "s"}}/>
88
+ {/if }
89
+ {#each Object.keys(sketchProps) as key, i}
90
+ {#if !sketchProps[key].hidden}
91
+ <Field
92
+ context={sketchKey}
93
+ key={key}
94
+ value={sketchProps[key].value}
95
+ params={sketchProps[key].params || {}}
96
+ type={sketchProps[key].type}
97
+ on:click={() => {
98
+ $props[sketchKey][key].value._refresh = true;
99
+ }}
100
+ on:change={(event) => {
101
+ $props[sketchKey][key].value = event.detail;
102
+
103
+ if (typeof $props[sketchKey][key].onChange === 'function') {
104
+ $props[sketchKey][key].onChange($props[sketchKey][key]);
105
+ }
106
+ }}
107
+ />
108
+ {/if}
109
+ {/each}
110
+ {/if}
111
+ {/if}
112
+ </Module>
@@ -0,0 +1,5 @@
1
+ export let onMountPreview = ({ canvas }) => {
2
+ return {
3
+ context: canvas.getContext("2d"),
4
+ }
5
+ };
@@ -0,0 +1,62 @@
1
+ import { fragment } from "../lib/gl";
2
+ import { client } from "@fragment/client";
3
+ import { getShaderPath } from "../utils/glsl.utils";
4
+ import { clearError } from "../stores/errors";
5
+
6
+ let frags = [];
7
+
8
+ export let onMountPreview = ({ canvas, id }) => {
9
+ let frag = fragment({
10
+ canvas,
11
+ });
12
+
13
+ frags.push({
14
+ id,
15
+ frag,
16
+ });
17
+
18
+ return { frag };
19
+ };
20
+
21
+ export let onResizePreview = ({ id, width, height, pixelRatio }) => {
22
+ let { frag } = frags.find(f => f.id === id);
23
+
24
+ frag.resize({ width, height, pixelRatio });
25
+ };
26
+
27
+ export let onDestroyPreview = ({ canvas, id }) => {
28
+ let fragIndex = frags.findIndex(f => f.id === id);
29
+ let { frag } = frags[fragIndex];
30
+
31
+ clearError(frag.gl.__uuid);
32
+
33
+ frag.destroy();
34
+ frags.splice(fragIndex, 1);
35
+ };
36
+
37
+ client.on('shader-update', (data) => {
38
+ frags.forEach(({ frag }) => clearError(frag.gl.__uuid));
39
+
40
+ const { filepath, source } = data;
41
+
42
+ const programs = frags.map(({ frag }) => frag.program);
43
+
44
+ programs.forEach((program) => {
45
+ const { fragment, vertex } = program;
46
+
47
+ const shaders = {
48
+ vertexShader: vertex,
49
+ fragmentShader: fragment
50
+ };
51
+
52
+ Object.keys(shaders).forEach((key) => {
53
+ const shaderPath = getShaderPath(shaders[key]);
54
+
55
+ if (shaderPath === filepath) {
56
+ console.log(`[fragment] shader update ${shaderPath.replace(__CWD__, "")}`);
57
+ program[key] = source;
58
+ program.needsUpdate = true;
59
+ }
60
+ });
61
+ });
62
+ });
File without changes
@@ -0,0 +1,39 @@
1
+ import p5 from "p5";
2
+
3
+ let previews = [];
4
+
5
+ export let onMountPreview = ({ id, width, height }) => {
6
+ const p = new p5((sketch) => {
7
+ sketch.setup = () => {
8
+ sketch.createCanvas(width, height);
9
+ }
10
+ });
11
+
12
+ const preview = {
13
+ id,
14
+ p,
15
+ };
16
+
17
+ previews.push(preview);
18
+
19
+ return {
20
+ canvas: p.canvas,
21
+ p,
22
+ };
23
+ };
24
+
25
+ export let onResizePreview = ({ id, width, height, pixelRatio }) => {
26
+ const preview = previews.find(p => p.id === id);
27
+
28
+ if (preview) {
29
+ preview.p.resizeCanvas(width * pixelRatio, height * pixelRatio, false);
30
+ }
31
+ };
32
+
33
+ export let onDestroyPreview = ({ id }) => {
34
+ const preview = previews.find(p => p.id === id);
35
+
36
+ if (preview) {
37
+ preview.p.remove();
38
+ }
39
+ };
@@ -0,0 +1,128 @@
1
+ import { WebGLRenderer, Scene } from "three";
2
+ import { Texture, fragment } from "@fragment/lib/gl";
3
+ import { client } from "@fragment/client";
4
+ import { getShaderPath } from "../utils/glsl.utils";
5
+ import { clearError } from "../stores/errors";
6
+
7
+ let renderer;
8
+ let previews = [];
9
+ let fragmentShader = /* glsl */`
10
+ precision highp float;
11
+ uniform sampler2D uSampler;
12
+ varying vec2 vUv;
13
+
14
+ void main() {
15
+ vec3 mapTexel = texture2D(uSampler, vUv).rgb;
16
+ gl_FragColor = vec4(mapTexel, 1.);
17
+ }
18
+ `;
19
+
20
+ export let init = ({ canvas }) => {
21
+ renderer = new WebGLRenderer({ antialias: true });
22
+
23
+ return {
24
+ renderer,
25
+ };
26
+ };
27
+
28
+ export let onMountPreview = ({ id, canvas, width, height, pixelRatio }) => {
29
+ let { gl, render, resize, uniforms, destroy } = fragment({
30
+ canvas,
31
+ shader: fragmentShader,
32
+ uniforms: {
33
+ uSampler: { value: null, type: "sampler2D" },
34
+ },
35
+ });
36
+
37
+ let texture = new Texture(gl, {
38
+ image: renderer.domElement,
39
+ });
40
+
41
+ uniforms.uSampler.value = texture;
42
+
43
+ let scene = new Scene();
44
+
45
+ previews.push({
46
+ id,
47
+ scene,
48
+ texture,
49
+ render,
50
+ resize,
51
+ destroy,
52
+ });
53
+
54
+ return {
55
+ scene,
56
+ renderer,
57
+ };
58
+ };
59
+
60
+ export let onDestroyPreview = ({ id, canvas }) => {
61
+ const previewIndex = previews.findIndex(p => p.id === id);
62
+ const preview = previews[previewIndex];
63
+
64
+ clearError(renderer.getContext().__uuid);
65
+
66
+ if (preview) {
67
+ preview.texture.destroy();
68
+ preview.destroy();
69
+ previews.splice(previewIndex, 1);
70
+ }
71
+ };
72
+
73
+ export let onAfterUpdatePreview = ({ id }) => {
74
+ const preview = previews.find(p => p.id === id);
75
+
76
+ if (preview) {
77
+ preview.texture.needsUpdate = true;
78
+ preview.render();
79
+ }
80
+ };
81
+
82
+ export let resize = ({ width, height, pixelRatio }) => {
83
+ renderer.setPixelRatio(pixelRatio);
84
+ renderer.setSize(width, height);
85
+
86
+ for (let i = 0; i < previews.length; i++) {
87
+ const preview = previews[i];
88
+ preview.resize({ width, height, pixelRatio });
89
+ }
90
+ };
91
+
92
+ /* HOT SHADER RELOADING */
93
+ client.on('shader-update', (data) => {
94
+ clearError(renderer.getContext().__uuid);
95
+ const { filepath, source } = data;
96
+
97
+ const scenes = previews.map((preview) => preview.scene);
98
+ const materials = [];
99
+
100
+ scenes.forEach(scene => {
101
+ scene.traverse((child) => {
102
+ if (child.material) {
103
+ const { material } = child;
104
+
105
+ if (material.isShaderMaterial || material.isRawShaderMaterial) {
106
+ materials.push(material);
107
+ }
108
+ }
109
+ })
110
+ });
111
+
112
+ materials.forEach(material => {
113
+ const { vertexShader, fragmentShader } = material;
114
+
115
+ Object.keys({ vertexShader, fragmentShader }).forEach((key) => {
116
+ const shader = material[key];
117
+ const shaderPath = getShaderPath(shader);
118
+
119
+ if (shaderPath === filepath) {
120
+ console.log(`[fragment] shader update ${shaderPath.replace(__CWD__, "")}`);
121
+ material[key] = source;
122
+ material.needsUpdate = true;
123
+ }
124
+ });
125
+ });
126
+
127
+
128
+ });
@@ -0,0 +1,10 @@
1
+ import { readable } from "svelte/store";
2
+ import Tempo from "../lib/tempo/index.js";
3
+
4
+ export const audioAnalysis = new Tempo({
5
+ });
6
+ audioAnalysis.listen();
7
+
8
+ window.audioAnalysis = audioAnalysis;
9
+
10
+ export const tempo = readable(audioAnalysis);
@@ -0,0 +1,76 @@
1
+ import { writable } from "svelte/store";
2
+ import { tree, traverse } from "./layout";
3
+
4
+ export const logs = writable([]);
5
+
6
+ let mirrored = ["log", "warn", "error", "dir"];
7
+ let enabled = false;
8
+ let refs = {};
9
+
10
+ tree.subscribe((t) => {
11
+ let hasConsole = false;
12
+ traverse((c) => {
13
+ if (c.type === "module" && c.name === "console") {
14
+ hasConsole = true;
15
+ }
16
+ }, t);
17
+
18
+ if (hasConsole && !enabled) {
19
+ enable();
20
+ } else if (enabled && !hasConsole) {
21
+ disable();
22
+ }
23
+ });
24
+
25
+ let clear = console.clear;
26
+
27
+ function enable() {
28
+ enabled = true;
29
+ mirrored.forEach((key) => {
30
+ const ref = console[`${key}`]
31
+ refs[`${key}`] = ref;
32
+
33
+ console[`${key}`] = (...args) => {
34
+ let isFromVite = args.some((log) => typeof log === "string" && log.includes('[vite]'));
35
+
36
+ if (!isFromVite) {
37
+ ref(...args);
38
+ }
39
+
40
+ logs.update((logs) => {
41
+ if (isFromVite) return logs;
42
+
43
+ if (logs.length > 0) {
44
+ const lastLog = logs[logs.length - 1];
45
+ const { level: lastLevel, args: lastArgs } = lastLog;
46
+
47
+ if (lastLevel === key && lastArgs[0] === args[0]) {
48
+ logs[logs.length - 1].count++;
49
+ return logs;
50
+ }
51
+ }
52
+
53
+ return [
54
+ ...logs,
55
+ { level: key, args, count: 1 },
56
+ ];
57
+ });
58
+ };
59
+ });
60
+
61
+ console.clear = () => {
62
+ clear();
63
+ logs.update(() => []);
64
+ };
65
+ }
66
+
67
+ function disable() {
68
+ enabled = false;
69
+ mirrored.forEach((key) => {
70
+ const ref = refs[key];
71
+
72
+ console[`${key}`] = ref;
73
+ });
74
+
75
+ console.clear = clear;
76
+ }
@@ -0,0 +1,25 @@
1
+ import { createStore } from "./utils";
2
+
3
+ export const errors = createStore('errors', new Map());
4
+
5
+ export function displayError(error, context) {
6
+ errors.update((current) => {
7
+ current.set(context, error);
8
+
9
+ return current;
10
+ });
11
+ }
12
+
13
+ export function clearError(context) {
14
+ errors.update((current) => {
15
+ if (current.has(context)) {
16
+ current.delete(context);
17
+ }
18
+
19
+ return current;
20
+ });
21
+ }
22
+
23
+ export function clearErrors() {
24
+ errors.update(() => new Map());
25
+ }
@@ -0,0 +1,28 @@
1
+ import { writable } from "svelte/store";
2
+ import { createStore } from "./utils";
3
+
4
+ export const IMAGE_ENCODINGS = ["png", "jpeg", "webp"];
5
+
6
+ export const VIDEO_FORMATS = {
7
+ FRAMES: "frames",
8
+ MP4: "mp4",
9
+ GIF: "gif",
10
+ WEBM: "webm",
11
+ };
12
+
13
+ export const exports = createStore(`exports`, {
14
+ imageEncoding: IMAGE_ENCODINGS[0],
15
+ videoFormat: Object.values(VIDEO_FORMATS)[0],
16
+ pixelsPerInch: 72,
17
+ framerate: 60,
18
+ useDuration: true,
19
+ loopCount: 1,
20
+ imageQuality: 100,
21
+ videoQuality: 100,
22
+ }, {
23
+ persist: !__PRODUCTION__,
24
+ reset: false,
25
+ });
26
+
27
+ export const recording = writable(false);
28
+ export const capturing = writable(false);
@@ -0,0 +1,2 @@
1
+ export { props } from "./props";
2
+ export { exports } from "./exports";
@@ -0,0 +1,187 @@
1
+ import { writable, get } from "svelte/store";
2
+ import { getStore, createStore } from "./utils";
3
+ import { onMount } from "svelte";
4
+
5
+ export const tree = getStore("layout.current", {}, {
6
+ persist: !__PRODUCTION__
7
+ });
8
+
9
+ export const layout = createStore('layout', {
10
+ editing: false,
11
+ previewing: false,
12
+ registerChild: (component, children) => {
13
+ onMount(() => {
14
+ component.children = children();
15
+
16
+ if (component.root) {
17
+ tree.set(cleanNodes(component));
18
+ }
19
+ });
20
+ },
21
+ });
22
+
23
+ function cleanNodes(value) {
24
+ return JSON.parse(JSON.stringify(value, (key, value) => {
25
+ if (!(value instanceof HTMLElement)) {
26
+ return value;
27
+ }
28
+ }));
29
+ }
30
+
31
+ export function traverse(fn = () => {}, node = get(tree)) {
32
+ const { children = [] } = node;
33
+
34
+ fn(node);
35
+
36
+ for (let i = 0; i < children.length; i++) {
37
+ const child = children[i];
38
+ traverse(fn, child);
39
+ }
40
+ };
41
+
42
+ export const replaceChildren = (component, newChildren) => {
43
+ tree.update((t) => {
44
+ traverse((c) => {
45
+ if (c.id === component.id) {
46
+ c.children = newChildren;
47
+ }
48
+ }, t);
49
+
50
+ return t;
51
+ });
52
+ };
53
+
54
+ export const swapRoot = (newRoot) => {
55
+ tree.update((t) => {
56
+ traverse((c) => {
57
+ if (!c.root && c.type !== "module") {
58
+ c.depth = c.depth + 1;
59
+ }
60
+ }, newRoot);
61
+
62
+ return newRoot;
63
+ })
64
+ };
65
+
66
+ export const addSibling = (component, sibling) => {
67
+ tree.update((t) => {
68
+ traverse((c) => {
69
+ if (c.id === component.parent) {
70
+ const index = c.children.findIndex( k => k.id === component.id);
71
+
72
+ const { size } = c.children[index];
73
+ c.children[index].size = size * 0.5;
74
+ sibling.size = size * 0.5;
75
+
76
+ const newChildren = [
77
+ ...c.children,
78
+ ];
79
+
80
+ newChildren.splice(index + 1, 0, sibling);
81
+
82
+ c.children = newChildren;
83
+ }
84
+ });
85
+
86
+ return t;
87
+ })
88
+ };
89
+
90
+ export const addChildren = (component, newChild) => {
91
+ tree.update((t) => {
92
+ traverse((c) => {
93
+ if (c.id === component.id) {
94
+ c.children = [
95
+ ...c.children,
96
+ newChild,
97
+ ];
98
+ }
99
+ }, t);
100
+
101
+ return t;
102
+ })
103
+ };
104
+
105
+ export const remove = (node) => {
106
+ tree.update((t) => {
107
+ traverse((c) => {
108
+ const { children = [] } = c;
109
+ const childIndex = children.findIndex( k => k.id === node.id);
110
+
111
+ if (childIndex >= 0) {
112
+ const newChildren = [...children];
113
+ newChildren.splice(childIndex, 1);
114
+
115
+ newChildren.forEach((k) => {
116
+ k.size = 1. / newChildren.length;
117
+ });
118
+
119
+ if (newChildren.length === 0) {
120
+ remove(c);
121
+ }
122
+
123
+ c.children = newChildren;
124
+ }
125
+ }, t);
126
+
127
+ return t;
128
+ });
129
+ };
130
+
131
+ /**
132
+ * Assign new or reassign existing properties to an exisiting component in the lauout
133
+ * @param {Number} id - the id of the component to update
134
+ * @param {object} newProperties - the new properties to assign to the component
135
+ */
136
+ export const updateComponent = (component, newProperties = {}) => {
137
+ tree.update((t) => {
138
+ let updated = false;
139
+
140
+ traverse((c) => {
141
+ if (c.id === component.id) {
142
+ updated = true;
143
+ if (typeof newProperties === "object") {
144
+ Object.assign(c, newProperties);
145
+ } else if (typeof newProperties === "function") {
146
+ Object.assign(c, newProperties(c));
147
+ }
148
+ }
149
+ }, t);
150
+
151
+ if (!updated) {
152
+ console.warn(`Cannot find component to update with id ${component.id}`);
153
+ }
154
+
155
+ return t;
156
+ });
157
+ };
158
+
159
+ export const updateModule = (m, newProperties = {}) => {
160
+ tree.update((t) => {
161
+ traverse((c) => {
162
+ if (c.mID === m.mID) {
163
+ if (typeof newProperties === "object") {
164
+ Object.assign(c, newProperties);
165
+ } else if (typeof newProperties === "function") {
166
+ Object.assign(c, newProperties(c));
167
+ }
168
+ }
169
+ }, t);
170
+
171
+ return t;
172
+ });
173
+ };
174
+
175
+ export const resize = (nodes = []) => {
176
+ tree.update((t) => {
177
+ traverse((c) => {
178
+ nodes.forEach(n => {
179
+ if (n.id === c.id) {
180
+ c.size = n.size;
181
+ }
182
+ });
183
+ }, t);
184
+
185
+ return t;
186
+ });
187
+ };
@@ -0,0 +1,16 @@
1
+ import { createStore } from "./utils";
2
+
3
+ export const multisampling = createStore("multisampling", [], {
4
+ persist: !__PRODUCTION__,
5
+ reset: true,
6
+ });
7
+
8
+ export const threshold = createStore("threshold", 0, {
9
+ persist: !__PRODUCTION__,
10
+ reset: false,
11
+ });
12
+
13
+ export const transition = createStore("transition", false, {
14
+ persist: !__PRODUCTION__,
15
+ reset: false,
16
+ });