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,44 @@
1
+ import { writable, get } from "svelte/store";
2
+ import { sketches } from "./sketches";
3
+
4
+ export const props = writable({});
5
+
6
+ sketches.subscribe((sketches) => {
7
+ const $props = get(props);
8
+
9
+ Object.keys(sketches).forEach((key) => {
10
+ const sketch = sketches[key];
11
+
12
+ if (sketch) { // sketch can be undefined if failed to load
13
+ $props[key] = reconcile(sketch.props, $props[key]);
14
+ }
15
+
16
+ });
17
+
18
+ props.set($props);
19
+ });
20
+
21
+ function reconcile(newProps = {}, existingProps = {}) {
22
+ Object.keys(newProps).forEach(propKey => {
23
+ newProps[propKey]._initialValue = newProps[propKey].value;
24
+ });
25
+
26
+ if (existingProps) {
27
+ Object.keys(existingProps).forEach((propKey) => {
28
+ let newProp = newProps[propKey];
29
+
30
+ if (newProp) {
31
+ let prevProp = existingProps[propKey];
32
+ let overrideValue =
33
+ typeof prevProp._initialValue === "number" &&
34
+ prevProp._initialValue === newProp._initialValue;
35
+
36
+ if (overrideValue) {
37
+ newProp.value = prevProp.value;
38
+ }
39
+ }
40
+ });
41
+ };
42
+
43
+ return newProps;
44
+ }
@@ -0,0 +1,60 @@
1
+ import { rendering } from "./rendering";
2
+
3
+ export let renderers = {};
4
+
5
+ function loadRenderer(renderingMode = "2d") {
6
+ if (__THREE_RENDERER__ && renderingMode === "three") {
7
+ return import("../renderers/THREERenderer.js");
8
+ }
9
+
10
+ if (__FRAGMENT_RENDERER__ && renderingMode === "fragment") {
11
+ return import("../renderers/FragmentRenderer.js");
12
+ }
13
+
14
+ if (__P5_RENDERER__ && renderingMode === "p5") {
15
+ return import("../renderers/P5Renderer.js");
16
+ }
17
+
18
+ if (__2D_RENDERER__ && renderingMode === "2d") {
19
+ return import("../renderers/2DRenderer.js");
20
+ }
21
+ }
22
+
23
+ export async function findRenderer(renderingMode = "2d") {
24
+ if (renderers[renderingMode]) return renderers[renderingMode];
25
+
26
+ // load and save
27
+ renderers[renderingMode] = await loadRenderer(renderingMode);
28
+
29
+ // get
30
+ let renderer = renderers[renderingMode];
31
+ let initialized = false;
32
+
33
+ rendering.subscribe((current) => {
34
+ let r;
35
+
36
+ if (!initialized) {
37
+ if (typeof renderer.init === "function") {
38
+ r = renderer.init({
39
+ canvas: document.createElement('canvas'),
40
+ pixelRatio: current.pixelRatio,
41
+ width: current.width,
42
+ height: current.height,
43
+ });
44
+ }
45
+ }
46
+
47
+ initialized = true;
48
+
49
+ if (typeof renderer.resize === "function") {
50
+ renderer.resize({
51
+ width: current.width,
52
+ height: current.height,
53
+ pixelRatio: current.pixelRatio,
54
+ ...r,
55
+ });
56
+ }
57
+ });
58
+
59
+ return renderer;
60
+ }
@@ -0,0 +1,111 @@
1
+ import { writable } from "svelte/store";
2
+ import { client } from "../client";
3
+ import { createStore } from "./utils";
4
+ import { getDimensionsForPreset } from "../lib/presets";
5
+
6
+ export const SIZES = {
7
+ FIXED: "fixed",
8
+ PRESET: "preset",
9
+ ASPECT_RATIO: "aspect-ratio",
10
+ WINDOW: "window",
11
+ SCALE: "scale",
12
+ };
13
+
14
+ export const rendering = createStore(`rendering`, {
15
+ width: 1024,
16
+ height: 1024,
17
+ pixelRatio: 1,
18
+ resizing: SIZES.FIXED,
19
+ aspectRatio: 1,
20
+ scale: 1,
21
+ preset: 'a4',
22
+ }, {
23
+ persist: !__PRODUCTION__,
24
+ reset: false,
25
+ });
26
+
27
+ export const monitors = createStore('monitors', []);
28
+ export const preview = createStore('preview', null);
29
+
30
+ export const override = (config) => {
31
+ const { canvasSize = SIZES.WINDOW } = config;
32
+ const resizing = canvasSize;
33
+
34
+ const overrides = {
35
+ resizing,
36
+ };
37
+
38
+ if (config.dimensions && config.dimensions.length === 2) {
39
+ const { dimensions } = config;
40
+ overrides.width = dimensions[0];
41
+ overrides.height = dimensions[1];
42
+
43
+ if (!config.canvasSize) {
44
+ overrides.resizing = SIZES.FIXED;
45
+ }
46
+ }
47
+
48
+ if (resizing === SIZES.PRESET) {
49
+ if (config.preset) {
50
+ const [ width, height ] = getDimensionsForPreset(config.preset, { pixelsPerInch: 300 });
51
+
52
+ overrides.width = width;
53
+ overrides.height = height;
54
+ } else {
55
+ overrides.resizing = SIZES.WINDOW;
56
+ console.warn(`Cannot apply canvasSize preset if 'preset' is not specified in config.`);
57
+ }
58
+ }
59
+
60
+ if (resizing === SIZES.ASPECT_RATIO) {
61
+ if (isNaN(config.aspectRatio)) {
62
+ overrides.resizing = SIZES.WINDOW;
63
+ console.warn(`Cannot apply canvasSize:"aspectRatio" if 'aspectRatio' is not specified in config.`);
64
+ }
65
+ }
66
+
67
+ if (resizing === SIZES.SCALE) {
68
+ if (!config.dimensions) {
69
+ console.warn(`Cannot apply canvasSize:"scale" if no dimensions are specified.`);
70
+ overrides.resizing = SIZES.WINDOW;
71
+ }
72
+
73
+ if (isNaN(config.scale)) {
74
+ console.warn(`Cannot apply canvasSize:"scale" if 'scale' is not specified in config.`);
75
+ overrides.resizing = SIZES.WINDOW;
76
+ } else {
77
+ overrides.scale = config.scale;
78
+ }
79
+ }
80
+
81
+ if (config.pixelRatio) {
82
+ const { pixelRatio } = config;
83
+ overrides.pixelRatio = typeof pixelRatio === "function" ? pixelRatio() : pixelRatio;
84
+ }
85
+
86
+ rendering.update((curr) => ({...curr, ...overrides}));
87
+ };
88
+
89
+ /* sync across clients */
90
+ let isSynchronized = false;
91
+
92
+ export const sync = writable(isSynchronized);
93
+
94
+ function checkForSync({ clientCount } = {}) {
95
+ let prev = isSynchronized;
96
+ isSynchronized = clientCount > 0;
97
+
98
+ if (prev && !isSynchronized) {
99
+ console.warn("[fragment] Sketch is running at specified framerate.");
100
+ } else if (!prev && isSynchronized) {
101
+ console.warn("[fragment] Multiple instances of Fragment detected. Running sketch(s) at simulated framerate.");
102
+ }
103
+
104
+ if (prev !== isSynchronized) {
105
+ sync.set(isSynchronized);
106
+ }
107
+ }
108
+
109
+ client.on('start', checkForSync);
110
+ client.on('client-connect', checkForSync);
111
+ client.on('client-disconnect', checkForSync);
@@ -0,0 +1,40 @@
1
+ import { createStore } from "./utils.js";
2
+ import { displayError } from "../stores/errors";
3
+ import { sketches as all, onSketchReload } from "@fragment/sketches";
4
+
5
+ export const sketches = createStore('sketches', {});
6
+ export const sketchesKeys = createStore('sketchesKeys', []);
7
+ export const sketchesCount = createStore('sketchesCount', 0);
8
+
9
+ async function loadSketch(collection, key) {
10
+ try {
11
+ let sketch = await collection[key]();
12
+
13
+ return sketch;
14
+ } catch (error) {
15
+ displayError(error, key);
16
+ }
17
+ }
18
+
19
+ async function loadAll(collection) {
20
+ const keys = [...Object.keys(collection)];
21
+ const loadedSketches = await Promise.all(keys.map((key) => loadSketch(collection, key)));
22
+
23
+ const newSketches = keys.reduce((all, key, index) => {
24
+ if (loadedSketches[index]) {
25
+ all[key] = loadedSketches[index];
26
+ }
27
+
28
+ return all;
29
+ }, {});
30
+
31
+ sketches.update(() => newSketches);
32
+ sketchesKeys.update(() => keys);
33
+ sketchesCount.update(() => keys.length);
34
+ }
35
+
36
+ loadAll(all);
37
+
38
+ onSketchReload(({ sketches }) => {
39
+ loadAll(sketches);
40
+ });
@@ -0,0 +1,27 @@
1
+ import { readable } from "svelte/store";
2
+
3
+ export const current = readable({ time: 0, deltaTime: 0 }, set => {
4
+ let _raf;
5
+ let lastTime = performance.now();
6
+ let startTime = lastTime - __START_TIME__;
7
+ let time = startTime;
8
+
9
+ function update(dt = 0) {
10
+ lastTime = time;
11
+
12
+ let currentTime = performance.now();
13
+ let deltaTime = currentTime - lastTime;
14
+
15
+ time = currentTime;
16
+
17
+ set({ time, deltaTime, startTime });
18
+
19
+ _raf = requestAnimationFrame(update)
20
+ }
21
+
22
+ update();
23
+
24
+ return () => {
25
+ cancelAnimationFrame(_raf);
26
+ }
27
+ });
@@ -0,0 +1,66 @@
1
+ import { writable } from "svelte/store";
2
+
3
+ let stores = new Map();
4
+
5
+ /**
6
+ * Returns the value stored in localStorage for key or return defaultValue if it doesn't exist
7
+ * @param {string} key
8
+ * @param {any} defaultValue
9
+ * @param {boolean} override
10
+ * @returns {any} result
11
+ */
12
+ export function rehydrate(key, defaultValue) {
13
+ const storedValue = localStorage.getItem(`fragment.${key}`);
14
+
15
+ if (storedValue) {
16
+ return typeof storedValue === "string" ? JSON.parse(storedValue) : storedValue;
17
+ }
18
+
19
+ return defaultValue;
20
+ };
21
+
22
+ /**
23
+ * Save value in localStorage
24
+ * @param {string} key
25
+ * @param {any} value
26
+ */
27
+ export function save(key, value) {
28
+ localStorage.setItem(`fragment.${key}`, JSON.stringify(value));
29
+ };
30
+
31
+ /**
32
+ * Create store and register it for later usage
33
+ * @param {string} key
34
+ * @param {any} initialValue
35
+ * @param {object} options
36
+ * @returns {object} store
37
+ */
38
+ export function createStore(key, initialValue, { persist = false, reset = false } = {}) {
39
+ const value = (persist && !reset) ? rehydrate(key, initialValue) : initialValue;
40
+ const store = writable(value);
41
+
42
+ if (persist) {
43
+ store.subscribe((current) => {
44
+ save(key, current);
45
+ });
46
+ }
47
+
48
+ stores.set(key, store);
49
+
50
+ return store;
51
+ };
52
+
53
+ /**
54
+ * Get an existing store from key or create it if it doesn't exist yet
55
+ * @param {string} key
56
+ * @param {any} initialValue
57
+ * @param {object} options
58
+ * @returns {object} store
59
+ */
60
+ export function getStore(key, initialValue, { persist = false, reset = false } = {}) {
61
+ if (!stores.has(key)) {
62
+ return createStore(key, initialValue, { persist, reset });
63
+ }
64
+
65
+ return stores.get(key);
66
+ };
@@ -0,0 +1,17 @@
1
+ export let name = "Fade";
2
+
3
+ export let props = {};
4
+
5
+ export let fragmentShader = /* glsl */`
6
+ precision highp float;
7
+
8
+ uniform sampler2D uSampler0;
9
+ uniform sampler2D uSampler1;
10
+ uniform float threshold;
11
+
12
+ varying vec2 vUv;
13
+
14
+ void main() {
15
+ gl_FragColor = mix(texture2D(uSampler0, vUv), texture2D(uSampler1, vUv), threshold);
16
+ }
17
+ `;
@@ -0,0 +1,12 @@
1
+
2
+ // This file is generated by Fragment. Do not edit it.
3
+
4
+ import * as transition0 from "./fade.js";
5
+ import * as transition1 from "./splitX.js";
6
+ import * as transition2 from "./splitY.js";
7
+
8
+ export const transitions = {
9
+ "fade.js": transition0,
10
+ "splitX.js": transition1,
11
+ "splitY.js": transition2,
12
+ };
@@ -0,0 +1,16 @@
1
+ export let name = "SplitX";
2
+ export let props = {};
3
+
4
+ export let fragmentShader = /* glsl */`
5
+ precision highp float;
6
+
7
+ uniform float threshold;
8
+ uniform sampler2D uSampler0;
9
+ uniform sampler2D uSampler1;
10
+
11
+ varying vec2 vUv;
12
+
13
+ void main() {
14
+ gl_FragColor = mix(texture2D(uSampler0, vUv), texture2D(uSampler1, vUv), step(1. - vUv.x, threshold));
15
+ }
16
+ `;
@@ -0,0 +1,16 @@
1
+ export let name = "SplitY";
2
+ export let props = {};
3
+
4
+ export let fragmentShader = /* glsl */`
5
+ precision highp float;
6
+
7
+ uniform float threshold;
8
+ uniform sampler2D uSampler0;
9
+ uniform sampler2D uSampler1;
10
+
11
+ varying vec2 vUv;
12
+
13
+ void main() {
14
+ gl_FragColor = mix(texture2D(uSampler0, vUv), texture2D(uSampler1, vUv), step(1. - vUv.y, threshold));
15
+ }
16
+ `;
@@ -0,0 +1,95 @@
1
+ import Trigger from "./Trigger";
2
+ import Keyboard from "../inputs/Keyboard";
3
+ import { wildcard, getContext } from "./shared";
4
+ import { addToMapArray, removeFromMapArray } from "../utils";
5
+
6
+ const pressedKeys = new Map();
7
+ const upKeys = new Map();
8
+ const downKeys = new Map();
9
+
10
+ export const removeHotListeners = (context) => {
11
+ function removeHotFrom(collection) {
12
+ for (let trigger of collection) {
13
+ const [key, triggers] = trigger;
14
+
15
+ collection.set(key, triggers.filter((trigger) => trigger.context !== context));
16
+ }
17
+ }
18
+
19
+ removeHotFrom(pressedKeys);
20
+ removeHotFrom(upKeys);
21
+ removeHotFrom(downKeys);
22
+ };
23
+
24
+ function createEventListener(collection) {
25
+ return (event) => {
26
+ const { key, target } = event;
27
+
28
+ if (!target.classList.contains('input')) {
29
+ const triggers = [
30
+ ...(collection.has(key) ? collection.get(key) : []),
31
+ ...(collection.has(wildcard) ? collection.get(wildcard) : []),
32
+ ];
33
+
34
+ triggers.forEach(trigger => {
35
+ if (!Keyboard.enabled) return;
36
+
37
+ trigger.run(event);
38
+ });
39
+ }
40
+ };
41
+ }
42
+
43
+ function createTrigger(eventName, collection) {
44
+ return (key, fn, options = {}) => {
45
+ if (typeof key === "function") {
46
+ if (typeof fn === "object") {
47
+ options = {
48
+ ...options,
49
+ ...fn,
50
+ };
51
+ }
52
+
53
+ fn = key;
54
+ key = "*";
55
+
56
+ if (options.key) {
57
+ key = options.key;
58
+ }
59
+ }
60
+
61
+ const { hot, enabled, ...params } = options;
62
+ const context = getContext();
63
+
64
+ const keys = Array.isArray(key) ? key : [key];
65
+
66
+ const trigger = new Trigger({
67
+ inputType: 'Keyboard',
68
+ eventName,
69
+ fn,
70
+ context,
71
+ params: {...params, key: keys },
72
+ hot,
73
+ enabled,
74
+ destroy: () => {
75
+ keys.forEach((key) => {
76
+ removeFromMapArray(collection, key, (item) => item.id === trigger.id);
77
+ });
78
+ }
79
+ });
80
+
81
+ keys.forEach(key => {
82
+ addToMapArray(collection, key, trigger);
83
+ });
84
+
85
+ return trigger;
86
+ };
87
+ };
88
+
89
+ window.addEventListener("keypress", createEventListener(pressedKeys));
90
+ window.addEventListener("keyup", createEventListener(upKeys));
91
+ window.addEventListener("keydown", createEventListener(downKeys));
92
+
93
+ export const onKeyPress = createTrigger('onKeyPress', pressedKeys);
94
+ export const onKeyDown = createTrigger('onKeyDown', downKeys);
95
+ export const onKeyUp = createTrigger('onKeyUp', upKeys);
@@ -0,0 +1,122 @@
1
+ import Trigger from "./Trigger";
2
+ import MIDI from "../inputs/MIDI.js";
3
+ import { addToMapArray, removeFromMapArray } from "../utils";
4
+ import { wildcard, getContext } from "./shared";
5
+
6
+ const noteons = new Map();
7
+ const noteoffs = new Map();
8
+ const numberons = new Map();
9
+ const numberoffs = new Map();
10
+ const controlchanges = new Map();
11
+
12
+ /**
13
+ * Remove listeners from a specific context
14
+ * @param {string} context
15
+ */
16
+ export const removeHotListeners = (context) => {
17
+ function removeHotFrom(collection) {
18
+ for (let trigger of collection) {
19
+ const [key, triggers] = trigger;
20
+
21
+ collection.set(key, triggers.filter((trigger) => trigger.context !== context));
22
+ }
23
+ }
24
+
25
+ removeHotFrom(noteons);
26
+ removeHotFrom(noteoffs);
27
+ removeHotFrom(numberons);
28
+ removeHotFrom(numberoffs);
29
+ removeHotFrom(controlchanges);
30
+ };
31
+
32
+ /**
33
+ * Check all registered listeners for a specific key
34
+ * @param {Map} collection
35
+ * @param {function} getKey
36
+ * @returns {function} listener
37
+ */
38
+ function createEventListener(collection, getKey = (event) => event.key) {
39
+ return (event) => {
40
+ const key = getKey(event);
41
+ const { id } = event.srcElement;
42
+
43
+ const triggers = [
44
+ ...(collection.has(key) ? collection.get(key) : []),
45
+ ...(collection.has(wildcard) ? collection.get(wildcard) : []),
46
+ ];
47
+
48
+ if (MIDI.enabled && id === MIDI.selectedInputID) {
49
+ triggers.forEach(trigger => {
50
+ trigger.run(event);
51
+ });
52
+ }
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Create a registering function for a specific event
58
+ * @param {string} eventName
59
+ * @param {Map} collection
60
+ * @returns {function} createListener
61
+ */
62
+ function createTrigger(eventName, collection) {
63
+ return (key, fn, options = {}) => {
64
+ if (typeof key === "function") {
65
+ if (typeof fn === "object") {
66
+ options = {
67
+ ...options,
68
+ ...fn,
69
+ };
70
+ }
71
+
72
+ fn = key;
73
+ key = "*";
74
+
75
+ if (options.key) {
76
+ key = options.key;
77
+ }
78
+ }
79
+
80
+ const { hot, enabled, ...params } = options;
81
+ const keys = Array.isArray(key) ? key : [key];
82
+
83
+ if (!MIDI.enabled) {
84
+ MIDI.request();
85
+ }
86
+
87
+ const context = getContext();
88
+
89
+ const trigger = new Trigger({
90
+ inputType: 'MIDI',
91
+ eventName,
92
+ fn,
93
+ params: {...params, key: keys },
94
+ hot,
95
+ context,
96
+ enabled,
97
+ destroy : () => {
98
+ keys.forEach((key) => {
99
+ removeFromMapArray(collection, key, (item) => item.id === trigger.id);
100
+ });
101
+ }
102
+ });
103
+
104
+ keys.forEach(k => {
105
+ addToMapArray(collection, k, trigger);
106
+ });
107
+
108
+ return trigger;
109
+ };
110
+ };
111
+
112
+ MIDI.addEventListener("noteon", createEventListener(noteons, (event) => event.note.name));
113
+ MIDI.addEventListener("noteoff", createEventListener(noteoffs, (event) => event.note.name));
114
+ MIDI.addEventListener("noteon", createEventListener(numberons, (event) => event.note.number));
115
+ MIDI.addEventListener("noteoff", createEventListener(numberoffs, (event) => event.note.number));
116
+ MIDI.addEventListener("controlchange", createEventListener(controlchanges, (event) => event.note.number));
117
+
118
+ export const onNoteOn = createTrigger('onNoteOn', noteons);
119
+ export const onNoteOff = createTrigger('onNoteOff', noteoffs);
120
+ export const onNumberOn = createTrigger('onNumberOn', numberons);
121
+ export const onNumberOff = createTrigger('onNumberOff', numberoffs);
122
+ export const onControlChange = createTrigger('onControlChange', controlchanges);