@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.
- package/README.md +60 -0
- package/dist/src/asset-pack/eslint.config.js +43 -0
- package/dist/src/asset-pack/scripts/postinstall.js +64 -0
- package/dist/src/asset-pack/src/index.js +1 -0
- package/dist/src/core/cli.js +306 -0
- package/dist/src/core/common.js +324 -0
- package/dist/src/core/index.js +6 -0
- package/dist/src/core/tools/build-project.js +450 -0
- package/dist/src/core/tools/index.js +2 -0
- package/dist/src/core/tools/new-asset-pack.js +150 -0
- package/dist/src/core/tools/new-project.js +292 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/dependencies.js +82 -0
- package/dist/src/electron/IpcSerializableError.js +38 -0
- package/dist/src/electron/api.js +7 -0
- package/dist/src/electron/backend/actions.js +56 -0
- package/dist/src/electron/backend/handler.js +441 -0
- package/dist/src/electron/backend/logging.js +41 -0
- package/dist/src/electron/backend/main.js +315 -0
- package/dist/src/electron/backend/menu.js +208 -0
- package/dist/src/electron/backend/state.js +201 -0
- package/dist/src/electron/backend/tools/const.js +9 -0
- package/dist/src/electron/backend/tools/file-server.js +383 -0
- package/dist/src/electron/backend/tools/open-project.js +261 -0
- package/dist/src/electron/backend/window.js +161 -0
- package/dist/src/templates/eslint.config.js +43 -0
- package/dist/src/templates/scripts/genesys/build-project.js +42 -0
- package/dist/src/templates/scripts/genesys/calc-bounding-box.js +205 -0
- package/dist/src/templates/scripts/genesys/common.js +36 -0
- package/dist/src/templates/scripts/genesys/const.js +9 -0
- package/dist/src/templates/scripts/genesys/dev/dump-default-scene.js +8 -0
- package/dist/src/templates/scripts/genesys/dev/generate-manifest.js +116 -0
- package/dist/src/templates/scripts/genesys/dev/launcher.js +39 -0
- package/dist/src/templates/scripts/genesys/dev/storage-provider.js +188 -0
- package/dist/src/templates/scripts/genesys/dev/update-template-scenes.js +67 -0
- package/dist/src/templates/scripts/genesys/doc-server.js +12 -0
- package/dist/src/templates/scripts/genesys/genesys-mcp.js +413 -0
- package/dist/src/templates/scripts/genesys/mcp/doc-tools.js +70 -0
- package/dist/src/templates/scripts/genesys/mcp/editor-functions.js +123 -0
- package/dist/src/templates/scripts/genesys/mcp/editor-tools.js +51 -0
- package/dist/src/templates/scripts/genesys/mcp/get-scene-state.js +26 -0
- package/dist/src/templates/scripts/genesys/mcp/run-subprocess.js +23 -0
- package/dist/src/templates/scripts/genesys/mcp/search-actors.js +703 -0
- package/dist/src/templates/scripts/genesys/mcp/search-assets.js +296 -0
- package/dist/src/templates/scripts/genesys/mcp/utils.js +234 -0
- package/dist/src/templates/scripts/genesys/misc.js +32 -0
- package/dist/src/templates/scripts/genesys/mock.js +5 -0
- package/dist/src/templates/scripts/genesys/place-actors.js +112 -0
- package/dist/src/templates/scripts/genesys/post-install.js +25 -0
- package/dist/src/templates/scripts/genesys/remove-engine-comments.js +113 -0
- package/dist/src/templates/scripts/genesys/storageProvider.js +146 -0
- package/dist/src/templates/scripts/genesys/validate-prefabs.js +115 -0
- package/dist/src/templates/src/index.js +20 -0
- package/dist/src/templates/src/templates/firstPerson/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/firstPerson/src/game.js +30 -0
- package/dist/src/templates/src/templates/firstPerson/src/player.js +60 -0
- package/dist/src/templates/src/templates/fps/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/fps/src/game.js +30 -0
- package/dist/src/templates/src/templates/fps/src/player.js +64 -0
- package/dist/src/templates/src/templates/fps/src/weapon.js +62 -0
- package/dist/src/templates/src/templates/freeCamera/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/freeCamera/src/game.js +30 -0
- package/dist/src/templates/src/templates/freeCamera/src/player.js +43 -0
- package/dist/src/templates/src/templates/sideScroller/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/sideScroller/src/const.js +43 -0
- package/dist/src/templates/src/templates/sideScroller/src/game.js +103 -0
- package/dist/src/templates/src/templates/sideScroller/src/level-generator.js +249 -0
- package/dist/src/templates/src/templates/sideScroller/src/player.js +105 -0
- package/dist/src/templates/src/templates/thirdPerson/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/thirdPerson/src/game.js +30 -0
- package/dist/src/templates/src/templates/thirdPerson/src/player.js +63 -0
- package/dist/src/templates/src/templates/vehicle/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/vehicle/src/base-vehicle.js +122 -0
- package/dist/src/templates/src/templates/vehicle/src/game.js +33 -0
- package/dist/src/templates/src/templates/vehicle/src/mesh-vehicle.js +189 -0
- package/dist/src/templates/src/templates/vehicle/src/player.js +102 -0
- package/dist/src/templates/src/templates/vehicle/src/primitive-vehicle.js +259 -0
- package/dist/src/templates/src/templates/vehicle/src/ui-hints.js +100 -0
- package/dist/src/templates/src/templates/vr-game/src/auto-imports.js +1 -0
- package/dist/src/templates/src/templates/vr-game/src/game.js +55 -0
- package/dist/src/templates/src/templates/vr-game/src/sample-vr-actor.js +29 -0
- package/dist/src/templates/vite.config.js +46 -0
- package/package.json +176 -0
- package/scripts/post-install.ts +143 -0
- package/src/asset-pack/.gitattributes +89 -0
- package/src/asset-pack/eslint.config.js +45 -0
- package/src/asset-pack/gitignore +11 -0
- package/src/asset-pack/scripts/postinstall.ts +81 -0
- package/src/asset-pack/src/index.ts +0 -0
- package/src/asset-pack/tsconfig.json +34 -0
- package/src/templates/.cursor/mcp.json +20 -0
- package/src/templates/.cursorignore +2 -0
- package/src/templates/.gitattributes +89 -0
- package/src/templates/.vscode/settings.json +6 -0
- package/src/templates/AGENTS.md +86 -0
- package/src/templates/CLAUDE.md +1 -0
- package/src/templates/README.md +24 -0
- package/src/templates/eslint.config.js +45 -0
- package/src/templates/gitignore +11 -0
- package/src/templates/index.html +34 -0
- package/src/templates/pnpm-lock.yaml +3676 -0
- package/src/templates/scripts/genesys/build-project.ts +51 -0
- package/src/templates/scripts/genesys/calc-bounding-box.ts +272 -0
- package/src/templates/scripts/genesys/common.ts +46 -0
- package/src/templates/scripts/genesys/const.ts +9 -0
- package/src/templates/scripts/genesys/dev/dump-default-scene.ts +11 -0
- package/src/templates/scripts/genesys/dev/generate-manifest.ts +146 -0
- package/src/templates/scripts/genesys/dev/launcher.ts +46 -0
- package/src/templates/scripts/genesys/dev/storage-provider.ts +229 -0
- package/src/templates/scripts/genesys/dev/update-template-scenes.ts +84 -0
- package/src/templates/scripts/genesys/doc-server.ts +16 -0
- package/src/templates/scripts/genesys/genesys-mcp.ts +526 -0
- package/src/templates/scripts/genesys/mcp/doc-tools.ts +86 -0
- package/src/templates/scripts/genesys/mcp/editor-functions.ts +151 -0
- package/src/templates/scripts/genesys/mcp/editor-tools.ts +73 -0
- package/src/templates/scripts/genesys/mcp/get-scene-state.ts +35 -0
- package/src/templates/scripts/genesys/mcp/run-subprocess.ts +30 -0
- package/src/templates/scripts/genesys/mcp/search-actors.ts +858 -0
- package/src/templates/scripts/genesys/mcp/search-assets.ts +380 -0
- package/src/templates/scripts/genesys/mcp/utils.ts +281 -0
- package/src/templates/scripts/genesys/misc.ts +42 -0
- package/src/templates/scripts/genesys/mock.ts +6 -0
- package/src/templates/scripts/genesys/place-actors.ts +179 -0
- package/src/templates/scripts/genesys/post-install.ts +30 -0
- package/src/templates/scripts/genesys/prefab.schema.json +85 -0
- package/src/templates/scripts/genesys/remove-engine-comments.ts +135 -0
- package/src/templates/scripts/genesys/run-mcp-inspector.bat +5 -0
- package/src/templates/scripts/genesys/storageProvider.ts +182 -0
- package/src/templates/scripts/genesys/validate-prefabs.ts +138 -0
- package/src/templates/src/index.ts +22 -0
- package/src/templates/src/templates/firstPerson/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/firstPerson/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/firstPerson/src/game.ts +39 -0
- package/src/templates/src/templates/firstPerson/src/player.ts +63 -0
- package/src/templates/src/templates/fps/assets/default.genesys-scene +9460 -0
- package/src/templates/src/templates/fps/assets/models/SM_Beam_400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_ChamferCube.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thick_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Floor_Thin_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Ramp_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Rifle.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x200_Orange.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400.glb +0 -0
- package/src/templates/src/templates/fps/assets/models/SM_Wall_Thin_400x400_Orange.glb +0 -0
- package/src/templates/src/templates/fps/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/fps/src/game.ts +39 -0
- package/src/templates/src/templates/fps/src/player.ts +69 -0
- package/src/templates/src/templates/fps/src/weapon.ts +54 -0
- package/src/templates/src/templates/freeCamera/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/freeCamera/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/freeCamera/src/game.ts +39 -0
- package/src/templates/src/templates/freeCamera/src/player.ts +45 -0
- package/src/templates/src/templates/sideScroller/assets/default.genesys-scene +122 -0
- package/src/templates/src/templates/sideScroller/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/sideScroller/src/const.ts +46 -0
- package/src/templates/src/templates/sideScroller/src/game.ts +122 -0
- package/src/templates/src/templates/sideScroller/src/level-generator.ts +361 -0
- package/src/templates/src/templates/sideScroller/src/player.ts +125 -0
- package/src/templates/src/templates/thirdPerson/assets/default.genesys-scene +166 -0
- package/src/templates/src/templates/thirdPerson/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/thirdPerson/src/game.ts +39 -0
- package/src/templates/src/templates/thirdPerson/src/player.ts +61 -0
- package/src/templates/src/templates/vehicle/assets/default.genesys-scene +226 -0
- package/src/templates/src/templates/vehicle/assets/models/cyberTruck/chassis.glb +0 -0
- package/src/templates/src/templates/vehicle/assets/models/cyberTruck/wheel.glb +0 -0
- package/src/templates/src/templates/vehicle/src/auto-imports.ts +0 -0
- package/src/templates/src/templates/vehicle/src/base-vehicle.ts +145 -0
- package/src/templates/src/templates/vehicle/src/game.ts +43 -0
- package/src/templates/src/templates/vehicle/src/mesh-vehicle.ts +191 -0
- package/src/templates/src/templates/vehicle/src/player.ts +109 -0
- package/src/templates/src/templates/vehicle/src/primitive-vehicle.ts +266 -0
- package/src/templates/src/templates/vehicle/src/ui-hints.ts +101 -0
- package/src/templates/src/templates/vr-game/assets/default.genesys-scene +247 -0
- package/src/templates/src/templates/vr-game/src/auto-imports.ts +1 -0
- package/src/templates/src/templates/vr-game/src/game.ts +66 -0
- package/src/templates/src/templates/vr-game/src/sample-vr-actor.ts +26 -0
- package/src/templates/tsconfig.json +35 -0
- 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
|
+
}
|