fragment-tools 0.2.8 → 0.2.9

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 (89) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.prettierignore +1 -0
  4. package/CHANGELOG.md +10 -0
  5. package/README.md +14 -10
  6. package/bin/index.js +4 -0
  7. package/package.json +9 -2
  8. package/src/cli/build.js +1 -3
  9. package/src/cli/create.js +55 -6
  10. package/src/cli/createConfig.js +8 -23
  11. package/src/cli/createFragmentFile.js +44 -46
  12. package/src/cli/getEntries.js +13 -5
  13. package/src/cli/plugins/check-dependencies.js +1 -1
  14. package/src/cli/run.js +12 -3
  15. package/src/cli/templates/blank/index.js +4 -4
  16. package/src/cli/templates/blank/index.ts +15 -0
  17. package/src/cli/templates/default/index.js +7 -6
  18. package/src/cli/templates/default/index.ts +20 -0
  19. package/src/cli/templates/fragment-gl/fragment.fs +1 -1
  20. package/src/cli/templates/fragment-gl/index.js +3 -3
  21. package/src/cli/templates/fragment-gl/index.ts +20 -0
  22. package/src/cli/templates/p5/index.js +6 -6
  23. package/src/cli/templates/p5/index.ts +14 -0
  24. package/src/cli/templates/p5-webgl/fragment.fs +2 -4
  25. package/src/cli/templates/p5-webgl/index.js +9 -15
  26. package/src/cli/templates/p5-webgl/index.ts +43 -0
  27. package/src/cli/templates/three-fragment/fragment.fs +1 -1
  28. package/src/cli/templates/three-fragment/index.js +10 -4
  29. package/src/cli/templates/three-fragment/index.ts +68 -0
  30. package/src/cli/templates/three-orthographic/index.js +10 -4
  31. package/src/cli/templates/three-orthographic/index.ts +29 -0
  32. package/src/cli/templates/three-perspective/index.js +10 -4
  33. package/src/cli/templates/three-perspective/index.ts +26 -0
  34. package/src/cli/utils.js +3 -0
  35. package/src/client/app/components/HintRecord.svelte +3 -3
  36. package/src/client/app/hooks.js +5 -5
  37. package/src/client/app/lib/gl/Renderer.js +1 -1
  38. package/src/client/app/lib/gl/Texture.js +1 -1
  39. package/src/client/app/lib/gl/index.js +2 -2
  40. package/src/client/app/modules/AudioAnalyser/Range.svelte +2 -2
  41. package/src/client/app/modules/AudioAnalyser/Spectrum.svelte +3 -3
  42. package/src/client/app/modules/Console/ConsoleLine.svelte +13 -13
  43. package/src/client/app/modules/Console.svelte +6 -4
  44. package/src/client/app/renderers/2DRenderer.js +6 -3
  45. package/src/client/app/renderers/FragmentRenderer.js +39 -2
  46. package/src/client/app/renderers/P5GLRenderer.js +28 -26
  47. package/src/client/app/renderers/P5Renderer.js +49 -9
  48. package/src/client/app/renderers/THREERenderer.js +64 -12
  49. package/src/client/app/state/rendering.svelte.js +2 -2
  50. package/src/client/app/state/utils.svelte.js +9 -2
  51. package/src/client/app/stores/sketches.js +2 -1
  52. package/src/client/app/ui/ErrorOverlay.svelte +5 -5
  53. package/src/client/app/ui/Field.svelte +5 -5
  54. package/src/client/app/ui/FieldGroup.svelte +5 -5
  55. package/src/client/app/ui/FieldSection.svelte +7 -7
  56. package/src/client/app/ui/FieldSpace.svelte +2 -2
  57. package/src/client/app/ui/FieldTrigger.svelte +6 -6
  58. package/src/client/app/ui/FloatingParams.svelte +1 -1
  59. package/src/client/app/ui/LayoutComponent.svelte +7 -7
  60. package/src/client/app/ui/LayoutResizer.svelte +1 -1
  61. package/src/client/app/ui/LayoutToolbar.svelte +6 -6
  62. package/src/client/app/ui/Module.svelte +6 -4
  63. package/src/client/app/ui/ModuleRenderer.svelte +3 -3
  64. package/src/client/app/ui/OutputRenderer.svelte +4 -1
  65. package/src/client/app/ui/SketchRenderer.svelte +4 -1
  66. package/src/client/app/ui/fields/ButtonInput.svelte +11 -11
  67. package/src/client/app/ui/fields/CheckboxInput.svelte +18 -12
  68. package/src/client/app/ui/fields/ColorInput.svelte +9 -7
  69. package/src/client/app/ui/fields/ImageInput.svelte +10 -8
  70. package/src/client/app/ui/fields/Input.svelte +13 -13
  71. package/src/client/app/ui/fields/IntervalInput.svelte +11 -14
  72. package/src/client/app/ui/fields/ListInput.svelte +9 -8
  73. package/src/client/app/ui/fields/ProgressInput.svelte +9 -9
  74. package/src/client/app/ui/fields/Select.svelte +11 -11
  75. package/src/client/app/ui/fields/VectorInput.svelte +1 -1
  76. package/src/client/public/css/global.css +26 -27
  77. package/src/client/public/preview.html +59 -0
  78. package/src/types/client.d.ts +36 -0
  79. package/src/types/gl.d.ts +130 -0
  80. package/src/types/helpers.d.ts +5 -0
  81. package/src/types/hooks.d.ts +14 -0
  82. package/src/types/index.d.ts +8 -0
  83. package/src/types/midi.d.ts +176 -0
  84. package/src/types/props.d.ts +72 -0
  85. package/src/types/renderers.d.ts +100 -0
  86. package/src/types/sketch.d.ts +45 -0
  87. package/src/types/triggers.d.ts +45 -0
  88. package/src/types/utils.ts +11 -0
  89. package/tsconfig.json +38 -0
