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,254 @@
1
+ <script>
2
+ import JSONTree from 'svelte-json-tree';
3
+ // import ConsoleTable from './ConsoleTable.svelte';
4
+
5
+ export let log;
6
+ export let level = 1;
7
+
8
+ function toggleGroupCollapse() {
9
+ log.collapsed = !log.collapsed;
10
+ }
11
+ </script>
12
+
13
+ <!-- {#if log.level === 'table'}
14
+ <ConsoleTable data={log.args[0]} columns={log.args[1]} />
15
+ {/if} -->
16
+
17
+ <div class="log console-{log.level}" style="padding-left: {level * 8}px" on:click={log.level === 'group' ? toggleGroupCollapse : undefined}>
18
+ {#if log.count > 1}
19
+ <div class="count">
20
+ <span>{log.count}</span>
21
+ </div>
22
+ {/if}
23
+
24
+ {#if log.level === 'trace' || log.level === 'assert'}
25
+ <div class="arrow" class:expand={!log.collapsed} on:click={toggleGroupCollapse}>▶</div>
26
+ {/if}
27
+
28
+ {#if log.level === 'assert'}
29
+ <span class="assert">Assertion failed:</span>
30
+ {/if}
31
+
32
+ {#if log.level === 'clear'}
33
+ <span class="info">Console was cleared</span>
34
+ {:else if log.level === 'unclonable'}
35
+ <span class="info error">Message could not be cloned. Open devtools to see it</span>
36
+ {:else if log.level === 'group'}
37
+ <div class="arrow" class:expand={!log.collapsed}>▶</div>
38
+ <span class="title">{log.label}</span>
39
+ {:else if log.level.startsWith('system')}
40
+ {#each log.args as arg}
41
+ {arg}
42
+ {/each}
43
+ {:else if log.level === 'table'}
44
+ <JSONTree value={log.args[0]} />
45
+ {:else}
46
+ <div class="args">
47
+ {#each log.args as arg}
48
+ {#if typeof arg === "string"}
49
+ <span class="string">{arg}</span>
50
+ {:else if typeof arg === "function"}
51
+ <div class="function">{arg.toString()}</div>
52
+ {:else}
53
+ <JSONTree value={arg} />
54
+ {/if}
55
+ {/each}
56
+ </div>
57
+ {/if}
58
+ {#each new Array(level - 1) as _, idx}
59
+ <div class="outline" style="left: {idx * 15 + 15}px" />
60
+ {/each}
61
+ </div>
62
+
63
+ {#if log.level === 'group' && !log.collapsed}
64
+ {#each log.logs as childLog}
65
+ <svelte:self log={childLog} level={level + 1}/>
66
+ {/each}
67
+ {/if}
68
+
69
+ {#if (log.level === 'trace' || log.level === 'assert') && !log.collapsed}
70
+ <div class="trace">
71
+ {#each log.stack.split('\n').slice(2) as stack}
72
+ <div>{stack.replace(/^\s*at\s+/, '')}</div>
73
+ {/each}
74
+ </div>
75
+ {/if}
76
+
77
+ <style>
78
+ .log {
79
+ --json-tree-string-color: rgba(240, 240, 240, 0.6);
80
+ --arrow-sign: rgba(255, 255, 255, 0.5);
81
+ --json-tree-font-size: var(--font-size-input);
82
+ --json-tree-font-family: var(--font-mono);
83
+ --json-tree-number-color: #9980FF;
84
+ --json-tree-symbol-color: #cb3f41;
85
+ --json-tree-boolean-color: #9980FF;
86
+ --json-tree-function-color: var(--color-active);
87
+ /* --json-tree-number-color: #3029cf; */
88
+ --json-tree-property-color: #5DB0D7;
89
+ --json-tree-label-color: #17d08e;
90
+ --json-tree-arrow-color: #727272;
91
+ --json-tree-null-color: #8d8d8d;
92
+ --json-tree-undefined-color: #8d8d8d;
93
+ --json-tree-date-color: #8d8d8d;
94
+ --json-tree-li-indentation: 12px;
95
+
96
+ position: relative;
97
+
98
+ display: flex;
99
+ padding: 4px 0 3px;
100
+
101
+ color: rgba(255, 255, 255, 0.5);
102
+
103
+ border-bottom: 1px solid #3A3A3A;
104
+ border-top: 1px solid #3A3A3A;
105
+ }
106
+
107
+ .args {
108
+ display: flex;
109
+ flex-direction: column;
110
+ }
111
+
112
+ .string {
113
+ display: block;
114
+ font-size: var(--font-size-input);
115
+ }
116
+
117
+ .function {
118
+ font-size: var(--font-size-input);
119
+ font-style: italic;
120
+ white-space: pre;
121
+ tab-size: 2em;
122
+ }
123
+
124
+ :global(.log ul > .Number, .log ul > .Boolean, .log ul > .Date, .log ul > .Undefined) {
125
+ margin-left: calc(var(--li-identation) * -1);
126
+ }
127
+
128
+ .log:first-child:not(.console-error) {
129
+ border-top: none;
130
+ }
131
+
132
+ .log:not(:first-child) {
133
+ margin-top: -1px;
134
+ }
135
+
136
+ /* :global(.console-warn .console-log) {
137
+ border-top-color: transparent;
138
+ } */
139
+
140
+ /* .log > :global(*) {
141
+ margin-right: 10px;
142
+ } */
143
+
144
+ .console-warn, .console-system-warn {
145
+ --json-tree-string-color: #F3AB26;
146
+ background: #332B00;
147
+ border-color: #665600;
148
+ color: var(--json-tree-string-color);
149
+ }
150
+
151
+ .console-error, .console-assert {
152
+ --json-tree-string-color: #FF8081;
153
+ --json-tree-label-color: #FF8081;
154
+
155
+ color: var(--json-tree-string-color);
156
+ background: #2A0000;
157
+ border-color: #5C0000;
158
+ }
159
+
160
+ .console-group, .arrow {
161
+ cursor: pointer;
162
+ user-select: none;
163
+ }
164
+
165
+ .log :global(.arrow) {
166
+ margin-right: 10px;
167
+ }
168
+
169
+ .log :global(.String) {
170
+ white-space: pre-wrap;
171
+ }
172
+
173
+ .console-trace, .console-assert {
174
+ border-bottom: none;
175
+ }
176
+
177
+ .console-assert + .trace {
178
+ background: #fff0f0;
179
+ border-color: #fed6d7;
180
+ }
181
+
182
+ .trace {
183
+ border-bottom: 1px solid #eee;
184
+ font-size: 12px;
185
+ font-family: var(--font-mono);
186
+ padding: 4px 0 2px;
187
+ }
188
+
189
+ .trace > :global(div) {
190
+ margin-left: 15px;
191
+ }
192
+
193
+ .count {
194
+ position: relative;
195
+
196
+ display: flex;
197
+ justify-content: center;
198
+ align-items: center;
199
+ margin-right: 4px;
200
+
201
+ font-size: 9px;
202
+ padding: 0 4px;
203
+ }
204
+
205
+ .count:before {
206
+ content: '';
207
+
208
+ position: absolute;
209
+
210
+ width: 100%;
211
+ min-width: 16px;
212
+ height: 16px;
213
+
214
+ border-radius: 9px;
215
+ background-color: var(--color-lightblack);
216
+ }
217
+
218
+ .count span {
219
+ position: relative;
220
+ }
221
+
222
+ .outline {
223
+ border-left: 1px solid #9c9cab;
224
+ position: absolute;
225
+ top: 0;
226
+ bottom: -1px;
227
+ }
228
+
229
+ .arrow {
230
+ position: absolute;
231
+ font-size: 0.6em;
232
+ transition: 150ms;
233
+ transform-origin: 50% 50%;
234
+ transform: translateY(1px) translateX(-50%);
235
+ }
236
+
237
+ .arrow.expand {
238
+ transform: translateY(1px) translateX(-50%) rotateZ(90deg);
239
+ }
240
+
241
+ .title {
242
+ font-family: var(--font-mono);
243
+ font-size: 13px;
244
+ font-weight: bold;
245
+ padding-left: 11px;
246
+ height: 19px;
247
+ }
248
+
249
+ .assert {
250
+ padding-left: 11px;
251
+ font-weight: bold;
252
+ /* color: #da106e; */
253
+ }
254
+ </style>
@@ -0,0 +1,82 @@
1
+ <script>
2
+ import Module from "../ui/Module.svelte";
3
+ import ModuleHeaderAction from "../ui/ModuleHeaderAction.svelte";
4
+ import { logs } from "../stores/console";
5
+ import ConsoleLine from "./Console/ConsoleLine.svelte";
6
+ import { afterUpdate } from "svelte";
7
+
8
+ export let mID;
9
+ export let hasHeader;
10
+
11
+ let scrollableContainer;
12
+
13
+ function clear() {
14
+ $logs = [];
15
+ }
16
+
17
+ afterUpdate(() => {
18
+ if (scrollableContainer) {
19
+ scrollableContainer.scrollTop = scrollableContainer.scrollHeight;
20
+ }
21
+ })
22
+
23
+ </script>
24
+
25
+ <Module {mID} {hasHeader} name="console" scrollable={false}>
26
+ <svelte:fragment slot="header-right">
27
+ <ModuleHeaderAction border label="Clear" on:click={() => clear()}>clear</ModuleHeaderAction>
28
+ </svelte:fragment>
29
+ <div class="container">
30
+ <div class="list">
31
+ <div class="scroll" bind:this={scrollableContainer}>
32
+ {#each $logs as log}
33
+ <ConsoleLine {log} />
34
+ {/each}
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </Module>
39
+
40
+ <style>
41
+ .container {
42
+ position: relative;
43
+
44
+ height: 100%;
45
+ max-height: 100%;
46
+ padding: 4px;
47
+ }
48
+
49
+ .list {
50
+ position: relative;
51
+
52
+ margin-right: var(--padding);
53
+ padding: 1px 1px;
54
+
55
+ height: 100%;
56
+ max-height: 100%;
57
+
58
+ background-color: #1d1d1e;
59
+ border-radius: var(--border-radius-input);
60
+ box-shadow: inset 0 0 0 1px var(--color-border-input);
61
+ }
62
+
63
+ .scroll {
64
+ height: 100%;
65
+ overflow-x: hidden;
66
+ overflow-y: scroll;
67
+ }
68
+
69
+ .scroll::-webkit-scrollbar {
70
+ width: 5px; /* width of the entire scrollbar */
71
+ }
72
+
73
+ .scroll::-webkit-scrollbar-track {
74
+ background-color: var(--color-lightblack); /* color of the tracking area */
75
+ }
76
+
77
+ .scroll::-webkit-scrollbar-thumb {
78
+ background-color: var(--color-active); /* color of the scroll thumb */
79
+ border-radius: 20px; /* roundness of the scroll thumb */
80
+ }
81
+
82
+ </style>
@@ -0,0 +1,105 @@
1
+ <script>
2
+ import Module from "../ui/Module.svelte";
3
+ import Field from "../ui/Field.svelte";
4
+ import FieldGroup from "../ui/FieldGroup.svelte";
5
+ import { exports } from "../stores";
6
+ import { recording, capturing, IMAGE_ENCODINGS, VIDEO_FORMATS } from "../stores/exports";
7
+
8
+ export let mID;
9
+ export let hasHeader = true;
10
+
11
+ const LABEL_RECORD = "start";
12
+ const LABEL_RECORDING = "stop";
13
+
14
+ function record () {
15
+ $recording = !$recording;
16
+ }
17
+
18
+ function capture() {
19
+ $capturing = !$capturing;
20
+ }
21
+
22
+ $: recordLabel = $recording ? LABEL_RECORDING : LABEL_RECORD;
23
+
24
+ </script>
25
+
26
+ <Module {mID} {hasHeader} name="exports">
27
+ <FieldGroup name="image">
28
+ <Field
29
+ key="encoding"
30
+ value={$exports.imageEncoding}
31
+ params={{ options: IMAGE_ENCODINGS }}
32
+ on:change={((e) => {
33
+ $exports.imageEncoding = e.detail;
34
+ })}
35
+ />
36
+ <Field
37
+ key="quality"
38
+ value={$exports.imageQuality}
39
+ params={{ min: 1, max: 100, suffix: "%", triggerable: false }}
40
+ on:change={((e) => {
41
+ $exports.imageQuality = e.detail;
42
+ })}
43
+ />
44
+ <Field
45
+ key="pixelsPerInch"
46
+ value={$exports.pixelsPerInch}
47
+ params={{ step: 1 }}
48
+ on:change={((e) => {
49
+ $exports.pixelsPerInch = e.detail;
50
+ })}
51
+ />
52
+ <Field
53
+ key="screenshot"
54
+ value={capture}
55
+ params={{ label: "capture", triggerable: false }}
56
+ />
57
+ </FieldGroup>
58
+ <FieldGroup name="video">
59
+ <Field
60
+ key="framerate"
61
+ value={$exports.framerate}
62
+ on:change={((e) => {
63
+ $exports.framerate = e.detail;
64
+ })}
65
+ />
66
+ <Field
67
+ key="format"
68
+ value={$exports.videoFormat}
69
+ params={{ options: Object.values(VIDEO_FORMATS) }}
70
+ on:change={((e) => {
71
+ $exports.videoFormat = e.detail;
72
+ })}
73
+ />
74
+ <Field
75
+ key="quality"
76
+ value={$exports.videoQuality}
77
+ params={{ min: 1, max: 100, step: 1, suffix: "%", triggerable: false }}
78
+ on:change={((e) => {
79
+ $exports.videoQuality = e.detail;
80
+ })}
81
+ />
82
+ <Field
83
+ key="useDuration"
84
+ value={$exports.useDuration}
85
+ on:change={((e) => {
86
+ $exports.useDuration = e.detail;
87
+ })}
88
+ />
89
+ {#if $exports.useDuration }
90
+ <Field
91
+ key="loopCount"
92
+ value={$exports.loopCount}
93
+ params={{ step: 1 }}
94
+ on:change={((e) => {
95
+ $exports.loopCount = e.detail;
96
+ })}
97
+ />
98
+ {/if}
99
+ <Field
100
+ key="record"
101
+ value={record}
102
+ params={{ label: recordLabel, triggerable: false }}
103
+ />
104
+ </FieldGroup>
105
+ </Module>
@@ -0,0 +1,106 @@
1
+ <script>
2
+ import { onMount } from "svelte";
3
+ import Module from "../ui/Module.svelte";
4
+ import Field from "../ui/Field.svelte";
5
+ import MIDI from "../inputs/MIDI.js";
6
+
7
+ export let mID;
8
+ export let hasHeader;
9
+
10
+ let input, output;
11
+ let inputs = [], outputs = [];
12
+
13
+ function createDeviceOptions(deviceMap = new Map()) {
14
+ let options = [];
15
+
16
+ if (deviceMap.size !== 0) {
17
+ options.push({ value: "none", label: "No device selected." });
18
+ }
19
+
20
+ for (let entry of deviceMap) {
21
+ let device = entry[1];
22
+ const { id, name, manufacturer } = device;
23
+
24
+ options.push({ value: id, label: `${manufacturer} ${name} – id: ${id}` });
25
+ }
26
+
27
+ if (options.length === 0) {
28
+ options = [
29
+ { value: "none", label: "No device detected."}
30
+ ];
31
+ }
32
+
33
+ return options;
34
+ }
35
+
36
+ let messages = [];
37
+
38
+ $: {
39
+ MIDI.selectedInputID = input;
40
+ }
41
+
42
+ $: {
43
+ MIDI.selectedOutputID = output;
44
+ }
45
+
46
+ onMount(async () => {
47
+ await MIDI.request();
48
+
49
+ function refresh() {
50
+ inputs = createDeviceOptions(MIDI.inputs);
51
+ outputs = createDeviceOptions(MIDI.outputs);
52
+
53
+ // if a single device is connected, select it by default
54
+ input = (inputs.length === 2 ? inputs[1].value : inputs[0].value);
55
+ output = (outputs.length === 2 ? outputs[1].value : outputs[0].value);
56
+ }
57
+
58
+ MIDI.addEventListener("connected", refresh);
59
+ MIDI.addEventListener("disconnected", () => {
60
+ refresh();
61
+ });
62
+
63
+ MIDI.addEventListener("message", (event) => {
64
+ const { type, note, channel, value } = event;
65
+ let date = new Date();
66
+ let time = `${date.getHours()}:${String(date.getMinutes()).padStart(2, "0")}:${String(date.getSeconds()).padStart(2, "0")}`;
67
+
68
+ let noteLog = ["noteon", "noteoff"].includes(type) ? ` note:${note.name}` : ``;
69
+
70
+ messages = [
71
+ ...messages,
72
+ `${time} ${type} number:${note.number}${noteLog}`,
73
+ ]
74
+ });
75
+
76
+ refresh();
77
+ });
78
+
79
+ </script>
80
+
81
+ <Module {mID} {hasHeader} name="MIDI" {...$$props} slug="midi">
82
+ <Field
83
+ key="inputs"
84
+ value={input}
85
+ on:change={(event) => input = event.detail}
86
+ params={{
87
+ options: inputs,
88
+ }}
89
+ />
90
+ <Field
91
+ key="outputs"
92
+ value={output}
93
+ on:change={(event) => output = event.detail}
94
+ params={{
95
+ options: outputs,
96
+ }}
97
+ />
98
+ <Field
99
+ key="messages"
100
+ value={messages}
101
+ type="list"
102
+ params={{
103
+ disabled: true
104
+ }}
105
+ />
106
+ </Module>
@@ -0,0 +1,62 @@
1
+ <script context="module">
2
+ let ID = 0;
3
+ </script>
4
+
5
+ <script>
6
+ import { onMount, onDestroy } from "svelte";
7
+ import Module from "../ui/Module.svelte";
8
+ import SketchRenderer from "../ui/SketchRenderer.svelte";
9
+ import OutputRenderer from "../ui/OutputRenderer.svelte";
10
+ import SketchSelect from "../ui/SketchSelect.svelte";
11
+ import { sketchesKeys } from "../stores/sketches.js";
12
+ import { monitors, preview } from "../stores/rendering";
13
+
14
+ export let mID;
15
+ export let hasHeader = true;
16
+ export let sketchKey = null;
17
+
18
+ let id = ID++;
19
+ let name = "monitor";
20
+ let selected = sketchKey ?
21
+ sketchKey :
22
+ ($preview ? $preview : $sketchesKeys[Math.min(id, $sketchesKeys.length - 1)]);
23
+
24
+ onMount(() => {
25
+ $monitors = [
26
+ ...$monitors,
27
+ {
28
+ id,
29
+ selected,
30
+ }
31
+ ];
32
+ });
33
+
34
+ monitors.subscribe((all) => {
35
+ const current = all.find((monitor) => monitor.id === id);
36
+
37
+ if (current && current.selected !== selected) {
38
+ selected = current.selected;
39
+ }
40
+ })
41
+
42
+ onDestroy(() => {
43
+ $monitors = $monitors.filter((m) => m.id !== id);
44
+ });
45
+
46
+ $: index = $monitors.findIndex(monitor => monitor.id === id);
47
+ $: moduleName = `${name} ${$monitors.length > 1 ? (index + 1) : ""}`;
48
+ </script>
49
+
50
+ <Module {hasHeader} {mID} slug="monitor" name={moduleName} scrollable={false}>
51
+ <svelte:fragment slot="header-left">
52
+ <SketchSelect
53
+ monitorID={id}
54
+ {selected}
55
+ />
56
+ </svelte:fragment>
57
+ {#if selected && selected !== "output"}
58
+ <SketchRenderer key={selected} {id} />
59
+ {:else if selected }
60
+ <OutputRenderer />
61
+ {/if}
62
+ </Module>