@directivegames/genesys.sdk 3.2.2

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 (181) hide show
  1. package/README.md +60 -0
  2. package/dist/src/asset-pack/eslint.config.js +43 -0
  3. package/dist/src/asset-pack/scripts/postinstall.js +64 -0
  4. package/dist/src/asset-pack/src/index.js +1 -0
  5. package/dist/src/core/cli.js +306 -0
  6. package/dist/src/core/common.js +324 -0
  7. package/dist/src/core/index.js +6 -0
  8. package/dist/src/core/tools/build-project.js +450 -0
  9. package/dist/src/core/tools/index.js +2 -0
  10. package/dist/src/core/tools/new-asset-pack.js +150 -0
  11. package/dist/src/core/tools/new-project.js +292 -0
  12. package/dist/src/core/types.js +1 -0
  13. package/dist/src/dependencies.js +82 -0
  14. package/dist/src/electron/IpcSerializableError.js +38 -0
  15. package/dist/src/electron/api.js +7 -0
  16. package/dist/src/electron/backend/actions.js +56 -0
  17. package/dist/src/electron/backend/handler.js +441 -0
  18. package/dist/src/electron/backend/logging.js +41 -0
  19. package/dist/src/electron/backend/main.js +315 -0
  20. package/dist/src/electron/backend/menu.js +208 -0
  21. package/dist/src/electron/backend/state.js +201 -0
  22. package/dist/src/electron/backend/tools/const.js +9 -0
  23. package/dist/src/electron/backend/tools/file-server.js +383 -0
  24. package/dist/src/electron/backend/tools/open-project.js +261 -0
  25. package/dist/src/electron/backend/window.js +161 -0
  26. package/dist/src/templates/eslint.config.js +43 -0
  27. package/dist/src/templates/scripts/genesys/build-project.js +42 -0
  28. package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
  29. package/dist/src/templates/scripts/genesys/common.js +36 -0
  30. package/dist/src/templates/scripts/genesys/const.js +9 -0
  31. package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
  32. package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
  33. package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
  34. package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
  35. package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
  36. package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
  37. package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
  38. package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
  39. package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
  40. package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
  41. package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
  42. package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
  43. package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
  44. package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
  45. package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
  46. package/dist/src/templates/scripts/genesys/misc.js +32 -0
  47. package/dist/src/templates/scripts/genesys/mock.js +5 -0
  48. package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
  49. package/dist/src/templates/scripts/genesys/post-install.js +25 -0
  50. package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
  51. package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
  52. package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
  53. package/dist/src/templates/src/index.js +20 -0
  54. package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
  55. package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
  56. package/dist/src/templates/src/templates/firstPerson/src/player.js +60 -0
  57. package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
  58. package/dist/src/templates/src/templates/fps/src/game.js +30 -0
  59. package/dist/src/templates/src/templates/fps/src/player.js +64 -0
  60. package/dist/src/templates/src/templates/fps/src/weapon.js +62 -0
  61. package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
  62. package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
  63. package/dist/src/templates/src/templates/freeCamera/src/player.js +43 -0
  64. package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
  65. package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
  66. package/dist/src/templates/src/templates/sideScroller/src/game.js +103 -0
  67. package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
  68. package/dist/src/templates/src/templates/sideScroller/src/player.js +105 -0
  69. package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
  70. package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
  71. package/dist/src/templates/src/templates/thirdPerson/src/player.js +63 -0
  72. package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
  73. package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
  74. package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
  75. package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +189 -0
  76. package/dist/src/templates/src/templates/vehicle/src/player.js +102 -0
  77. package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +259 -0
  78. package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
  79. package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
  80. package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
  81. package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
  82. package/dist/src/templates/vite.config.js +46 -0
  83. package/package.json +176 -0
  84. package/scripts/post-install.ts +143 -0
  85. package/src/asset-pack/.gitattributes +89 -0
  86. package/src/asset-pack/eslint.config.js +45 -0
  87. package/src/asset-pack/gitignore +11 -0
  88. package/src/asset-pack/scripts/postinstall.ts +81 -0
  89. package/src/asset-pack/src/index.ts +0 -0
  90. package/src/asset-pack/tsconfig.json +34 -0
  91. package/src/templates/.cursor/mcp.json +20 -0
  92. package/src/templates/.cursorignore +2 -0
  93. package/src/templates/.gitattributes +89 -0
  94. package/src/templates/.vscode/settings.json +6 -0
  95. package/src/templates/AGENTS.md +86 -0
  96. package/src/templates/CLAUDE.md +1 -0
  97. package/src/templates/README.md +24 -0
  98. package/src/templates/eslint.config.js +45 -0
  99. package/src/templates/gitignore +11 -0
  100. package/src/templates/index.html +34 -0
  101. package/src/templates/pnpm-lock.yaml +3676 -0
  102. package/src/templates/scripts/genesys/build-project.ts +51 -0
  103. package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
  104. package/src/templates/scripts/genesys/common.ts +46 -0
  105. package/src/templates/scripts/genesys/const.ts +9 -0
  106. package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
  107. package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
  108. package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
  109. package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
  110. package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
  111. package/src/templates/scripts/genesys/doc-server.ts +16 -0
  112. package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
  113. package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
  114. package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
  115. package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
  116. package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
  117. package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
  118. package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
  119. package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
  120. package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
  121. package/src/templates/scripts/genesys/misc.ts +42 -0
  122. package/src/templates/scripts/genesys/mock.ts +6 -0
  123. package/src/templates/scripts/genesys/place-actors.ts +179 -0
  124. package/src/templates/scripts/genesys/post-install.ts +30 -0
  125. package/src/templates/scripts/genesys/prefab.schema.json +85 -0
  126. package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
  127. package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
  128. package/src/templates/scripts/genesys/storageProvider.ts +182 -0
  129. package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
  130. package/src/templates/src/index.ts +22 -0
  131. package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
  132. package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
  133. package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
  134. package/src/templates/src/templates/firstPerson/src/player.ts +63 -0
  135. package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
  136. package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
  137. package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
  138. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
  139. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
  140. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
  141. package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
  142. package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
  143. package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
  144. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
  145. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
  146. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
  147. package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
  148. package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
  149. package/src/templates/src/templates/fps/src/game.ts +39 -0
  150. package/src/templates/src/templates/fps/src/player.ts +69 -0
  151. package/src/templates/src/templates/fps/src/weapon.ts +54 -0
  152. package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
  153. package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
  154. package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
  155. package/src/templates/src/templates/freeCamera/src/player.ts +45 -0
  156. package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
  157. package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
  158. package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
  159. package/src/templates/src/templates/sideScroller/src/game.ts +122 -0
  160. package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
  161. package/src/templates/src/templates/sideScroller/src/player.ts +125 -0
  162. package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
  163. package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
  164. package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
  165. package/src/templates/src/templates/thirdPerson/src/player.ts +61 -0
  166. package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
  167. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
  168. package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
  169. package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
  170. package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
  171. package/src/templates/src/templates/vehicle/src/game.ts +43 -0
  172. package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +191 -0
  173. package/src/templates/src/templates/vehicle/src/player.ts +109 -0
  174. package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +266 -0
  175. package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
  176. package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
  177. package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
  178. package/src/templates/src/templates/vr-game/src/game.ts +66 -0
  179. package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
  180. package/src/templates/tsconfig.json +35 -0
  181. package/src/templates/vite.config.ts +52 -0