@@ -0,0 +1,8 @@
1
+ # Changesets
2
+
3
+ Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4
+ with multi-package repos, or single-package repos to help you version and publish your code. You can
5
+ find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6
+
7
+ We have a quick list of common questions to get you started engaging with this project in
8
+ [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
3
+ "changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "raphaelameaume/fragment"}],
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "restricted",
8
+ "baseBranch": "main",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": []
11
+ }
package/.prettierignore CHANGED
@@ -1,4 +1,5 @@
1
1
  pnpm-lock.yaml
2
2
  pnpm-workspace.yaml
3
3
  package-lock.json
4
+ .changeset/config.json
4
5
  /docs
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # fragment-tools
2
+
3
+ ## 0.2.9
4
+
5
+ ### Patch Changes
6
+
7
+ - Prevent state mutations and warnings
8
+ - Start templates on a green screen
9
+ - Update examples
10
+ - Prevent build layout re-render if layout is not persistent
package/README.md CHANGED
@@ -14,6 +14,7 @@
14
14
  - Hot shader reloading & [glslify](https://github.com/glslify/glslify) support
15
15
  - Interactive sketches using _triggers_
16
16
  - Static build for production deployment
17
+ - TypeScript support
17
18
 
18
19
  ## Installation
19
20
 
@@ -44,15 +45,18 @@ npx fragment sketch.js --new
44
45
 
45
46
  ## Usage
46
47
 
47
- ```
48
- # create a new directory for your sketches
48
+ ```bash
49
+ # Create a new directory for your sketches
49
50
  mkdir sketches
50
51
 
51
- # move into that folder
52
+ # Move into that folder
52
53
  cd sketches
53
54
 
54
- # create a sketch from a template
55
- npx fragment-tools ./sketch.js --new --template=2d
55
+ # Create a sketch from a template
56
+ npx fragment ./sketch.js --new --template=2d
57
+
58
+ # or with TypeScript
59
+ npx fragment ./sketch.ts --new --template=2d --typescript
56
60
  ```
57
61
 
58
62
  Learn more about the available flag options in the [CLI docs](./docs/api/CLI.md).
@@ -97,14 +101,14 @@ Feel free to reach out on [Twitter](https://twitter.com/raphaelameaume) if you w
97
101
 
98
102
  ## Running it locally
99
103
 
100
- ```
101
- # clone or fork the project
104
+ ```bash
105
+ # Clone or fork the project
102
106
  git clone https://github.com/raphaelameaume/fragment.git
103
107
 
104
- # move to the root of the repository
108
+ # Move to the root of the repository
105
109
  cd fragment
106
110
 
107
- # run the command line locally
111
+ # Run the command line locally
108
112
  node ./bin/index.js examples/shape-2d.js --dev
109
113
 
110
114
  # or from your sketch folder
@@ -122,7 +126,7 @@ npm link
122
126
 
123
127
  You should be able the command as before, only this time it will point to the repository instead of the globally installed package.
124
128
 
125
- ```
129
+ ```bash
126
130
  fragment sketch.js
127
131
  ```
128
132
 
package/bin/index.js CHANGED
@@ -21,6 +21,7 @@ prog.command('run [entry]', '', { default: true })
21
21
  .describe('Run a dev environment for fragment')
22
22
  .option('-n, --new', 'Create a new sketch', false)
23
23
  .option('-t, --template', 'Specify template to create the file from', '2d')
24
+ .option('--typescript', 'Specify TypeScript support', false)
24
25
  .option('-p, --port', 'Port to bind', 3000)
25
26
  .option('-dev, --development', 'Enable development mode', false)
26
27
  .option('-b, --build', 'Build sketch for production', false)
@@ -34,6 +35,7 @@ prog.command('run [entry]', '', { default: true })
34
35
  if (options.new) {
35
36
  return create(entry, {
36
37
  templateName: options.template,
38
+ typescript: options.typescript,
37
39
  });
38
40
  }
39
41
 
@@ -59,9 +61,11 @@ prog.command('run [entry]', '', { default: true })
59
61
  prog.command('create [entry]')
60
62
  .describe('Create a new sketch')
61
63
  .option('-t, --template', 'Specify template to create the file from', '2d')
64
+ .option('--typescript', 'Specify TypeScript support', false)
62
65
  .action((entry = '', options) => {
63
66
  create(entry, {
64
67
  templateName: options.template,
68
+ typescript: options.typescript,
65
69
  });
66
70
  });
67
71
 
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "fragment-tools",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "A web development environment for creative coding",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "fragment": "bin/index.js"
8
8
  },
