@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,25 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { getProjectRoot } from './common.js';
4
+ async function main() {
5
+ const engineInstallFolder = path.join(getProjectRoot(), 'node_modules/genesys.js');
6
+ if (!fs.existsSync(engineInstallFolder)) {
7
+ return;
8
+ }
9
+ const copiedEngineFolder = path.join(getProjectRoot(), '.engine');
10
+ if (fs.existsSync(copiedEngineFolder)) {
11
+ fs.rmdirSync(copiedEngineFolder, { recursive: true });
12
+ }
13
+ fs.mkdirSync(copiedEngineFolder, { recursive: true });
14
+ const foldersToCopy = [
15
+ 'games/examples',
16
+ 'src',
17
+ 'docs',
18
+ ];
19
+ for (const folder of foldersToCopy) {
20
+ const engineFolderPath = path.join(engineInstallFolder, folder);
21
+ const localFolderPath = path.join(copiedEngineFolder, folder);
22
+ fs.cpSync(engineFolderPath, localFolderPath, { recursive: true });
23
+ }
24
+ }
25
+ main();
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env tsx
2
+ import { readdir, readFile, stat, writeFile } from 'fs/promises';
3
+ import { join } from 'path';
4
+ /**
5
+ * Recursively finds all TypeScript files in a directory
6
+ */
7
+ async function findTsFiles(dir) {
8
+ const files = [];
9
+ try {
10
+ const entries = await readdir(dir);
11
+ for (const entry of entries) {
12
+ const fullPath = join(dir, entry);
13
+ const stats = await stat(fullPath);
14
+ if (stats.isDirectory()) {
15
+ const subFiles = await findTsFiles(fullPath);
16
+ files.push(...subFiles);
17
+ }
18
+ else if (entry.endsWith('.ts') || entry.endsWith('.tsx')) {
19
+ files.push(fullPath);
20
+ }
21
+ }
22
+ }
23
+ catch (error) {
24
+ console.warn(`Warning: Could not read directory ${dir}:`, error);
25
+ }
26
+ return files;
27
+ }
28
+ /**
29
+ * Removes comments from TypeScript code using regex
30
+ */
31
+ function removeComments(code) {
32
+ const originalLength = code.length;
33
+ // Remove single-line comments (// comments)
34
+ // This regex handles // comments but preserves URLs and string literals
35
+ let cleaned = code.replace(/^(\s*)\/\/.*$/gm, '$1');
36
+ // Remove multi-line comments (/* ... */ and /** ... */)
37
+ // This regex handles nested quotes and preserves strings
38
+ cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, '');
39
+ // Clean up multiple consecutive empty lines (replace with single empty line)
40
+ cleaned = cleaned.replace(/\n\s*\n\s*\n/g, '\n\n');
41
+ // Trim trailing whitespace on each line
42
+ cleaned = cleaned.replace(/[ \t]+$/gm, '');
43
+ const hadComments = cleaned.length !== originalLength || cleaned !== code;
44
+ return { cleaned, hadComments };
45
+ }
46
+ /**
47
+ * Removes comments from a TypeScript file
48
+ */
49
+ async function removeCommentsFromFile(filePath) {
50
+ try {
51
+ const content = await readFile(filePath, 'utf8');
52
+ const { cleaned, hadComments } = removeComments(content);
53
+ if (!hadComments) {
54
+ return false; // No comments to remove
55
+ }
56
+ await writeFile(filePath, cleaned, 'utf8');
57
+ return true;
58
+ }
59
+ catch (error) {
60
+ console.error(`Error processing file ${filePath}:`, error);
61
+ return false;
62
+ }
63
+ }
64
+ async function main() {
65
+ const engineDir = '.engine';
66
+ console.log(`Searching for TypeScript files in ${engineDir}...`);
67
+ console.log(`Current working directory: ${process.cwd()}`);
68
+ try {
69
+ const tsFiles = await findTsFiles(engineDir);
70
+ console.log(`Found ${tsFiles.length} TypeScript files.`);
71
+ if (tsFiles.length > 0) {
72
+ console.log('First few files:');
73
+ tsFiles.slice(0, 5).forEach(file => console.log(` - ${file}`));
74
+ }
75
+ if (tsFiles.length === 0) {
76
+ console.log('No TypeScript files found in .engine folder.');
77
+ return;
78
+ }
79
+ let processedCount = 0;
80
+ let modifiedCount = 0;
81
+ for (const filePath of tsFiles) {
82
+ console.log(`Processing: ${filePath}`);
83
+ try {
84
+ const wasModified = await removeCommentsFromFile(filePath);
85
+ processedCount++;
86
+ if (wasModified) {
87
+ modifiedCount++;
88
+ console.log(' ✓ Comments removed');
89
+ }
90
+ else {
91
+ console.log(' - No comments found');
92
+ }
93
+ }
94
+ catch (error) {
95
+ console.error(` ✗ Error: ${error}`);
96
+ }
97
+ }
98
+ console.log('\nCompleted:');
99
+ console.log(`- Files processed: ${processedCount}`);
100
+ console.log(`- Files modified: ${modifiedCount}`);
101
+ console.log(`- Files skipped: ${processedCount - modifiedCount}`);
102
+ }
103
+ catch (error) {
104
+ console.error('Error:', error);
105
+ process.exit(1);
106
+ }
107
+ }
108
+ // Always run main if this file is executed directly
109
+ main().catch((error) => {
110
+ console.error('Unexpected error:', error);
111
+ console.error('Stack trace:', error.stack);
112
+ process.exit(1);
113
+ });
@@ -0,0 +1,146 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import * as ENGINE from 'genesys.js';
4
+ import { AssetPath, AssetPathEncodeState } from 'genesys.js';
5
+ import { getProjectRoot } from './common.js';
6
+ export class StorageProvider {
7
+ async resolvePath(assetPath, expiry) {
8
+ if (assetPath.isResolved()) {
9
+ return assetPath;
10
+ }
11
+ assetPath.resolvePath(this.getFullPath(assetPath.initialPath), AssetPathEncodeState.Decoded);
12
+ return assetPath;
13
+ }
14
+ getFullPath(filePath) {
15
+ let fullPath = filePath;
16
+ let rootPath = undefined;
17
+ if (filePath.startsWith(ENGINE.PROJECT_PATH_PREFIX)) {
18
+ filePath = filePath.slice(ENGINE.PROJECT_PATH_PREFIX.length);
19
+ rootPath = getProjectRoot();
20
+ }
21
+ else if (filePath.startsWith(ENGINE.ENGINE_PATH_PREFIX)) {
22
+ filePath = filePath.slice(ENGINE.ENGINE_PATH_PREFIX.length);
23
+ rootPath = path.join(getProjectRoot(), 'node_modules', 'genesys.js');
24
+ }
25
+ if (rootPath !== undefined) {
26
+ fullPath = AssetPath.join(rootPath, filePath);
27
+ }
28
+ return fullPath;
29
+ }
30
+ async downloadFileAsBuffer(assetPath) {
31
+ assetPath = await this.resolvePath(assetPath);
32
+ const fullPath = getResolvedPath(assetPath);
33
+ if (!fs.existsSync(fullPath)) {
34
+ return new ArrayBuffer(0);
35
+ }
36
+ const data = fs.readFileSync(fullPath);
37
+ const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
38
+ return arrayBuffer;
39
+ }
40
+ async downloadFileAsJson(assetPath) {
41
+ assetPath = await this.resolvePath(assetPath);
42
+ const fullPath = getResolvedPath(assetPath);
43
+ if (!fs.existsSync(fullPath)) {
44
+ return {};
45
+ }
46
+ return JSON.parse(fs.readFileSync(fullPath, 'utf8'));
47
+ }
48
+ async downloadFileAsText(assetPath) {
49
+ assetPath = await this.resolvePath(assetPath);
50
+ const fullPath = getResolvedPath(assetPath);
51
+ if (!fs.existsSync(fullPath)) {
52
+ return '';
53
+ }
54
+ return fs.readFileSync(fullPath, 'utf8');
55
+ }
56
+ async exists(assetPath) {
57
+ assetPath = await this.resolvePath(assetPath);
58
+ const fullPath = getResolvedPath(assetPath);
59
+ return fs.existsSync(fullPath);
60
+ }
61
+ async buildCurrentProject(runTsc) {
62
+ throw new Error('Not implemented');
63
+ }
64
+ async uploadFile(assetPath, content, options) {
65
+ assetPath = await this.resolvePath(assetPath);
66
+ const fullPath = getResolvedPath(assetPath);
67
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
68
+ if (typeof content === 'string') {
69
+ fs.writeFileSync(fullPath, content);
70
+ }
71
+ else {
72
+ throw new Error(`Unsupported content type: ${typeof content}`);
73
+ }
74
+ return {
75
+ path: fullPath,
76
+ name: path.basename(fullPath)
77
+ };
78
+ }
79
+ async deleteFile(assetPath) {
80
+ assetPath = await this.resolvePath(assetPath);
81
+ const fullPath = getResolvedPath(assetPath);
82
+ if (fs.existsSync(fullPath)) {
83
+ fs.unlinkSync(fullPath);
84
+ }
85
+ }
86
+ async listFiles(assetPath, recursive, includeHiddenFiles) {
87
+ assetPath = await this.resolvePath(assetPath);
88
+ const fullPath = getResolvedPath(assetPath);
89
+ if (!fs.existsSync(fullPath)) {
90
+ return { files: [], directories: [] };
91
+ }
92
+ const files = [];
93
+ const directories = [];
94
+ const processDirectory = (dirPath, basePath = '') => {
95
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
96
+ for (const entry of entries) {
97
+ // Skip hidden files if not requested
98
+ if (!includeHiddenFiles && entry.name.startsWith('.')) {
99
+ continue;
100
+ }
101
+ const fullEntryPath = path.join(dirPath, entry.name);
102
+ const relativePath = basePath ? path.join(basePath, entry.name) : entry.name;
103
+ const stats = fs.statSync(fullEntryPath);
104
+ const fileItem = {
105
+ name: entry.name,
106
+ path: relativePath,
107
+ absolutePath: fullEntryPath,
108
+ size: stats.size,
109
+ modifiedTime: stats.mtime,
110
+ isDirectory: entry.isDirectory()
111
+ };
112
+ if (entry.isDirectory()) {
113
+ directories.push(fileItem);
114
+ // Recursively process subdirectories if requested
115
+ if (recursive) {
116
+ processDirectory(fullEntryPath, relativePath);
117
+ }
118
+ }
119
+ else {
120
+ files.push(fileItem);
121
+ }
122
+ }
123
+ };
124
+ // Check if the path is a directory
125
+ const stats = fs.statSync(fullPath);
126
+ if (stats.isDirectory()) {
127
+ processDirectory(fullPath);
128
+ }
129
+ else {
130
+ // If it's a file, return just that file
131
+ const fileItem = {
132
+ name: path.basename(fullPath),
133
+ path: path.basename(fullPath),
134
+ absolutePath: fullPath,
135
+ size: stats.size,
136
+ modifiedTime: stats.mtime,
137
+ isDirectory: false
138
+ };
139
+ files.push(fileItem);
140
+ }
141
+ return { files, directories };
142
+ }
143
+ }
144
+ export function getResolvedPath(assetPath) {
145
+ return assetPath.getResolvedPath(false);
146
+ }
@@ -0,0 +1,115 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import Ajv from 'ajv';
4
+ import { getProjectRoot } from './common.js';
5
+ function findPrefabFiles(dir, prefabFiles = []) {
6
+ const files = fs.readdirSync(dir);
7
+ for (const file of files) {
8
+ const filePath = path.join(dir, file);
9
+ const stat = fs.statSync(filePath);
10
+ if (stat.isDirectory()) {
11
+ // Skip node_modules and other common directories that shouldn't contain prefabs
12
+ if (file === 'node_modules' || file === 'dist' || file === '.git') {
13
+ continue;
14
+ }
15
+ findPrefabFiles(filePath, prefabFiles);
16
+ }
17
+ else if (file.endsWith('.prefab.json')) {
18
+ prefabFiles.push(filePath);
19
+ }
20
+ }
21
+ return prefabFiles;
22
+ }
23
+ function validatePrefabs() {
24
+ const projectRoot = getProjectRoot();
25
+ const schemaPath = path.join(__dirname, 'prefab.schema.json');
26
+ // Load the schema
27
+ let schema;
28
+ try {
29
+ const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
30
+ schema = JSON.parse(schemaContent);
31
+ }
32
+ catch (error) {
33
+ console.error(`❌ Failed to load schema from ${schemaPath}`);
34
+ console.error(error);
35
+ process.exit(1);
36
+ }
37
+ // Initialize Ajv
38
+ const ajv = new Ajv({
39
+ allErrors: true,
40
+ validateSchema: false // Don't validate the schema itself
41
+ });
42
+ // Process $ref in the schema to use proper format
43
+ const processedSchema = JSON.parse(JSON.stringify(schema), (key, value) => {
44
+ if (key === '$ref' && typeof value === 'string' && !value.startsWith('#')) {
45
+ return `#/definitions/${value}`;
46
+ }
47
+ return value;
48
+ });
49
+ const validate = ajv.compile(processedSchema);
50
+ // Find all prefab files
51
+ const prefabFiles = findPrefabFiles(projectRoot);
52
+ if (prefabFiles.length === 0) {
53
+ console.log('⚠️ No prefab files found in the project.');
54
+ return;
55
+ }
56
+ console.log(`Found ${prefabFiles.length} prefab file(s) to validate:\n`);
57
+ const validationErrors = [];
58
+ let validCount = 0;
59
+ // Validate each prefab file
60
+ for (const prefabPath of prefabFiles) {
61
+ const relativePath = path.relative(projectRoot, prefabPath);
62
+ try {
63
+ const prefabContent = fs.readFileSync(prefabPath, 'utf-8');
64
+ const prefabData = JSON.parse(prefabContent);
65
+ const valid = validate(prefabData);
66
+ if (valid) {
67
+ console.log(`✅ ${relativePath}`);
68
+ validCount++;
69
+ }
70
+ else {
71
+ console.log(`❌ ${relativePath}`);
72
+ const errors = validate.errors?.map((err) => {
73
+ const path = err.instancePath ?? '/';
74
+ const message = err.message ?? 'unknown error';
75
+ return ` - ${path}: ${message}`;
76
+ }) ?? [];
77
+ validationErrors.push({
78
+ file: relativePath,
79
+ errors
80
+ });
81
+ }
82
+ }
83
+ catch (error) {
84
+ console.log(`❌ ${relativePath} (parse error)`);
85
+ validationErrors.push({
86
+ file: relativePath,
87
+ errors: [`Failed to parse JSON: ${error instanceof Error ? error.message : String(error)}`]
88
+ });
89
+ }
90
+ }
91
+ // Print summary
92
+ console.log(`\n${'='.repeat(60)}`);
93
+ console.log('Validation Summary:');
94
+ console.log(` Total files: ${prefabFiles.length}`);
95
+ console.log(` Valid: ${validCount}`);
96
+ console.log(` Invalid: ${validationErrors.length}`);
97
+ console.log(`${'='.repeat(60)}\n`);
98
+ // Print detailed errors if any
99
+ if (validationErrors.length > 0) {
100
+ console.log('Validation Errors:\n');
101
+ for (const { file, errors } of validationErrors) {
102
+ console.log(`${file}:`);
103
+ for (const error of errors) {
104
+ console.log(error);
105
+ }
106
+ console.log('');
107
+ }
108
+ process.exit(1);
109
+ }
110
+ else {
111
+ console.log('🎉 All prefab files are valid!');
112
+ }
113
+ }
114
+ // Run validation
115
+ validatePrefabs();
@@ -0,0 +1,20 @@
1
+ // which items will be copied to the new project, includes files and folders
2
+ export const sharedTemplateItems = [
3
+ '.cursor',
4
+ '.vscode',
5
+ 'scripts/genesys',
6
+ 'gitignore', // npm excludes .gitignore files from packages, so we rename it when copying
7
+ '.gitattributes',
8
+ '.cursorignore',
9
+ 'eslint.config.js',
10
+ 'tsconfig.json',
11
+ 'AGENTS.md',
12
+ 'CLAUDE.md',
13
+ 'index.html',
14
+ 'vite.config.ts',
15
+ ];
16
+ // which items will be deleted from the project, if exists
17
+ export const deletedTemplateItems = [
18
+ '.cursorrules'
19
+ ];
20
+ export * as ENGINE from 'genesys.js';
@@ -0,0 +1,30 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+ import { FirstPersonPlayer } from './player.js';
4
+ import './auto-imports.js';
5
+ class FirstPersonGame extends ENGINE.BaseGameLoop {
6
+ pawn = null;
7
+ controller = null;
8
+ createLoadingScreen() {
9
+ // enable the default loading screen
10
+ return new ENGINE.DefaultLoadingScreen();
11
+ }
12
+ async preStart() {
13
+ // default spawn location
14
+ const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT / 2, 0);
15
+ // now create the pawn
16
+ this.pawn = new FirstPersonPlayer({ position });
17
+ // create the controller and possess the pawn
18
+ this.controller = new ENGINE.PlayerController();
19
+ this.controller.possess(this.pawn);
20
+ // add both to the world
21
+ this.world.addActors(this.pawn, this.controller);
22
+ }
23
+ }
24
+ export function main(container, gameId) {
25
+ const game = new FirstPersonGame(container, {
26
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
27
+ gameId
28
+ });
29
+ return game;
30
+ }
@@ -0,0 +1,60 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import * as ENGINE from 'genesys.js';
8
+ import * as THREE from 'three';
9
+ /**
10
+ * A first person player class.
11
+ *
12
+ * Key points:
13
+ * - No need to provide movementComponent and camera, they are created internally
14
+ * - The pawn is set to be transient so it's never saved in the level
15
+ * - The directional light follows the player for consistent shadows
16
+ *
17
+ */
18
+ let FirstPersonPlayer = class FirstPersonPlayer extends ENGINE.Pawn {
19
+ // No need to provide rootComponent, movementComponent and camera, they are created internally
20
+ constructor(options) {
21
+ // simple camera component - contains a perspective camera by default
22
+ const camera = new THREE.PerspectiveCamera(ENGINE.CAMERA_FOV, 1, ENGINE.CAMERA_NEAR, ENGINE.CAMERA_FAR);
23
+ // set proper camera height for first person view
24
+ camera.position.set(0, ENGINE.CHARACTER_HEIGHT * 0.4, 0);
25
+ // use a simple capsule geometry as the root component
26
+ const rootComponent = new ENGINE.MeshComponent({
27
+ geometry: ENGINE.GameBuilder.createDefaultPawnCapsuleGeometry(),
28
+ material: new THREE.MeshStandardMaterial({ color: ENGINE.Color.YELLOW }),
29
+ physicsOptions: {
30
+ enabled: true,
31
+ // KinematicVelocityBased is required to use the physics character controller
32
+ motionType: ENGINE.PhysicsMotionType.KinematicVelocityBased,
33
+ collisionProfile: ENGINE.DefaultCollisionProfile.Pawn,
34
+ generateCollisionEvents: true,
35
+ }
36
+ });
37
+ // hide the mesh in first person view
38
+ rootComponent.getMesh().visible = false;
39
+ // create the movement component
40
+ const movementComponent = new ENGINE.CharacterMovementComponent({
41
+ ...ENGINE.CharacterMovementComponent.DEFAULT_OPTIONS,
42
+ movementType: ENGINE.CharacterMovementType.FirstPerson,
43
+ });
44
+ // construct the pawn
45
+ super({
46
+ ...options,
47
+ rootComponent,
48
+ movementComponent,
49
+ // make sure the directional light follows the player for consistent shadows
50
+ enableDirectionalLightFollowing: true,
51
+ camera,
52
+ });
53
+ // set the pawn to be transient so it's never saved in the level
54
+ this.setTransient(true);
55
+ }
56
+ };
57
+ FirstPersonPlayer = __decorate([
58
+ ENGINE.GameClass()
59
+ ], FirstPersonPlayer);
60
+ export { FirstPersonPlayer };
@@ -0,0 +1,30 @@
1
+ import * as ENGINE from 'genesys.js';
2
+ import * as THREE from 'three';
3
+ import { FPSPlayer } from './player.js';
4
+ import './auto-imports.js';
5
+ class MyGame extends ENGINE.BaseGameLoop {
6
+ pawn = null;
7
+ controller = null;
8
+ createLoadingScreen() {
9
+ // enable the default loading screen
10
+ return new ENGINE.DefaultLoadingScreen();
11
+ }
12
+ async preStart() {
13
+ // default spawn location
14
+ const position = new THREE.Vector3(0, ENGINE.CHARACTER_HEIGHT / 2, 0);
15
+ // now create the pawn
16
+ this.pawn = new FPSPlayer({ position });
17
+ // create the controller and possess the pawn
18
+ this.controller = new ENGINE.PlayerController();
19
+ this.controller.possess(this.pawn);
20
+ // add both to the world
21
+ this.world.addActors(this.pawn, this.controller);
22
+ }
23
+ }
24
+ export function main(container, gameId) {
25
+ const game = new MyGame(container, {
26
+ ...ENGINE.BaseGameLoop.DEFAULT_OPTIONS,
27
+ gameId
28
+ });
29
+ return game;
30
+ }
@@ -0,0 +1,64 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import * as ENGINE from 'genesys.js';
8
+ import * as THREE from 'three';
9
+ import { DefaultWeapon } from './weapon.js';
10
+ /**
11
+ * A FPS player class.
12
+ *
13
+ * Key points:
14
+ * - No need to provide rootComponent, movementComponent and camera, they are created internally
15
+ * - The pawn is set to be transient so it's never saved in the level
16
+ * - The directional light follows the player for consistent shadows
17
+ * - The weapon is created and attached to the camera
18
+ *
19
+ */
20
+ let FPSPlayer = class FPSPlayer extends ENGINE.Pawn {
21
+ // No need to provide rootComponent, movementComponent and camera, they are created internally
22
+ constructor(options) {
23
+ // simple camera component - contains a perspective camera by default
24
+ const camera = new THREE.PerspectiveCamera(ENGINE.CAMERA_FOV, 1, ENGINE.CAMERA_NEAR, ENGINE.CAMERA_FAR);
25
+ // set proper camera height for first person view
26
+ camera.position.set(0, ENGINE.CHARACTER_HEIGHT * 0.4, 0);
27
+ // create the weapon and attach it to the camera
28
+ const weapon = new DefaultWeapon();
29
+ camera.add(weapon);
30
+ // use a simple capsule geometry as the root component
31
+ const rootComponent = new ENGINE.MeshComponent({
32
+ geometry: ENGINE.GameBuilder.createDefaultPawnCapsuleGeometry(),
33
+ material: new THREE.MeshStandardMaterial({ color: ENGINE.Color.YELLOW }),
34
+ physicsOptions: {
35
+ enabled: true,
36
+ // KinematicVelocityBased is required to use the physics character controller
37
+ motionType: ENGINE.PhysicsMotionType.KinematicVelocityBased,
38
+ collisionProfile: ENGINE.DefaultCollisionProfile.Pawn,
39
+ generateCollisionEvents: true,
40
+ }
41
+ });
42
+ // hide the mesh in first person view
43
+ rootComponent.getMesh().visible = false;
44
+ // create the movement component
45
+ const movementComponent = new ENGINE.CharacterMovementComponent({
46
+ ...ENGINE.CharacterMovementComponent.DEFAULT_OPTIONS,
47
+ movementType: ENGINE.CharacterMovementType.FirstPerson,
48
+ });
49
+ super({
50
+ ...options,
51
+ rootComponent,
52
+ movementComponent,
53
+ // make sure the directional light follows the player for consistent shadows
54
+ enableDirectionalLightFollowing: true,
55
+ camera
56
+ });
57
+ // set the pawn to be transient so it's never saved in the level
58
+ this.setTransient(true);
59
+ }
60
+ };
61
+ FPSPlayer = __decorate([
62
+ ENGINE.GameClass()
63
+ ], FPSPlayer);
64
+ export { FPSPlayer };
@@ -0,0 +1,62 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import * as ENGINE from 'genesys.js';
8
+ import * as THREE from 'three';
9
+ /**
10
+ * A default weapon class.
11
+ *
12
+ * Key points:
13
+ * - Inherits from the ProjectileWeaponComponent class
14
+ * - All the weapon options are configured in the constructor so no need to configure by the user
15
+ */
16
+ let DefaultWeapon = class DefaultWeapon extends ENGINE.ProjectileWeaponComponent {
17
+ constructor() {
18
+ super({
19
+ // firing params
20
+ fireInterval: 0.1,
21
+ isSingleFire: false,
22
+ // configure the weapon model
23
+ modelPath: '@project/assets/models/SM_Rifle.glb',
24
+ modelTransform: {
25
+ position: new THREE.Vector3(0.1, -0.1, -0.25),
26
+ rotation: new THREE.Euler(0, THREE.MathUtils.degToRad(-90), 0),
27
+ },
28
+ // tweak the projectile spawn offset so it matches the muzzle position
29
+ projectileSpawnOffset: new THREE.Vector3(0.8, -0.6, -2),
30
+ // add a crosshair
31
+ crosshairOptions: {
32
+ size: 10,
33
+ color: 'white',
34
+ style: 'dot'
35
+ },
36
+ // add weapon sounds
37
+ fireSoundUrl: '@engine/assets/sounds/game-gun-short.mp3',
38
+ // enable recoil
39
+ recoilOptions: {
40
+ weaponRecoilDistance: 0.05,
41
+ weaponRecoilDuration: 0.05,
42
+ weaponRecoilRotation: 0,
43
+ },
44
+ // configure the projectile
45
+ projectileOptions: {
46
+ velocity: 100,
47
+ range: 500,
48
+ lifeSpan: 3,
49
+ useOverlapCheck: false,
50
+ destroyOnHit: false,
51
+ gravityScale: 0,
52
+ geometry: new THREE.SphereGeometry(0.1),
53
+ material: new THREE.MeshStandardMaterial({ color: ENGINE.Color.YELLOW })
54
+ }
55
+ });
56
+ this.setTransient(true);
57
+ }
58
+ };
59
+ DefaultWeapon = __decorate([
60
+ ENGINE.GameClass()
61
+ ], DefaultWeapon);
62
+ export { DefaultWeapon };