@@ -0,0 +1,292 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import * as ENGINE from 'genesys.js';
4
+ import { ALL_DEPENDENCIES } from '../../dependencies.js';
5
+ import { deletedTemplateItems, sharedTemplateItems } from '../../templates/src/index.js';
6
+ import { copyAsync, existsAsync, getEngineVersion, getProjectRoot, mkdirAsync, readdirAsync, runCommandAsync, writeFileAsync } from '../common.js';
7
+ import { IgnoredFiles } from '../index.js';
8
+ // Available project templates
9
+ export const TEMPLATES = [
10
+ { id: 'fps', name: 'FPS', path: 'src/templates/fps', description: 'First person shooter template' },
11
+ { id: 'freeCamera', name: 'Free Camera Movement', path: 'src/templates/freeCamera', description: 'Free Camera Movement template' },
12
+ { id: 'firstPerson', name: '1st Person Movement', path: 'src/templates/firstPerson', description: '1st Person Movement template' },
13
+ { id: 'thirdPerson', name: '3rd Person Movement', path: 'src/templates/thirdPerson', description: '3rd Person Movement template' },
14
+ { id: 'sideScroller', name: 'Side Scroller', path: 'src/templates/sideScroller', description: 'Side Scroller template' },
15
+ { id: 'vehicle', name: 'Vehicle', path: 'src/templates/vehicle', description: 'Vehicle template' },
16
+ { id: 'vrGame', name: 'VR Game', path: 'src/templates/vr-game', description: 'VR Game template' },
17
+ ];
18
+ export const projectFiles = {
19
+ packageJson: {
20
+ name: '',
21
+ version: '0.0.1',
22
+ scripts: {
23
+ 'build': 'tsc',
24
+ 'build-project': 'pnpm exec tsx ./scripts/genesys/build-project.ts',
25
+ 'postinstall': 'pnpm exec tsx ./scripts/genesys/post-install.ts',
26
+ 'lint': 'eslint . --fix --ext .ts,.tsx',
27
+ 'remove-engine-comments': 'pnpm exec tsx ./scripts/genesys/remove-engine-comments.ts',
28
+ 'dev': 'pnpm exec tsx ./scripts/genesys/dev/generate-manifest.ts && vite',
29
+ 'validate-prefabs': 'pnpm exec tsx ./scripts/genesys/validate-prefabs.ts',
30
+ },
31
+ keywords: [],
32
+ type: 'module',
33
+ dependencies: {
34
+ 'genesys.js': `${getEngineVersion()}`,
35
+ 'three': ALL_DEPENDENCIES['three'],
36
+ },
37
+ devDependencies: {
38
+ '@types/three': ALL_DEPENDENCIES['@types/three'],
39
+ 'nanoid': ALL_DEPENDENCIES['nanoid'],
40
+ 'ajv': ALL_DEPENDENCIES['ajv'],
41
+ 'esbuild': ALL_DEPENDENCIES['esbuild'],
42
+ 'canvas': '3.1.0',
43
+ 'get-port': '7.1.0',
44
+ 'zod-to-json-schema': '3.24.6',
45
+ 'ws': '8.18.2',
46
+ '@types/node': '22.15.21',
47
+ '@types/jsdom': '21.1.7',
48
+ '@modelcontextprotocol/sdk': '1.22.0',
49
+ 'tsx': '4.20.3', // pin the tsx version to avoid import issues of the @webxr-input-profiles/motion-controllers module in game projects
50
+ 'zod': '3.24.4',
51
+ 'jsdom': '26.1.0',
52
+ 'typescript': '5.8.3',
53
+ 'vite': '7.1.7',
54
+ 'vite-plugin-mkcert': '1.17.8',
55
+ 'vite-plugin-node-polyfills': '0.24.0',
56
+ '@typescript-eslint/parser': '8.29.1',
57
+ '@typescript-eslint/utils': '8.38.0',
58
+ 'eslint': '9.24.0',
59
+ '@types/ws': '8.18.1',
60
+ 'ts-morph': '26.0.0',
61
+ }
62
+ },
63
+ codeWorkspace: {
64
+ folders: [
65
+ {
66
+ path: '.'
67
+ },
68
+ {
69
+ path: './.engine'
70
+ }
71
+ ],
72
+ settings: {
73
+ ['editor.tabSize']: 2
74
+ }
75
+ },
76
+ genesysProject: {
77
+ [ENGINE.DEFAULT_SCENE_KEY]: `./${ENGINE.ASSETS_FOLDER}/default${ENGINE.SCENE_NAME_EXT}`,
78
+ [ENGINE.DEFAULT_EDITOR_SCENE_KEY]: `./${ENGINE.ASSETS_FOLDER}/default${ENGINE.SCENE_NAME_EXT}`,
79
+ [ENGINE.ENGINE_VERSION_KEY]: getEngineVersion()
80
+ }
81
+ };
82
+ export function getTemplatePath(isPackaged, resourcesPath, projectRoot) {
83
+ const packageName = 'src/templates';
84
+ if (isPackaged) {
85
+ return path.join(resourcesPath, 'vendor', packageName);
86
+ }
87
+ else {
88
+ return path.join(projectRoot, packageName);
89
+ }
90
+ }
91
+ export async function copySharedTemplateToProject(projectPath, templatePackagePath, logger) {
92
+ for (const sharedTemplateItem of sharedTemplateItems) {
93
+ const sourcePath = path.join(templatePackagePath, sharedTemplateItem);
94
+ // gitignore is renamed to .gitignore when copied to the project
95
+ // (npm excludes .gitignore files from packages)
96
+ const destinationName = sharedTemplateItem === 'gitignore' ? '.gitignore' : sharedTemplateItem;
97
+ const destinatePath = path.join(projectPath, destinationName);
98
+ if (!(await existsAsync(sourcePath))) {
99
+ logger.error(`${sourcePath} not found, skipping...`);
100
+ continue;
101
+ }
102
+ await copyAsync(sourcePath, destinatePath, { recursive: true });
103
+ }
104
+ for (const deletedTemplateItem of deletedTemplateItems) {
105
+ const filePath = path.join(projectPath, deletedTemplateItem);
106
+ if (await existsAsync(filePath)) {
107
+ await fs.promises.unlink(filePath);
108
+ }
109
+ }
110
+ // copy .gitignore to .npmignore, which is used by pnpm pack
111
+ const gitIgnorePath = path.join(projectPath, '.gitignore');
112
+ const npmIgnorePath = path.join(projectPath, '.npmignore');
113
+ await copyAsync(gitIgnorePath, npmIgnorePath);
114
+ }
115
+ export function getProjectNameFromPath(projectPath) {
116
+ return path.basename(projectPath).replace(' ', '-');
117
+ }
118
+ export function getGenesysProjectFile(projectPath) {
119
+ const projectName = getProjectNameFromPath(projectPath);
120
+ return path.join(projectPath, `${projectName}${ENGINE.GAME_PROJECT_FILE_EXT}`);
121
+ }
122
+ export async function createGenesysProjectFile(projectPath) {
123
+ const filePath = getGenesysProjectFile(projectPath);
124
+ if (await existsAsync(filePath)) {
125
+ return filePath;
126
+ }
127
+ await writeFileAsync(filePath, JSON.stringify(projectFiles.genesysProject, null, 2));
128
+ return filePath;
129
+ }
130
+ export async function migrateGenesysProjectFileForScenes(projectPath) {
131
+ const projectName = getProjectNameFromPath(projectPath);
132
+ const filePath = path.join(projectPath, `${projectName}${ENGINE.GAME_PROJECT_FILE_EXT}`);
133
+ if (await existsAsync(filePath)) {
134
+ // Migration logic would go here if needed
135
+ }
136
+ }
137
+ export async function newProject(parentPath, projectName, templateId, logger, handler) {
138
+ const projectPath = path.join(parentPath, projectName);
139
+ // Calculate template path using handler's app properties
140
+ const templatePackagePath = getTemplatePath(handler.app.isPackaged, handler.app.resourcesPath, getProjectRoot());
141
+ const template = TEMPLATES.find(t => t.id === templateId);
142
+ if (!template) {
143
+ return {
144
+ success: false,
145
+ message: `Template ${templateId} not found`,
146
+ path: projectPath
147
+ };
148
+ }
149
+ // Validate project name - only allow English characters, numbers, hyphens, underscores, and dots
150
+ const validNameRegex = /^[a-zA-Z0-9_.-]+$/;
151
+ if (!validNameRegex.test(projectName)) {
152
+ return {
153
+ success: false,
154
+ message: `Invalid project name "${projectName}". Project name can only contain English characters (a-z, A-Z), numbers (0-9), hyphens (-), underscores (_), and dots (.).`,
155
+ path: projectPath
156
+ };
157
+ }
158
+ const createProjectMessage = `Creating project at ${projectPath} using ${templateId} template`;
159
+ logger.log(createProjectMessage);
160
+ handler?.ui.showLoadingOverlay(`Creating project...\n${createProjectMessage}`);
161
+ try {
162
+ if (await existsAsync(projectPath)) {
163
+ // Check if directory is empty
164
+ const files = (await readdirAsync(projectPath)).filter(file => !IgnoredFiles.includes(file));
165
+ if (files.length > 0) {
166
+ return {
167
+ success: false,
168
+ message: `The directory ${projectPath} already contains files. Please choose an empty directory.`,
169
+ path: projectPath
170
+ };
171
+ }
172
+ }
173
+ else {
174
+ await mkdirAsync(projectPath, { recursive: true });
175
+ }
176
+ // Overall project creation progress tracking
177
+ let overallProgress = 0;
178
+ const totalSteps = 5;
179
+ // Step 1: Creating directories (0-5%)
180
+ logger.log('Creating default scene and game code...');
181
+ handler?.ui.showLoadingOverlay('Creating project 0%\nStep 1/5 ▶ Creating directories...');
182
+ await new Promise(resolve => setTimeout(resolve, 300));
183
+ handler?.ui.showLoadingOverlay('Creating project 2%\nStep 1/5 ▶ Creating directories...');
184
+ await Promise.all([
185
+ mkdirAsync(path.join(projectPath, `${ENGINE.ASSETS_FOLDER}/models`), { recursive: true }),
186
+ mkdirAsync(path.join(projectPath, `${ENGINE.ASSETS_FOLDER}/textures`), { recursive: true }),
187
+ mkdirAsync(path.join(projectPath, `${ENGINE.ASSETS_FOLDER}/sounds`), { recursive: true })
188
+ ]);
189
+ overallProgress = 5;
190
+ handler?.ui.showLoadingOverlay('Creating project 5%\nStep 1/5 ▶ Directories created ✅');
191
+ await new Promise(resolve => setTimeout(resolve, 300));
192
+ // Step 2: Creating project files (5-10%)
193
+ logger.log('Creating project files...');
194
+ handler?.ui.showLoadingOverlay('Creating project 5%\nStep 2/5 ▶ Generating project files...');
195
+ await new Promise(resolve => setTimeout(resolve, 300));
196
+ const packageJson = { ...projectFiles.packageJson }; // Create a copy to avoid mutation
197
+ packageJson.name = projectName;
198
+ handler?.ui.showLoadingOverlay('Creating project 7%\nStep 2/5 ▶ Generating project files...');
199
+ const [, , projectFileFullPath] = await Promise.all([
200
+ writeFileAsync(path.join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2)),
201
+ writeFileAsync(path.join(projectPath, `${projectName}.code-workspace`), JSON.stringify(projectFiles.codeWorkspace, null, 2)),
202
+ createGenesysProjectFile(projectPath)
203
+ ]);
204
+ overallProgress = 8;
205
+ handler?.ui.showLoadingOverlay('Creating project 8%\nStep 2/5 ▶ Copying template files...');
206
+ // Copy template files
207
+ logger.log('Copying other project files...');
208
+ const individualTemplatePath = path.join(templatePackagePath, template.path);
209
+ await Promise.all([
210
+ copySharedTemplateToProject(projectPath, templatePackagePath, logger),
211
+ copyAsync(individualTemplatePath, projectPath, { recursive: true })
212
+ ]);
213
+ overallProgress = 10;
214
+ handler?.ui.showLoadingOverlay('Creating project 10%\nStep 2/5 ▶ Project files created ✅');
215
+ await new Promise(resolve => setTimeout(resolve, 300));
216
+ // Step 3: Installing dependencies (10-70%)
217
+ logger.log('Running pnpm install...');
218
+ handler?.ui.showLoadingOverlay('Creating project 10%\nStep 3/5 ▶ Installing dependencies...');
219
+ const installStartTime = Date.now();
220
+ const estimatedInstallTime = 35; // seconds
221
+ let installComplete = false;
222
+ let packageCount = '';
223
+ // Force UI updates every second with timer
224
+ const installInterval = setInterval(() => {
225
+ if (installComplete)
226
+ return;
227
+ const elapsed = (Date.now() - installStartTime) / 1000;
228
+ // Asymptotic progress: approaches 70% but never quite reaches it
229
+ const installProgress = Math.min(0.95, elapsed / estimatedInstallTime);
230
+ overallProgress = 10 + Math.floor(installProgress * 60);
231
+ handler?.ui.showLoadingOverlay(`Creating project ${overallProgress}%\nStep 3/5 ▶ Installing dependencies...`);
232
+ }, 1000);
233
+ await runCommandAsync('pnpm install', projectPath, logger, (progressMsg) => {
234
+ // Detect completion - pnpm uses different output format
235
+ if (progressMsg.match(/(\+|\d+) packages? in/i)) {
236
+ const countMatch = progressMsg.match(/(\d+) packages? in/i);
237
+ if (countMatch) {
238
+ packageCount = countMatch[1];
239
+ }
240
+ }
241
+ });
242
+ installComplete = true;
243
+ clearInterval(installInterval);
244
+ overallProgress = 70;
245
+ handler?.ui.showLoadingOverlay(`Creating project 70%\nStep 3/5 ▶ Installed ${packageCount} packages ✅`);
246
+ await new Promise(resolve => setTimeout(resolve, 500));
247
+ // Step 4: Building project (70-90%)
248
+ logger.log('Running pnpm build...');
249
+ handler?.ui.showLoadingOverlay('Creating project 70%\nStep 4/5 ▶ Building project...');
250
+ const buildStartTime = Date.now();
251
+ const estimatedBuildTime = 10; // seconds
252
+ let buildComplete = false;
253
+ // Force UI updates every second with timer
254
+ const buildInterval = setInterval(() => {
255
+ if (buildComplete)
256
+ return;
257
+ const elapsed = (Date.now() - buildStartTime) / 1000;
258
+ // Asymptotic progress: approaches 90% but never quite reaches it
259
+ const buildProgress = Math.min(0.95, elapsed / estimatedBuildTime);
260
+ overallProgress = 70 + Math.floor(buildProgress * 20);
261
+ handler?.ui.showLoadingOverlay(`Creating project ${overallProgress}%\nStep 4/5 ▶ Building project...`);
262
+ }, 1000);
263
+ await runCommandAsync('pnpm build', projectPath, logger);
264
+ buildComplete = true;
265
+ clearInterval(buildInterval);
266
+ overallProgress = 90;
267
+ handler?.ui.showLoadingOverlay('Creating project 90%\nStep 4/5 ▶ Build complete ✅');
268
+ await new Promise(resolve => setTimeout(resolve, 500));
269
+ // Step 5: Finalizing (90-100%)
270
+ handler?.ui.showLoadingOverlay('Creating project 95%\nStep 5/5 ▶ Finalizing...');
271
+ // open the project in the file explorer
272
+ handler?.os.openPath(projectPath);
273
+ await new Promise(resolve => setTimeout(resolve, 500));
274
+ overallProgress = 100;
275
+ logger.log('Project created successfully');
276
+ handler?.ui.showLoadingOverlay('Creating project 100%\n✅ Project created successfully!');
277
+ await new Promise(resolve => setTimeout(resolve, 1000));
278
+ return {
279
+ success: true,
280
+ message: `Project created successfully at ${projectPath} using ${templateId} template`,
281
+ path: projectFileFullPath
282
+ };
283
+ }
284
+ catch (error) {
285
+ return {
286
+ success: false,
287
+ message: `Failed to create project: ${error}`,
288
+ path: projectPath,
289
+ error: error,
290
+ };
291
+ }
292
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Auto-generated file containing all package dependencies and their exact installed versions.
3
+ * This file is generated by the post-install script.
4
+ * Do not edit manually - it will be overwritten on next install.
5
+ *
6
+ * Versions are extracted from pnpm-lock.yaml to show exact installed versions,
7
+ * not the version ranges from package.json.
8
+ *
9
+ * Includes dependencies from the main package.
10
+ */
11
+ export const DEPENDENCIES = {
12
+ '@electron/rebuild': '4.0.1',
13
+ '@emotion/react': '11.14.0',
14
+ '@emotion/styled': '11.14.1',
15
+ '@mui/icons-material': '7.3.5',
16
+ '@mui/lab': '7.0.0',
17
+ '@mui/material': '7.3.5',
18
+ 'chokidar': '4.0.3',
19
+ 'commander': '14.0.2',
20
+ 'core-util-is': '1.0.3',
21
+ 'cors': '2.8.5',
22
+ 'electron-devtools-installer': '4.0.0',
23
+ 'electron-is-dev': '3.0.1',
24
+ 'electron-log': '5.4.3',
25
+ 'electron-store': '11.0.2',
26
+ 'electron-updater': '6.6.2',
27
+ 'esbuild': '0.25.12',
28
+ 'express': '5.1.0',
29
+ 'fix-path': '4.0.0',
30
+ 'genesys.js': '3.1.24',
31
+ 'jsdom': '27.2.0',
32
+ 'minimatch': '10.1.1',
33
+ 'multer': '2.0.2',
34
+ 'node-abi': '4.24.0',
35
+ 'react': '19.2.0',
36
+ 'react-dom': '19.2.0',
37
+ 'three': '0.177.0',
38
+ 'upath': '2.0.1',
39
+ 'ws': '8.18.3',
40
+ 'zod': '3.25.76',
41
+ };
42
+ export const DEV_DEPENDENCIES = {
43
+ '@electron/notarize': '3.1.1',
44
+ '@modelcontextprotocol/sdk': '1.22.0',
45
+ '@types/cors': '2.8.19',
46
+ '@types/electron-store': '1.3.1',
47
+ '@types/express': '5.0.5',
48
+ '@types/jsdom': '27.0.0',
49
+ '@types/minimatch': '5.1.2',
50
+ '@types/multer': '1.4.13',
51
+ '@types/react': '19.2.7',
52
+ '@types/react-dom': '19.2.3',
53
+ '@types/three': '0.177.0',
54
+ '@types/ws': '8.18.1',
55
+ '@typescript-eslint/eslint-plugin': '8.48.0',
56
+ '@typescript-eslint/parser': '8.48.0',
57
+ '@vitejs/plugin-react': '4.7.0',
58
+ 'ajv': '8.17.1',
59
+ 'concurrently': '9.2.1',
60
+ 'dotenv-cli': '8.0.0',
61
+ 'electron': '39.2.3',
62
+ 'electron-builder': '26.0.12',
63
+ 'eslint': '9.39.1',
64
+ 'eslint-plugin-import': '2.32.0',
65
+ 'get-port': '7.1.0',
66
+ 'nanoid': '5.1.6',
67
+ 'nodemon': '3.1.11',
68
+ 'ts-morph': '27.0.2',
69
+ 'tsc-watch': '7.2.0',
70
+ 'tsx': '4.20.6',
71
+ 'typescript': '5.9.3',
72
+ 'vite': '6.4.1',
73
+ 'vite-plugin-mkcert': '1.17.9',
74
+ 'vite-plugin-node-polyfills': '0.24.0',
75
+ 'wait-on': '8.0.5',
76
+ 'yaml': '2.8.1',
77
+ 'zod-to-json-schema': '3.25.0',
78
+ };
79
+ export const ALL_DEPENDENCIES = {
80
+ ...DEPENDENCIES,
81
+ ...DEV_DEPENDENCIES,
82
+ };
@@ -0,0 +1,38 @@
1
+ // IpcSerializableError.ts
2
+ export class IpcSerializableError extends Error {
3
+ code;
4
+ data;
5
+ // Optionally include additional fields as needed
6
+ constructor(message, code, data) {
7
+ super(message);
8
+ this.code = code;
9
+ this.data = data;
10
+ this.name = this.constructor.name;
11
+ // Maintains proper stack trace in V8
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, this.constructor);
14
+ }
15
+ }
16
+ // Serialize for IPC
17
+ static serialize(err) {
18
+ const plain = {
19
+ __ipcError: true,
20
+ name: err.name,
21
+ message: err.message,
22
+ stack: err.stack,
23
+ // If extra fields exist, include them (optional)
24
+ ...err.code && { code: err.code },
25
+ ...err.data && { data: err.data },
26
+ };
27
+ return plain;
28
+ }
29
+ // Deserialize in renderer
30
+ static deserialize(obj) {
31
+ if (!obj || !obj.__ipcError)
32
+ return obj;
33
+ const error = new IpcSerializableError(obj.message, obj.code, obj.data);
34
+ error.name = obj.name;
35
+ error.stack = obj.stack;
36
+ return error;
37
+ }
38
+ }
@@ -0,0 +1,7 @@
1
+ export var AppStateKey;
2
+ (function (AppStateKey) {
3
+ AppStateKey["ProjectPath"] = "project.lastOpenedDirectory";
4
+ AppStateKey["ProjectParentPath"] = "project.lastParentDirectory";
5
+ AppStateKey["Projects"] = "projects";
6
+ AppStateKey["WindowState"] = "window.state";
7
+ })(AppStateKey || (AppStateKey = {}));
@@ -0,0 +1,56 @@
1
+ import { dialog } from 'electron';
2
+ import { AppStateKey } from '../api.js';
3
+ import { handlers } from './handler.js';
4
+ import { appState } from './state.js';
5
+ export async function showInExplorer() {
6
+ const lastOpenedDirectory = appState.getState(AppStateKey.ProjectPath);
7
+ if (lastOpenedDirectory) {
8
+ handlers.os.openPath(lastOpenedDirectory);
9
+ }
10
+ }
11
+ export async function buildProject(runTsc) {
12
+ try {
13
+ handlers.ui.showLoadingOverlay('Building Project...');
14
+ const lastOpenedDirectory = appState.getState(AppStateKey.ProjectPath);
15
+ if (lastOpenedDirectory) {
16
+ const result = await handlers.tools.buildProject(lastOpenedDirectory, runTsc);
17
+ if (!result.success) {
18
+ handlers.notifications.sendNotification('error', 'Build Project', result.message);
19
+ }
20
+ }
21
+ }
22
+ finally {
23
+ handlers.ui.hideLoadingOverlay();
24
+ }
25
+ }
26
+ export async function checkUpdates() {
27
+ await handlers.app.checkForUpdates(true);
28
+ }
29
+ export async function openAppLog() {
30
+ const appInfo = await handlers.app.getInfo();
31
+ await handlers.os.openPath(appInfo.logPath);
32
+ }
33
+ export async function deleteProject() {
34
+ const lastOpenedDirectory = appState.getState(AppStateKey.ProjectPath);
35
+ if (lastOpenedDirectory) {
36
+ const result = await handlers.tools.deleteProject(lastOpenedDirectory);
37
+ if (result.success) {
38
+ handlers.notifications.sendNotification('info', 'Delete Project', result.message);
39
+ }
40
+ else {
41
+ handlers.notifications.sendNotification('error', 'Delete Project', result.message);
42
+ appState.setState(AppStateKey.ProjectPath, undefined);
43
+ }
44
+ }
45
+ }
46
+ export async function showAbout(mainWindow) {
47
+ const appInfo = await handlers.app.getInfo();
48
+ let message = `App Version: ${appInfo.appVersion}\n`;
49
+ message += `Engine Version: ${appInfo.engineVersion}\n`;
50
+ dialog.showMessageBox(mainWindow, {
51
+ type: 'info',
52
+ buttons: ['OK'],
53
+ title: 'About',
54
+ message,
55
+ });
56
+ }