9
9
  "scripts": {
10
- "format": "prettier . --write"
10
+ "format": "prettier . --write",
11
+ "changeset:add": "changeset add",
12
+ "changeset:version": "changeset version",
13
+ "changeset:publish": "changeset publish"
11
14
  },
12
15
  "type": "module",
13
16
  "repository": {
@@ -38,6 +41,10 @@
38
41
  "ws": "^8.2.3"
39
42
  },
40
43
  "devDependencies": {
44
+ "@changesets/cli": "^2.29.6",
45
+ "@svitejs/changesets-changelog-github-compact": "^1.2.0",
46
+ "@types/p5": "^1.7.6",
47
+ "@types/three": "^0.174.0",
41
48
  "prettier": "^3.2.5",
42
49
  "prettier-plugin-svelte": "^3.2.6"
43
50
  }
package/src/cli/build.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { readdir } from 'node:fs/promises';
3
3
  import { mergeConfig, build as viteBuild } from 'vite';
4
- import { createFragmentFile } from './createFragmentFile.js';
5
4
  import { createConfig } from './createConfig.js';
6
5
  import { getEntries } from './getEntries.js';
7
6
  import { log, magenta } from './log.js';
@@ -17,6 +16,7 @@ import hotShaderReplacement from './plugins/hot-shader-replacement.js';
17
16
  * @param {string} options.outDir
18
17
  * @param {boolean} options.emptyOutDir
19
18
  * @param {boolean} options.development
19
+ * @param {string} options.configFilepath
20
20
  * @param {boolean} [options.prompts=true]
21
21
  */
