fragment-tools 0.1.13 → 0.1.14

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 (52) hide show
  1. package/bin/index.js +2 -2
  2. package/package.json +4 -5
  3. package/src/cli/log.js +31 -21
  4. package/src/cli/plugins/check-dependencies.js +47 -30
  5. package/src/cli/plugins/hot-shader-replacement.js +384 -0
  6. package/src/cli/plugins/hot-sketch-reload.js +3 -13
  7. package/src/cli/plugins/screenshot.js +57 -20
  8. package/src/cli/server.js +144 -133
  9. package/src/client/app/App.svelte +3 -3
  10. package/src/client/app/client.js +55 -39
  11. package/src/client/app/components/Init.svelte +12 -9
  12. package/src/client/app/helpers.js +42 -0
  13. package/src/client/app/hooks.js +20 -0
  14. package/src/client/app/inputs/Keyboard.js +13 -15
  15. package/src/client/app/inputs/MIDI.js +14 -15
  16. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +41 -21
  17. package/src/client/app/lib/gl/Renderer.js +127 -139
  18. package/src/client/app/modules/Exports.svelte +62 -43
  19. package/src/client/app/modules/MidiPanel.svelte +100 -101
  20. package/src/client/app/modules/Params.svelte +116 -103
  21. package/src/client/app/renderers/2DRenderer.js +3 -3
  22. package/src/client/app/renderers/FragmentRenderer.js +30 -23
  23. package/src/client/app/renderers/P5Renderer.js +10 -7
  24. package/src/client/app/renderers/THREERenderer.js +136 -94
  25. package/src/client/app/stores/exports.js +36 -20
  26. package/src/client/app/stores/props.js +28 -5
  27. package/src/client/app/stores/renderers.js +22 -15
  28. package/src/client/app/stores/sketches.js +7 -9
  29. package/src/client/app/stores/utils.js +95 -38
  30. package/src/client/app/triggers/Keyboard.js +88 -79
  31. package/src/client/app/triggers/MIDI.js +110 -84
  32. package/src/client/app/ui/Field.svelte +343 -240
  33. package/src/client/app/ui/FieldGroup.svelte +106 -94
  34. package/src/client/app/ui/FieldSection.svelte +125 -116
  35. package/src/client/app/ui/ParamsMultisampling.svelte +96 -95
  36. package/src/client/app/ui/ParamsOutput.svelte +113 -113
  37. package/src/client/app/ui/SelectChevrons.svelte +27 -15
  38. package/src/client/app/ui/SketchRenderer.svelte +761 -667
  39. package/src/client/app/ui/fields/ButtonInput.svelte +61 -48
  40. package/src/client/app/ui/fields/CheckboxInput.svelte +67 -61
  41. package/src/client/app/ui/fields/ColorInput.svelte +294 -238
  42. package/src/client/app/ui/fields/ImageInput.svelte +123 -121
  43. package/src/client/app/ui/fields/Input.svelte +100 -111
  44. package/src/client/app/ui/fields/ListInput.svelte +96 -96
  45. package/src/client/app/ui/fields/NumberInput.svelte +121 -116
  46. package/src/client/app/ui/fields/ProgressInput.svelte +80 -73
  47. package/src/client/app/ui/fields/Select.svelte +137 -124
  48. package/src/client/app/ui/fields/VectorInput.svelte +86 -82
  49. package/src/client/app/utils/canvas.utils.js +228 -201
  50. package/src/client/app/utils/file.utils.js +38 -34
  51. package/src/client/public/css/global.css +27 -21
  52. package/src/cli/plugins/hot-shader-reload.js +0 -86
@@ -1,27 +1,59 @@
1
- import path from "path";
2
- import fs from "fs/promises";
3
- import fsSync from "fs";
4
- import bodyParser from "body-parser";
5
- import log from "../log.js";
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import fsSync from 'fs';
4
+ import bodyParser from 'body-parser';
5
+ import log from '../log.js';
6
6
 