22
22
  export async function build(entry, options) {
@@ -94,10 +94,8 @@ export async function build(entry, options) {
94
94
  prefix,
95
95
  );
96
96
 
97
- const fragmentFilepath = await createFragmentFile(entries, cwd);
98
97
  const config = await createConfig(
99
98
  entries,
100
- fragmentFilepath,
101
99
  {
102
100
  dev: options.development,
103
101
  build: true,
package/src/cli/create.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'node:fs';
3
3
  import { readdir, readFile, writeFile } from 'node:fs/promises';
4
+ import { createTsConfigFile } from './createFragmentFile.js';
4
5
  import { log, magenta, bold, cyan, dim } from './log.js';
5
6
  import * as p from './prompts.js';
6
7
  import {
7
8
  packageManager,
9
+ __dirname,
8
10
  file,
9
11
  mkdirp,
10
12
  handleCancelledPrompt,
@@ -17,8 +19,9 @@ import {
17
19
  * @param {string} entry
18
20
  * @param {object} options
19
21
  * @param {string} options.templateName
22
+ * @param {boolean} options.typescript
20
23
  */
21
- export async function create(entry, { templateName } = {}) {
24
+ export async function create(entry, { templateName, typescript } = {}) {
22
25
  const cwd = process.cwd();
23
26
  const prefix = log.prefix('create');
24
27
 
@@ -64,7 +67,8 @@ export async function create(entry, { templateName } = {}) {
64
67
  let templatesOptions = fs
65
68
  .readdirSync(file('./templates'))
66
69
  .map((dir) => {
67
- const metadata = file(`./templates/${dir}/meta.json`);
70
+ const dirpath = file(`./templates/${dir}`);
71
+ const metadata = path.join(dirpath, 'meta.json');
68
72
  const template = JSON.parse(fs.readFileSync(metadata, 'utf8'));
69
73
 
70
74
  return {
@@ -92,6 +96,15 @@ export async function create(entry, { templateName } = {}) {
92
96
 
93
97
  handleCancelledPrompt(templateName, prefix);
94
98
 
99
+ typescript = await p.confirm({
100
+ message: 'Use TypeScript template?',
101
+ active: 'Yes',
102
+ inactive: 'No',
103
+ initialValue: typescript,
104
+ });
105
+
106
+ handleCancelledPrompt(typescript, prefix);
107
+
95
108
  let template = templatesOptions.find(
96
109
  (option) => option.value === templateName,
97
110
  );
@@ -114,8 +127,12 @@ export async function create(entry, { templateName } = {}) {
114
127
  const from = file(`./templates/${template.path}`);
115
128
  const to = dir;
116
129
 
130
+ const tsOptions = templatesOptions.typescript ?? {};
131
+ const tsExcludes = tsOptions.excludes ?? ['index.js'];
132
+ const jsExcludes = tsOptions.includes ?? ['index.ts'];
133
+ let excludes = [...(typescript ? tsExcludes : jsExcludes), 'meta.json'];
134
+
117
135
  let filename = path.basename(name).split('.')[0];
118
- let excludes = ['meta.json'];
119
136
  let templateFiles = await readdir(from);
120
137
 
121
138
  templateFiles = templateFiles.filter(
@@ -128,14 +145,14 @@ export async function create(entry, { templateName } = {}) {
128
145
  prefix,
129
146
  );
130
147
 
131
- const checkForFileExistence = async (filepath) => {
148
+ const checkForFileExistence = async (filepath, skip = false) => {
132
149
  if (fs.existsSync(filepath)) {
133
150
  const dirname = path.dirname(filepath);
134
151
  const ext = path.extname(filepath);
135
152
 
136
153
  let filename = path.basename(filepath);
137
154
 
138
- log.warn(`${filename} already exists in ${dirname}.\n`);
155
+ log.warn(`${filename} already exists.\n`);
139
156
 
140
157
  let override = await p.confirm({
141
158
  message: `Override ${filename}?`,
@@ -147,6 +164,8 @@ export async function create(entry, { templateName } = {}) {
147
164
  handleCancelledPrompt(override, prefix);
148
165
 
149
166
  if (!override) {
167
+ if (skip) return '';
168
+
150
169
  filename = await p.text({
151
170
  message: 'Pick a different name:',
152
171
  placeholder: ` `,
@@ -214,6 +233,33 @@ export async function create(entry, { templateName } = {}) {
214
233
  newFiles.push(dest);
215
234
  }
216
235
 
236
+ if (typescript) {
237
+ let dest = path.join(cwd, `tsconfig.json`);
238
+
239
+ log.info(`Creating tsconfig.json in ${dest}...`);
240
+
241
+ dest = await checkForFileExistence(dest, true);
242
+
243
+ if (dest) {
244
+ const fragmentTsConfigPath = await createTsConfigFile(cwd);
245
+
246
+ const tsConfigCode = `
247
+ // Generated by Fragment.
248
+ {
249
+ // https://github.com/raphaelameaume/fragment
250
+ "extends": "./${path.relative(path.dirname(dest), fragmentTsConfigPath)}",
251
+ "compilerOptions": {
252
+ "types": ["${path.relative(path.dirname(dest), path.join(__dirname, 'src/types/client.d.ts'))}"]
253
+ }
254
+ }
255
+ `;
256
+
257
+ await writeFile(dest, tsConfigCode);
258
+
259
+ log.success(`Created tsconfig.json in ${dest}\n`);
260
+ }
261
+ }
262
+
217
263
  log.success(
218
264
  `Done in ${prettifyTime(Date.now() - startTime)}\n`,
219
265
  prefix,
@@ -228,7 +274,10 @@ export async function create(entry, { templateName } = {}) {
228
274
  nextSteps += `${dim(`${i++}. Install dependencies`)}\n${bold(cyan(`${packageManager} install ${template.dependencies.join(' ')}`))}\n\n`;
229
275
  }
230
276
 
231
- nextSteps += `${dim(`${i++}. Start Fragment`)}\n${bold(cyan(`fragment ${path.relative(cwd, newFiles[newFiles.length - 1])}`))}`;
277
+ const regex = new RegExp(`${filename}\.(js|ts)$`);
278
+ const newIndexFile = newFiles.findLast((file) => regex.test(file));
279
+
280
+ nextSteps += `${dim(`${i++}. Start Fragment`)}\n${bold(cyan(`fragment ${path.relative(cwd, newIndexFile ?? entry)}`))}`;
232
281
 
233
282
  p.note(nextSteps, 'Next steps');
234
283
  } catch (error) {
@@ -4,7 +4,7 @@ import { defineConfig, loadConfigFromFile, mergeConfig } from 'vite';
4
4
  import { svelte } from '@sveltejs/vite-plugin-svelte';
5
5
 
6
6
  import checkDependencies from './plugins/check-dependencies.js';
7
- import { file } from './utils.js';
7
+ import { __dirname, file } from './utils.js';
8
8
  import { log } from './log.js';
9
9
  import sketches from './plugins/sketches.js';
10
10
 
@@ -43,7 +43,6 @@ export async function loadConfig({ cwd, filepath }) {
43
43
  /**
44
44
  * Create Vite config from entries
45
45
  * @param {string[]} entries
46
- * @param {string} fragmentFilepath
47
46
  * @param {options} options
48
47
  * @param {boolean} [options.dev=false]
49
48
  * @param {boolean} [options.build=false]
@@ -52,7 +51,6 @@ export async function loadConfig({ cwd, filepath }) {
52
51
  */
53
52
  export async function createConfig(
54
53
  entries,
55
- fragmentFilepath,
56
54
  { dev = false, build = false } = {},
57
55
  configFilepath,
58
56
  cwd = process.cwd(),
@@ -76,25 +74,13 @@ export async function createConfig(
76
74
  logLevel: dev ? 'info' : 'silent',
77
75
  publicDir,
78
76
  resolve: {
79
- alias: [
80
- {
81
- find: '@fragment/sketches',
82
- replacement: fragmentFilepath,
83
- },
84
- { find: '@fragment', replacement: app },
85
- {
86
- find: 'three',
87
- replacement: path.join(cwd, 'node_modules/three'),
88
- },
89
- {
90
- find: 'p5',
91
- replacement: path.join(cwd, 'node_modules/p5'),
92
- },
93
- {
94
- find: 'ogl',
95
- replacement: path.join(cwd, 'node_modules/ogl'),
96
- },
97
- ],
77
+ alias: {
78
+ '@fragment/types': path.join(__dirname, 'src/types'),
79
+ '@fragment': path.join(__dirname, 'src/client/app'),
80
+ three: path.join(cwd, 'node_modules/three'),
81
+ p5: path.join(cwd, 'node_modules/p5'),
82
+ ogl: path.join(cwd, 'node_modules/ogl'),
83
+ },
98
84
  },
99
85
  plugins: [
100
86
  svelte({
@@ -125,7 +111,6 @@ export async function createConfig(
125
111
  },
126
112
  optimizeDeps: {
127
113
  include: ['convert-length', 'webm-writer', 'changedpi'],
128
- exclude: ['@fragment/sketches', ...entriesPaths],
129
114
  },
130
115
  }),
131
116
  config.vite ?? {},
@@ -1,67 +1,65 @@
1
1
  import path from 'node:path';
2
- import { writeFile } from 'node:fs/promises';
2
+ import { readFile, writeFile } from 'node:fs/promises';
3
3
  import { log } from './log.js';
4
- import { mkdirp } from './utils.js';
4
+ import { __dirname, file, mkdirp } from './utils.js';
5
+
6
+ export const FRAGMENT_DIRECTORY = '/.fragment';
5
7
 
6
8
  /**
7
- * Create local files needed by Fragment
8
- * @param {string[]} entries
9
+ * Create local tsconfig.json file
9
10
  * @param {string} cwd Current working directory
10
11
  * @returns {string}
11
12
  */
12
- export async function createFragmentFile(entries = [], cwd = process.cwd()) {
13
+ export async function createTsConfigFile(cwd = process.cwd()) {
13
14
  try {
14
- function getFilenameFromEntries(entries) {
15
- if (entries.length === 1) {
16
- const filename = path.parse(entries[0]).name;
17
-
18
- return `${filename}.js`;
19
- }
20
-
21
- return `sketches.js`;
22
- }
15
+ const dirpath = path.join(cwd, FRAGMENT_DIRECTORY);
16
+ const filepath = path.join(dirpath, 'tsconfig.json');
23
17
 
24
- log.info(`Generating files...`);
18
+ const fragmentPath = path.relative(dirpath, __dirname);
25
19
 
26
- const dir = '/node_modules/.fragment';
27
- const dirpath = path.join(cwd, dir);
28
- const filename = getFilenameFromEntries(entries);
29
- const filepath = path.join(dirpath, filename);
30
-
31
- // generate sketch index file
32
- const code = /* js */ `
20
+ // Generate tsconfig.json file
21
+ const tsConfigCode = `
33
22
  // This file is generated by Fragment. Do not edit it.
23
+ {
24
+ "compilerOptions": {
25
+ "target": "ESNext",
26
+ "useDefineForClassFields": true,
27
+ "module": "ESNext",
28
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
29
+ "skipLibCheck": true,
34
30
 
35
- export const sketches = {
36
- ${entries
37
- .map((entry) => {
38
- const entryPath = entry.split(path.sep).join(path.posix.sep);
39
- const relativeEntryPath = `../../${entry}`
40
- .split(path.sep)
41
- .join(path.posix.sep);
42
-
43
- return `"${entryPath}": () => import("${relativeEntryPath}")`;
44
- })
45
- .join(',')}
46
- };
31
+ /* Bundler mode */
32
+ "moduleResolution": "bundler",
33
+ "allowImportingTsExtensions": true,
34
+ "isolatedModules": true,
35
+ "esModuleInterop": false,
36
+ "moduleDetection": "force",
37
+ "resolveJsonModule": true,
38
+ "noEmit": true,
47
39
 
48
- export const onSketchReload = (fn) => {
49
- if (import.meta.hot) {
50
- import.meta.hot.data.onSketchChange = fn;
51
- }
52
- };
40
+ /* Linting */
41
+ "strict": true,
42
+ "allowJs": true,
43
+ "checkJs": false,
44
+ "noUnusedLocals": true,
45
+ "noUnusedParameters": true,
46
+ "noFallthroughCasesInSwitch": true,
47
+ "noUncheckedSideEffectImports": true,
48
+ "allowSyntheticDefaultImports": true,
49
+ "forceConsistentCasingInFileNames": true,
53
50
 
54
- if (import.meta.hot) {
55
- import.meta.hot.accept((m) => {
56
- if (typeof import.meta.hot.data.onSketchChange === "function") {
57
- import.meta.hot.data.onSketchChange(m);
58
- }
59
- });
51
+ /* Paths */
52
+ "paths": {
53
+ "@fragment/types": ["${path.join(fragmentPath, 'src/types')}"],
54
+ "@fragment/types/*": ["${path.join(fragmentPath, 'src/types')}/*"],
55
+ "@fragment/*": ["${path.join(fragmentPath, 'src/client/app')}/*"]
56
+ }
57
+ }
60
58
  }
61
59
  `;
62
60
 
63
61
  await mkdirp(dirpath);
64
- await writeFile(filepath, code);
62
+ await writeFile(filepath, tsConfigCode);
65
63
 
66
64
  return filepath;
67
65
  } catch (error) {
@@ -39,6 +39,8 @@ export async function getEntries(
39
39
 
40
40
  const entryPath = path.join(cwd, entry);
41
41
 
42
+ const allowedExtensions = ['.js', '.ts'];
43
+
42
44
  if (fs.existsSync(entryPath)) {
43
45
  const stats = await lstat(entryPath);
44
46
 
@@ -47,7 +49,9 @@ export async function getEntries(
47
49
  } else if (stats.isDirectory()) {
48
50
  const files = await readdir(entryPath);
49
51
  const sketchFiles = files
50
- .filter((file) => path.extname(file) === '.js')
52
+ .filter((file) =>
53
+ allowedExtensions.includes(path.extname(file)),
54
+ )
51
55
  .map((file) => path.join(entryPath, file));
52
56
 
53
57
  if (sketchFiles.length > 0) {
@@ -63,10 +67,14 @@ export async function getEntries(
63
67
  } else {
64
68
  onError(`${path.join(cwd, entry)} does not exist.\n`);
65
69
 
66
- const entryWithExt = addExtension(entry, '.js');
67
- const fileExists = fs.existsSync(path.join(cwd, entryWithExt));
70
+ const entriesWithExt = allowedExtensions.map((ext) =>
71
+ addExtension(entry, ext),
72
+ );
73
+ const entryWithExt = entriesWithExt.find((entryWithExt) =>
74
+ fs.existsSync(path.join(cwd, entryWithExt)),
75
+ );
68
76
 
69
- if (fileExists) {
77
+ if (typeof entryWithExt !== 'undefined') {
70
78
  log.message(`Did you mean to type?\n`);
71
79
 
72
80
  displayCommand(`fragment ${entryWithExt}`);
@@ -74,7 +82,7 @@ export async function getEntries(
74
82
  log.message(
75
83
  `Run the following command to start a new sketch:\n`,
76
84
  );
77
- displayCommand(`fragment ${entryWithExt} --new`);
85
+ displayCommand(`fragment ${entriesWithExt[0]} --new`);
78
86
  }
79
87
  }
80
88
 
@@ -20,7 +20,7 @@ export default function checkDependencies({
20
20
  build,
21
21
  } = {}) {
22
22
  const regex =
23
- /\bexport[\s]*\b(let|const)[\s]*\brendering\b[\s]*=[\s]*["'](.*?)["']/;
23
+ /\bexport\s+\b(let|const)\s+\brendering\b\s*(?::\s*\w+)?\s*=\s*["'](.*?)["']/;
24
24
 
25
25
  const dependenciesMap = new Map();
26
26
  dependenciesMap.set('three', ['three']);
package/src/cli/run.js CHANGED
@@ -1,6 +1,11 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
1
3
  import { createServer, mergeConfig } from 'vite';
2
4
  import { createConfig } from './createConfig.js';
3
- import { createFragmentFile } from './createFragmentFile.js';
5
+ import {
6
+ createTsConfigFile,
7
+ FRAGMENT_DIRECTORY,
8
+ } from './createFragmentFile.js';
4
9
  import { getEntries } from './getEntries.js';
5
10
  import { log, magenta, bold, cyan, red } from './log.js';
6
11
  import save from './plugins/save.js';
@@ -17,6 +22,7 @@ import hotShaderReplacement from './plugins/hot-shader-replacement.js';
17
22
  * @param {boolean} options.development
18
23
  * @param {number} options.port
19
24
  * @param {number} options.exportDir
25
+ * @param {string} options.configFilepath
20
26
  */
21
27
  export async function run(entry, options = {}) {
22
28
  let fragmentServer;
@@ -56,7 +62,11 @@ export async function run(entry, options = {}) {
56
62
  );
57
63
  }
58
64
 
59
- const fragmentFilepath = await createFragmentFile(entries, cwd);
65
+ const tsConfigDirpath = path.join(cwd, FRAGMENT_DIRECTORY);
66
+ const tsConfigFilepath = path.join(tsConfigDirpath, 'tsconfig.json');
67
+ if (!fs.existsSync(tsConfigFilepath)) {
68
+ await createTsConfigFile(cwd);
69
+ }
60
70
 
61
71
  fragmentServer = await startWebSocketServer({
62
72
  cwd,
@@ -64,7 +74,6 @@ export async function run(entry, options = {}) {
64
74
 
65
75
  const config = await createConfig(
66
76
  entries,
67
- fragmentFilepath,
68
77
  {
69
78
  dev: options.development,
70
79
  build: false,
@@ -1,4 +1,4 @@
1
- export let props = {};
1
+ export const props = {};
2
2
 
3
3
  /**
4
4
  * @param {object} params
@@ -7,7 +7,7 @@ export let props = {};
7
7
  * @param {number} params.height
8
8
  * @param {number} params.pixelRatio
9
9
  */
10
- export let init = ({ canvas, width, height, pixelRatio }) => {};
10
+ export const init = ({ canvas, width, height, pixelRatio }) => {};
11
11
 
12
12
  /**
13
13
  * @param {object} params
@@ -21,7 +21,7 @@ export let init = ({ canvas, width, height, pixelRatio }) => {};
21
21
  * @param {number} params.playhead
22
22
  * @param {number} params.playcount
23
23
  */
24
- export let update = ({ width, height, time, deltaTime }) => {};
24
+ export const update = ({ width, height, time, deltaTime }) => {};
25
25
 
26
26
  /**
27
27
  * @param {object} params
@@ -30,7 +30,7 @@ export let update = ({ width, height, time, deltaTime }) => {};
30
30
  * @param {number} params.height
31
31
  * @param {number} params.pixelRatio
32
32
  */
33
- export let resize = ({ canvas, width, height, pixelRatio }) => {
33
+ export const resize = ({ canvas, width, height, pixelRatio }) => {
34
34
  canvas.width = width * pixelRatio;
35
35
  canvas.height = height * pixelRatio;
36
36
  canvas.style.width = `${width}px`;
@@ -0,0 +1,15 @@
1
+ import { Init, Resize, Update } from '@fragment/types';
2
+ import { defineProps } from '@fragment/types/utils';
3
+
4
+ export const props = defineProps({});
5
+
6
+ export const init: Init<any> = ({}) => {};
7
+
8
+ export const update: Update<any> = ({}) => {};
9
+
10
+ export const resize: Resize<any> = ({ canvas, width, height, pixelRatio }) => {
11
+ canvas.width = width * pixelRatio;
12
+ canvas.height = height * pixelRatio;
13
+ canvas.style.width = `${width}px`;
14
+ canvas.style.height = `${height}px`;
15
+ };