7
- export default function screenshot({ cwd, exportDir = cwd }) {
8
- let dir = (path.isAbsolute(exportDir) ? exportDir : path.join(cwd, exportDir));
7
+ export default function screenshot({ cwd, inlineExportDir }) {
8
+ function resolveDirectory(directoryPath) {
9
+ return path.isAbsolute(directoryPath)
10
+ ? directoryPath
11
+ : path.join(cwd, directoryPath);
12
+ }
13
+
14
+ function resolveExportDirectory({ exportDir }) {
15
+ let directory;
16
+
17
+ if (inlineExportDir) {
18
+ if (!inlineExportDirPath) {
19
+ inlineExportDirPath = resolveDirectory(inlineExportDir);
20
+ }
21
+
22
+ directory = inlineExportDirPath;
23
+
24
+ if (exportDir) {
25
+ log.warning(
26
+ `'exportDir' configuration from sketch has been overridden by --exportDir.`,
27
+ );
28
+ }
29
+ } else if (exportDir) {
30
+ directory = resolveDirectory(exportDir);
31
+ } else {
32
+ directory = cwd;
33
+ }
34
+
35
+ return directory;
36
+ }
37
+
38
+ let inlineExportDirPath;
9
39
 
10
40
  return {
11
41
  name: 'screenshot',
12
- configureServer(server){
13
- server.middlewares.use(bodyParser.json({ limit: '100mb'}))
42
+ configureServer(server) {
43
+ server.middlewares.use(bodyParser.json({ limit: '100mb' }));
14
44
  server.middlewares.use('/save', async (req, res, next) => {
15
- if (req.method === "POST") {
45
+ if (req.method === 'POST') {
16
46
  const { filename, dataURL } = req.body;
17
47
 
18
- const filepath = path.join(dir, filename);
48
+ let directory = resolveExportDirectory(req.body);
49
+
50
+ const filepath = path.join(directory, filename);
19
51
  const buffer = Buffer.from(dataURL, 'base64');
20
52
 
21
- if (!fsSync.existsSync(dir)) {
53
+ if (!fsSync.existsSync(directory)) {
22
54
  try {
23
- await fs.mkdir(dir, { recursive: true });
24
- } catch(error) {
55
+ await fs.mkdir(directory, { recursive: true });
56
+ } catch (error) {
25
57
  log.error('Cannot create directory for exports');
26
58
  console.log(error);
27
59
  }
@@ -30,17 +62,22 @@ export default function screenshot({ cwd, exportDir = cwd }) {
30
62
  try {
31
63
  await fs.writeFile(filepath, buffer);
32
64
 
33
- res.writeHead(200, {'Content-Type': 'application/json'});
65
+ log.success(`Saved ${filepath}`);
66
+
67
+ res.writeHead(200, {
68
+ 'Content-Type': 'application/json',
69
+ });
34
70
  res.end(JSON.stringify({ filepath }));
35
- } catch(error) {
36
- res.writeHead(500, {'Content-Type': 'application/json'});
71
+ } catch (error) {
72
+ res.writeHead(500, {
73
+ 'Content-Type': 'application/json',
74
+ });
37
75
  res.end(JSON.stringify({ error }));
38
76
  }
39
77
  } else {
40
78
  next();
41
79
  }
42
80
  });
43
- }
44
- }
45
-
81
+ },
82
+ };
46
83
  }
package/src/cli/server.js CHANGED
@@ -1,153 +1,164 @@
1
- import path from "path";
2
- import kleur from "kleur";
1
+ import path from 'path';
2
+ import kleur from 'kleur';
3
3
  import { fileURLToPath } from 'url';
4
- import { createServer, defineConfig, build } from "vite";
5
- import { svelte } from '@sveltejs/vite-plugin-svelte'
6
- import hotShaderReload from "./plugins/hot-shader-reload.js";
7
- import hotSketchReload from "./plugins/hot-sketch-reload.js";
8
- import dbPlugin from "./plugins/db.js";
4
+ import { createServer, defineConfig, build } from 'vite';
5
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
6
+ import hotShaderReplacement from './plugins/hot-shader-replacement.js';
7
+ import hotSketchReload from './plugins/hot-sketch-reload.js';
8
+ import dbPlugin from './plugins/db.js';
9
9
 
10
- import log from "./log.js";
11
- import db from "./db.js";
12
- import screenshotPlugin from "./plugins/screenshot.js";
13
- import checkDependencies from "./plugins/check-dependencies.js";
10
+ import log from './log.js';
11
+ import screenshotPlugin from './plugins/screenshot.js';
12
+ import checkDependencies from './plugins/check-dependencies.js';
14
13
 
15
14
  const __filename = fileURLToPath(import.meta.url);
16
15
  const __dirname = path.dirname(__filename);
17
16
 
18
17
  export async function start({ options, filepaths, entries, fragment }) {
19
- const root = path.join(__dirname, '/../client');
20
- const cwd = process.cwd();
21
- const app = path.join(root, 'app');
18
+ const root = path.join(__dirname, '/../client');
19
+ const cwd = process.cwd();
20
+ const app = path.join(root, 'app');
22
21
 
23
- const entriesPaths = entries.map((entry ) => path.join(cwd, entry));
22
+ const entriesPaths = entries.map((entry) => path.join(cwd, entry));
24
23
 
25
- const config = defineConfig({
26
- configFile: false,
27
- root,
28
- logLevel: options.development ? "info" : "silent",
29
- resolve: {
30
- alias: [
31
- { find: '@fragment/sketches', replacement: filepaths[0] },
32
- { find: '@fragment', replacement: app },
33
- { find: 'three', replacement: path.join(cwd, 'node_modules/three') },
34
- { find: 'p5', replacement: path.join(cwd, 'node_modules/p5') },
35
- { find: 'ogl', replacement: path.join(cwd, 'node_modules/ogl') },
36
- ]
37
- },
38
- plugins: [
39
- svelte({
40
- configFile: false,
41
- onwarn: (warning, handler) => {
42
- if (options.development) {
43
- handler(warning);
44
- } else {
45
- return;
46
- }
47
- }
48
- }),
49
- hotSketchReload({
50
- cwd,
51
- }),
52
- hotShaderReload({ wss: fragment.server }),
53
- {
54
- name: 'configure-response-headers',
55
- configureServer: (server) => {
56
- server.middlewares.use((_req, res, next) => {
57
- res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
58
- res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
59
- next();
60
- });
61
- }
62
- },
63
- dbPlugin(),
64
- screenshotPlugin({ cwd, exportDir: options.exportDir }),
65
- checkDependencies({
66
- cwd,
67
- app,
68
- entriesPaths,
69
- build: options.build,
70
- })
71
- ],
72
- server: {
73
- port: options.port,
74
- host: true,
75
- fs: {
76
- strict: false,
77
- allow: [".."],
78
- },
79
- },
80
- define: {
81
- '__CWD__': `${JSON.stringify(cwd)}`,
82
- '__FRAGMENT_PORT__': fragment.server ? fragment.server.port : undefined,
83
- '__START_TIME__': Date.now(),
84
- '__SEED__': Date.now(),
85
- '__BUILD__': options.build,
86
- '__DEV__': !options.build,
24
+ const config = defineConfig({
25
+ configFile: false,
26
+ root,
27
+ logLevel: options.development ? 'info' : 'silent',
28
+ resolve: {
29
+ alias: [
30
+ { find: '@fragment/sketches', replacement: filepaths[0] },
31
+ { find: '@fragment', replacement: app },
32
+ {
33
+ find: 'three',
34
+ replacement: path.join(cwd, 'node_modules/three'),
35
+ },
36
+ { find: 'p5', replacement: path.join(cwd, 'node_modules/p5') },
37
+ {
38
+ find: 'ogl',
39
+ replacement: path.join(cwd, 'node_modules/ogl'),
40
+ },
41
+ ],
42
+ },
43
+ plugins: [
44
+ svelte({
45
+ configFile: false,
46
+ onwarn: (warning, handler) => {
47
+ if (options.development) {
48
+ handler(warning);
49
+ } else {
50
+ return;
51
+ }
52
+ },
53
+ }),
54
+ hotSketchReload({
55
+ cwd,
56
+ }),
57
+ hotShaderReplacement({ cwd, wss: fragment.server }),
58
+ {
59
+ name: 'configure-response-headers',
60
+ configureServer: (server) => {
61
+ server.middlewares.use((_req, res, next) => {
62
+ res.setHeader(
63
+ 'Cross-Origin-Opener-Policy',
64
+ 'same-origin',
65
+ );
66
+ res.setHeader(
67
+ 'Cross-Origin-Embedder-Policy',
68
+ 'require-corp',
69
+ );
70
+ next();
71
+ });
72
+ },
73
+ },
74
+ dbPlugin(),
75
+ screenshotPlugin({ cwd, inlineExportDir: options.exportDir }),
76
+ checkDependencies({
77
+ cwd,
78
+ app,
79
+ entriesPaths,
80
+ build: options.build,
81
+ }),
82
+ ],
83
+ server: {
84
+ port: options.port,
85
+ host: true,
86
+ fs: {
87
+ strict: false,
88
+ allow: ['..'],
89
+ },
90
+ },
91
+ define: {
92
+ __CWD__: `${JSON.stringify(cwd)}`,
93
+ __FRAGMENT_PORT__: fragment.server
94
+ ? fragment.server.port
95
+ : undefined,
96
+ __START_TIME__: Date.now(),
97
+ __SEED__: Date.now(),
98
+ __BUILD__: options.build,
99
+ __DEV__: !options.build,
100
+ },
101
+ optimizeDeps: {
102
+ include: ['convert-length', 'webm-writer', 'changedpi'],
103
+ exclude: ['@fragment/sketches', ...entriesPaths],
104
+ },
105
+ build: {
106
+ commonjsOptions: {
107
+ include: ['convert-length', 'webm-writer', 'changedpi'],
108
+ },
109
+ },
110
+ });
87
111
 
88
- },
89
- optimizeDeps: {
90
- include: ['convert-length', 'webm-writer', 'changedpi'],
91
- exclude: [
92
- "@fragment/sketches",
93
- ...entriesPaths,
94
- ]
95
- },
96
- build: {
97
- commonjsOptions: {
98
- include: ['convert-length', 'webm-writer', 'changedpi'],
99
- },
100
- },
101
- });
112
+ if (options.build) {
113
+ if (entries.length > 1) {
114
+ log.error(`fragment can only build one sketch at a time.`);
115
+ return;
116
+ }
102
117
 
103
- if (options.build) {
104
- if (entries.length > 1) {
105
- log.error(`fragment can only build one sketch at a time.`);
106
- return;
107
- }
118
+ const outDir = options.outDir
119
+ ? options.outDir
120
+ : entries[0].split('.js')[0];
108
121
 
109
- const outDir = options.outDir ? options.outDir : entries[0].split('.js')[0];
122
+ await build({
123
+ ...config,
124
+ logLevel: 'info',
125
+ build: {
126
+ outDir: path.join(process.cwd(), outDir),
127
+ emptyOutDir: options.emptyOutDir,
128
+ },
129
+ });
110
130
 
111
- await build({
112
- ...config,
113
- logLevel: "info",
114
- build: {
115
- outDir: path.join(process.cwd(), outDir),
116
- emptyOutDir: options.emptyOutDir,
117
- },
118
- });
131
+ log.success(`Built files for:`);
132
+ entries.forEach((entry) => console.log(`- ${entry}`));
133
+ } else {
134
+ log.warning(`Starting server...`);
135
+ const server = await createServer(config);
119
136
 
120
- log.success(`Built files for:`);
121
- entries.forEach(entry => console.log(`- ${entry}`));
122
- } else {
123
- log.warning(`Starting server...`);
124
- const server = await createServer(config);
137
+ server.middlewares.use('/db', (req, res, next) => {
138
+ next();
139
+ });
125
140
 
126
- server.middlewares.use('/db', (req, res, next) => {
127
- next();
128
- });
141
+ await server.listen();
129
142
 
130
- await server.listen();
131
-
132
- log.success(`Server started at:`);
143
+ log.success(`Server started at:`);
133
144
 
134
- const { resolvedUrls } = server;
145
+ const { resolvedUrls } = server;
135
146
 
136
- for (const url of resolvedUrls.local) {
137
- console.log(
138
- ` ${kleur.green('➜')} ${kleur.bold('Local')}: ${kleur.cyan(
139
- url,
140
- )}`,
141
- );
142
- }
143
- for (const url of resolvedUrls.network) {
144
- console.log(
145
- ` ${kleur.green('➜')} ${kleur.bold('Network')}: ${kleur.cyan(
146
- url,
147
- )}`,
148
- );
149
- }
147
+ for (const url of resolvedUrls.local) {
148
+ console.log(
149
+ ` ${kleur.green('➜')} ${kleur.bold('Local')}: ${kleur.cyan(
150
+ url,
151
+ )}`,
152
+ );
153
+ }
154
+ for (const url of resolvedUrls.network) {
155
+ console.log(
156
+ ` ${kleur.green('➜')} ${kleur.bold('Network')}: ${kleur.cyan(
157
+ url,
158
+ )}`,
159
+ );
160
+ }
150
161
 
151
- return server;
152
- }
162
+ return server;
163
+ }
153
164
  }
@@ -1,7 +1,7 @@
1
1
  <script>
2
- import Layout from "./ui/Layout.svelte";
3
- import Init from "./components/Init.svelte";
4
- import "./client";
2
+ import Layout from './ui/Layout.svelte';
3
+ import Init from './components/Init.svelte';
4
+ import './client';
5
5
  </script>
6
6
 
7
7
  <Init />
@@ -1,68 +1,84 @@
1
- const socketProtocol = (location.protocol === 'https:' ? 'wss' : 'ws');
1
+ const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
2
2
  const socketHost = `${location.hostname}:${__FRAGMENT_PORT__}`;
3
3
 
4
- let socket, listeners = {};
4
+ let socket,
5
+ listeners = {};
5
6
 
6
7
  function handleMessage(payload) {
7
- const { event, data = {} } = payload;
8
- const callbacks = listeners[event];
8
+ const { event, data = {} } = payload;
9
+ const callbacks = listeners[event];
9
10
 
10
- if (callbacks && callbacks.length) {
11
- callbacks.forEach((cb) => cb(data));
12
- }
11
+ if (callbacks && callbacks.length) {
12
+ callbacks.forEach((cb) => cb(data));
13
+ }
13
14
  }
14
15
 
15
16
  function on(event, cb) {
16
- if (!listeners[event]) {
17
- listeners[event] = [];
18
- }
17
+ if (!listeners[event]) {
18
+ listeners[event] = [];
19
+ }
19
20
 
20
- listeners[event].push(cb);
21
+ listeners[event].push(cb);
21
22
 
22
- return () => {
23
- off(event, cb);
24
- };
23
+ return () => {
24
+ off(event, cb);
25
+ };
25
26
  }
26
27
 
27
- function off(event, cb) {
28
- const callbacks = listeners[event];
28
+ function off(event, cb) {
29
+ const callbacks = listeners[event];
29
30
 
30
- if (callbacks && callbacks.length) {
31
- const filtered = callbacks.filter((callback) => callback !== cb);
31
+ if (callbacks && callbacks.length) {
32
+ const filtered = callbacks.filter((callback) => callback !== cb);
32
33
 
33
- listeners[event] = filtered;
34
- }
34
+ listeners[event] = filtered;
35
+ }
35
36
  }
36
37
 
37
38
  let opened = false;
38
39
  function emit(event, data) {
39
- if (opened) {
40
- socket.send(JSON.stringify({
41
- event,
42
- data,
43
- }));
44
- }
40
+ if (opened) {
41
+ socket.send(
42
+ JSON.stringify({
43
+ event,
44
+ data,
45
+ }),
46
+ );
47
+ }
45
48
  }
46
49
 
47
50
  if (import.meta.hot) {
48
- console.log("[fragment] connecting...");
51
+ console.log('[fragment] connecting...');
49
52
 
50
- socket = new WebSocket(`${socketProtocol}://${socketHost}`);
53
+ socket = new WebSocket(`${socketProtocol}://${socketHost}`);
51
54
 
52
- socket.addEventListener('message', async (message) => {
53
- const { data } = message;
55
+ socket.addEventListener('message', async (message) => {
56
+ const { data } = message;
54
57
 
55
- handleMessage(JSON.parse(data));
56
- });
58
+ handleMessage(JSON.parse(data));
59
+ });
57
60
 
58
- socket.addEventListener("open", () => {
59
- console.log("[fragment] connected.");
60
- opened = true;
61
- });
61
+ socket.addEventListener('open', () => {
62
+ console.log('[fragment] connected.');
63
+ opened = true;
64
+ });
62
65
 
63
- import.meta.hot.on('sketch-update', (data) => {
64
- console.log(`[fragment] hmr update /${data.filepath}`);
65
- })
66
+ import.meta.hot.on('sketch-update', (data) => {
67
+ console.log(`[fragment] hmr update /${data.filepath}`);
68
+ });
66
69
  }
67
70
 
68
71
  export const client = { on, off, emit };
72
+
73
+ client.on('shader-update', (shaderUpdates) => {
74
+ shaderUpdates.forEach(({ warnings = [] } = {}) => {
75
+ if (warnings.length > 0) {
76
+ warnings.forEach((warning) => {
77
+ const { location } = warning;
78
+ console.warn(
79
+ `[fragment-plugin-hsr] ${warning.type} ${warning.importer}\n\n ${location.lineText}\n\n${warning.message}`,
80
+ );
81
+ });
82
+ }
83
+ });
84
+ });
@@ -1,13 +1,16 @@
1
1
  <script>
2
- import { assignSketchFiles } from "../triggers/shared.js";
3
- import { sketchesKeys } from "../stores/sketches.js";
4
- import "../utils/glslErrors.js";
5
-
6
- sketchesKeys.subscribe((keys) => {
7
- if (keys.length > 0) {
8
- assignSketchFiles(keys);
9
- }
10
- })
2
+ import { assignSketchFiles } from '../triggers/shared.js';
3
+ import { loadAll, sketchesKeys } from '../stores/sketches.js';
4
+ import { onSketchReload } from '@fragment/sketches';
5
+ import '../utils/glslErrors.js';
11
6
 
7
+ sketchesKeys.subscribe((keys) => {
8
+ if (keys.length > 0) {
9
+ assignSketchFiles(keys);
10
+ }
11
+ });
12
12
 
13
+ onSketchReload(({ sketches }) => {
14
+ loadAll(sketches);
15
+ });
13
16
  </script>
@@ -0,0 +1,42 @@
1
+ import { props } from './stores/props';
2
+
3
+ const propHandler = {
4
+ set: function (target, key, value, receiver) {
5
+ Reflect.set(target, key, value, receiver);
6
+
7
+ if (key === 'value') {
8
+ props.update((currentProps) => currentProps);
9
+ }
10
+
11
+ return true;
12
+ },
13
+ };
14
+
15
+ const propsHandler = {
16
+ get: (target, key) => {
17
+ if (typeof target[key] === 'object' && target[key] !== null) {
18
+ return new Proxy(target[key], propHandler);
19
+ }
20
+ },
21
+ set: (target, key, value) => {
22
+ console.log('new set', target, key, value);
23
+
24
+ target[key] = value;
25
+
26
+ props.update((currentProps) => currentProps);
27
+
28
+ return true;
29
+ },
30
+ deleteProperty: (target, prop) => {
31
+ if (prop in target) {
32
+ delete target[prop];
33
+ props.update((currentProps) => currentProps);
34
+
35
+ return true;
36
+ }
37
+ },
38
+ };
39
+
40
+ export function reactiveProps(props = {}) {
41
+ return new Proxy(props, propsHandler);
42
+ }
@@ -0,0 +1,20 @@
1
+ import {
2
+ removeBeforeCaptureFrom,
3
+ removeAfterCaptureFrom,
4
+ removeBeforeRecordFrom,
5
+ removeAfterRecordFrom,
6
+ } from './stores/exports';
7
+
8
+ export {
9
+ onBeforeCapture,
10
+ onAfterCapture,
11
+ onBeforeRecord,
12
+ onAfterRecord,
13
+ } from './stores/exports';
14
+
15
+ export function removeHooksFrom(context) {
16
+ removeBeforeCaptureFrom(context);
17
+ removeAfterCaptureFrom(context);
18
+ removeBeforeRecordFrom(context);
19
+ removeAfterRecordFrom(context);
20
+ }
@@ -1,21 +1,19 @@
1
- import Input from "./Input";
1
+ import Input from './Input';
2
2
 
3
3
  class Keyboard extends Input {
4
+ /**
5
+ *
6
+ * @param {KeyboardEvent} event
7
+ */
8
+ getStepFromEvent(event) {
9
+ if (event.shiftKey) {
10
+ return 10;
11
+ } else if (event.altKey) {
12
+ return 0.1;
13
+ }
4
14
 
5
- /**
6
- *
7
- * @param {KeyboardEvent} event
8
- */
9
- getStepFromEvent(event) {
10
- if (event.shiftKey) {
11
- return 10;
12
- } else if (event.altKey) {
13
- return 0.1;
14
- }
15
-
16
- return 1;
17
- }
18
-
15
+ return 1;
16
+ }
19
17
  }
20
18
 
21
19
  export default new Keyboard();