@nice2dev/game-engine 1.0.2 → 1.0.4

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 (188) hide show
  1. package/dist/cjs/ai/BehaviorTree.js +1215 -0
  2. package/dist/cjs/ai/BehaviorTree.js.map +1 -0
  3. package/dist/cjs/ai/StateMachine.js +783 -0
  4. package/dist/cjs/ai/StateMachine.js.map +1 -0
  5. package/dist/cjs/editor/ShaderGraph.js +1616 -0
  6. package/dist/cjs/editor/ShaderGraph.js.map +1 -0
  7. package/dist/cjs/editor/TimelineEditor.js +819 -0
  8. package/dist/cjs/editor/TimelineEditor.js.map +1 -0
  9. package/dist/cjs/export/GodotExporter.js +1102 -0
  10. package/dist/cjs/export/GodotExporter.js.map +1 -0
  11. package/dist/cjs/export/PlatformExporter.js +236 -0
  12. package/dist/cjs/export/PlatformExporter.js.map +1 -0
  13. package/dist/cjs/export/ThreeJSExporter.js +1116 -0
  14. package/dist/cjs/export/ThreeJSExporter.js.map +1 -0
  15. package/dist/cjs/export/UnityExporter.js +1193 -0
  16. package/dist/cjs/export/UnityExporter.js.map +1 -0
  17. package/dist/cjs/export/WebExporter.js +1036 -0
  18. package/dist/cjs/export/WebExporter.js.map +1 -0
  19. package/dist/cjs/export/index.js +58 -0
  20. package/dist/cjs/export/index.js.map +1 -0
  21. package/dist/cjs/import/AsepriteImporter.js +761 -0
  22. package/dist/cjs/import/AsepriteImporter.js.map +1 -0
  23. package/dist/cjs/import/DragonBonesImporter.js +499 -0
  24. package/dist/cjs/import/DragonBonesImporter.js.map +1 -0
  25. package/dist/cjs/import/GameMakerImporter.js +559 -0
  26. package/dist/cjs/import/GameMakerImporter.js.map +1 -0
  27. package/dist/cjs/import/GodotSceneImporter.js +824 -0
  28. package/dist/cjs/import/GodotSceneImporter.js.map +1 -0
  29. package/dist/cjs/import/LDtkImporter.js +481 -0
  30. package/dist/cjs/import/LDtkImporter.js.map +1 -0
  31. package/dist/cjs/import/Live2DImporter.js +553 -0
  32. package/dist/cjs/import/Live2DImporter.js.map +1 -0
  33. package/dist/cjs/import/NdgFormat.js +499 -0
  34. package/dist/cjs/import/NdgFormat.js.map +1 -0
  35. package/dist/cjs/import/OgmoImporter.js +529 -0
  36. package/dist/cjs/import/OgmoImporter.js.map +1 -0
  37. package/dist/cjs/import/RPGMakerImporter.js +520 -0
  38. package/dist/cjs/import/RPGMakerImporter.js.map +1 -0
  39. package/dist/cjs/import/SceneImporter.js +449 -0
  40. package/dist/cjs/import/SceneImporter.js.map +1 -0
  41. package/dist/cjs/import/SpineImporter.js +583 -0
  42. package/dist/cjs/import/SpineImporter.js.map +1 -0
  43. package/dist/cjs/import/SpriterImporter.js +652 -0
  44. package/dist/cjs/import/SpriterImporter.js.map +1 -0
  45. package/dist/cjs/import/TiledMapImporter.js +859 -0
  46. package/dist/cjs/import/TiledMapImporter.js.map +1 -0
  47. package/dist/cjs/import/UnitySceneImporter.js +732 -0
  48. package/dist/cjs/import/UnitySceneImporter.js.map +1 -0
  49. package/dist/cjs/import/index.js +305 -0
  50. package/dist/cjs/import/index.js.map +1 -0
  51. package/dist/cjs/index.js +201 -0
  52. package/dist/cjs/index.js.map +1 -1
  53. package/dist/cjs/scripting/GraphToAST.js +567 -0
  54. package/dist/cjs/scripting/GraphToAST.js.map +1 -0
  55. package/dist/cjs/scripting/LanguageExporter.js +321 -0
  56. package/dist/cjs/scripting/LanguageExporter.js.map +1 -0
  57. package/dist/cjs/scripting/ScriptAST.js +67 -0
  58. package/dist/cjs/scripting/ScriptAST.js.map +1 -0
  59. package/dist/cjs/scripting/VisualScripting2.js +1140 -0
  60. package/dist/cjs/scripting/VisualScripting2.js.map +1 -0
  61. package/dist/cjs/scripting/exporters/CSharpExporter.js +503 -0
  62. package/dist/cjs/scripting/exporters/CSharpExporter.js.map +1 -0
  63. package/dist/cjs/scripting/exporters/GDScriptExporter.js +452 -0
  64. package/dist/cjs/scripting/exporters/GDScriptExporter.js.map +1 -0
  65. package/dist/cjs/scripting/exporters/LuaExporter.js +457 -0
  66. package/dist/cjs/scripting/exporters/LuaExporter.js.map +1 -0
  67. package/dist/cjs/scripting/exporters/PythonExporter.js +565 -0
  68. package/dist/cjs/scripting/exporters/PythonExporter.js.map +1 -0
  69. package/dist/cjs/scripting/exporters/RustExporter.js +525 -0
  70. package/dist/cjs/scripting/exporters/RustExporter.js.map +1 -0
  71. package/dist/cjs/scripting/exporters/TypeScriptExporter.js +570 -0
  72. package/dist/cjs/scripting/exporters/TypeScriptExporter.js.map +1 -0
  73. package/dist/cjs/systems/ParticleSystem2.js +1478 -0
  74. package/dist/cjs/systems/ParticleSystem2.js.map +1 -0
  75. package/dist/esm/ai/BehaviorTree.js +1186 -0
  76. package/dist/esm/ai/BehaviorTree.js.map +1 -0
  77. package/dist/esm/ai/StateMachine.js +767 -0
  78. package/dist/esm/ai/StateMachine.js.map +1 -0
  79. package/dist/esm/editor/ShaderGraph.js +1606 -0
  80. package/dist/esm/editor/ShaderGraph.js.map +1 -0
  81. package/dist/esm/editor/TimelineEditor.js +800 -0
  82. package/dist/esm/editor/TimelineEditor.js.map +1 -0
  83. package/dist/esm/export/GodotExporter.js +1100 -0
  84. package/dist/esm/export/GodotExporter.js.map +1 -0
  85. package/dist/esm/export/PlatformExporter.js +230 -0
  86. package/dist/esm/export/PlatformExporter.js.map +1 -0
  87. package/dist/esm/export/ThreeJSExporter.js +1114 -0
  88. package/dist/esm/export/ThreeJSExporter.js.map +1 -0
  89. package/dist/esm/export/UnityExporter.js +1191 -0
  90. package/dist/esm/export/UnityExporter.js.map +1 -0
  91. package/dist/esm/export/WebExporter.js +1033 -0
  92. package/dist/esm/export/WebExporter.js.map +1 -0
  93. package/dist/esm/export/index.js +44 -0
  94. package/dist/esm/export/index.js.map +1 -0
  95. package/dist/esm/import/AsepriteImporter.js +759 -0
  96. package/dist/esm/import/AsepriteImporter.js.map +1 -0
  97. package/dist/esm/import/DragonBonesImporter.js +496 -0
  98. package/dist/esm/import/DragonBonesImporter.js.map +1 -0
  99. package/dist/esm/import/GameMakerImporter.js +556 -0
  100. package/dist/esm/import/GameMakerImporter.js.map +1 -0
  101. package/dist/esm/import/GodotSceneImporter.js +822 -0
  102. package/dist/esm/import/GodotSceneImporter.js.map +1 -0
  103. package/dist/esm/import/LDtkImporter.js +479 -0
  104. package/dist/esm/import/LDtkImporter.js.map +1 -0
  105. package/dist/esm/import/Live2DImporter.js +550 -0
  106. package/dist/esm/import/Live2DImporter.js.map +1 -0
  107. package/dist/esm/import/NdgFormat.js +490 -0
  108. package/dist/esm/import/NdgFormat.js.map +1 -0
  109. package/dist/esm/import/OgmoImporter.js +526 -0
  110. package/dist/esm/import/OgmoImporter.js.map +1 -0
  111. package/dist/esm/import/RPGMakerImporter.js +517 -0
  112. package/dist/esm/import/RPGMakerImporter.js.map +1 -0
  113. package/dist/esm/import/SceneImporter.js +441 -0
  114. package/dist/esm/import/SceneImporter.js.map +1 -0
  115. package/dist/esm/import/SpineImporter.js +580 -0
  116. package/dist/esm/import/SpineImporter.js.map +1 -0
  117. package/dist/esm/import/SpriterImporter.js +649 -0
  118. package/dist/esm/import/SpriterImporter.js.map +1 -0
  119. package/dist/esm/import/TiledMapImporter.js +857 -0
  120. package/dist/esm/import/TiledMapImporter.js.map +1 -0
  121. package/dist/esm/import/UnitySceneImporter.js +730 -0
  122. package/dist/esm/import/UnitySceneImporter.js.map +1 -0
  123. package/dist/esm/import/index.js +279 -0
  124. package/dist/esm/import/index.js.map +1 -0
  125. package/dist/esm/index.js +36 -0
  126. package/dist/esm/index.js.map +1 -1
  127. package/dist/esm/scripting/GraphToAST.js +564 -0
  128. package/dist/esm/scripting/GraphToAST.js.map +1 -0
  129. package/dist/esm/scripting/LanguageExporter.js +311 -0
  130. package/dist/esm/scripting/LanguageExporter.js.map +1 -0
  131. package/dist/esm/scripting/ScriptAST.js +52 -0
  132. package/dist/esm/scripting/ScriptAST.js.map +1 -0
  133. package/dist/esm/scripting/VisualScripting2.js +1130 -0
  134. package/dist/esm/scripting/VisualScripting2.js.map +1 -0
  135. package/dist/esm/scripting/exporters/CSharpExporter.js +501 -0
  136. package/dist/esm/scripting/exporters/CSharpExporter.js.map +1 -0
  137. package/dist/esm/scripting/exporters/GDScriptExporter.js +450 -0
  138. package/dist/esm/scripting/exporters/GDScriptExporter.js.map +1 -0
  139. package/dist/esm/scripting/exporters/LuaExporter.js +455 -0
  140. package/dist/esm/scripting/exporters/LuaExporter.js.map +1 -0
  141. package/dist/esm/scripting/exporters/PythonExporter.js +563 -0
  142. package/dist/esm/scripting/exporters/PythonExporter.js.map +1 -0
  143. package/dist/esm/scripting/exporters/RustExporter.js +523 -0
  144. package/dist/esm/scripting/exporters/RustExporter.js.map +1 -0
  145. package/dist/esm/scripting/exporters/TypeScriptExporter.js +568 -0
  146. package/dist/esm/scripting/exporters/TypeScriptExporter.js.map +1 -0
  147. package/dist/esm/systems/ParticleSystem2.js +1471 -0
  148. package/dist/esm/systems/ParticleSystem2.js.map +1 -0
  149. package/dist/types/ai/BehaviorTree.d.ts +375 -0
  150. package/dist/types/ai/StateMachine.d.ts +296 -0
  151. package/dist/types/editor/ShaderGraph.d.ts +207 -0
  152. package/dist/types/editor/TimelineEditor.d.ts +393 -0
  153. package/dist/types/export/GodotExporter.d.ts +56 -0
  154. package/dist/types/export/PlatformExporter.d.ts +201 -0
  155. package/dist/types/export/ThreeJSExporter.d.ts +40 -0
  156. package/dist/types/export/UnityExporter.d.ts +69 -0
  157. package/dist/types/export/WebExporter.d.ts +58 -0
  158. package/dist/types/export/index.d.ts +19 -0
  159. package/dist/types/import/AsepriteImporter.d.ts +46 -0
  160. package/dist/types/import/DragonBonesImporter.d.ts +331 -0
  161. package/dist/types/import/GameMakerImporter.d.ts +375 -0
  162. package/dist/types/import/GodotSceneImporter.d.ts +34 -0
  163. package/dist/types/import/LDtkImporter.d.ts +177 -0
  164. package/dist/types/import/Live2DImporter.d.ts +237 -0
  165. package/dist/types/import/NdgFormat.d.ts +387 -0
  166. package/dist/types/import/OgmoImporter.d.ts +237 -0
  167. package/dist/types/import/RPGMakerImporter.d.ts +186 -0
  168. package/dist/types/import/SceneImporter.d.ts +276 -0
  169. package/dist/types/import/SpineImporter.d.ts +372 -0
  170. package/dist/types/import/SpriterImporter.d.ts +230 -0
  171. package/dist/types/import/TiledMapImporter.d.ts +57 -0
  172. package/dist/types/import/UnitySceneImporter.d.ts +87 -0
  173. package/dist/types/import/index.d.ts +59 -0
  174. package/dist/types/index.d.ts +29 -17
  175. package/dist/types/scripting/GraphToAST.d.ts +55 -0
  176. package/dist/types/scripting/LanguageExporter.d.ts +136 -0
  177. package/dist/types/scripting/ScriptAST.d.ts +312 -0
  178. package/dist/types/scripting/VisualScripting2.d.ts +353 -0
  179. package/dist/types/scripting/exporters/CSharpExporter.d.ts +44 -0
  180. package/dist/types/scripting/exporters/GDScriptExporter.d.ts +46 -0
  181. package/dist/types/scripting/exporters/LuaExporter.d.ts +46 -0
  182. package/dist/types/scripting/exporters/PythonExporter.d.ts +49 -0
  183. package/dist/types/scripting/exporters/RustExporter.d.ts +46 -0
  184. package/dist/types/scripting/exporters/TypeScriptExporter.d.ts +48 -0
  185. package/dist/types/scripting/exporters/index.d.ts +8 -0
  186. package/dist/types/scripting/index.d.ts +11 -0
  187. package/dist/types/systems/ParticleSystem2.d.ts +646 -0
  188. package/package.json +3 -3
@@ -0,0 +1,1114 @@
1
+ import { PlatformExporter } from './PlatformExporter.js';
2
+ import { TypeScriptExporter } from '../scripting/exporters/TypeScriptExporter.js';
3
+ import { GraphToAST } from '../scripting/GraphToAST.js';
4
+
5
+ /* ────────────────────────────────────────────────────────────────
6
+ Three.js Exporter
7
+
8
+ Exports Nice2Dev projects to Three.js format for 3D web games.
9
+ Generates ES modules with scene management and entity systems.
10
+ ──────────────────────────────────────────────────────────────── */
11
+ /* ── Three.js Exporter Class ──────────────────────────────────── */
12
+ class ThreeJSExporter extends PlatformExporter {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.platformId = 'threejs';
16
+ this.platformInfo = {
17
+ id: 'threejs',
18
+ name: 'Three.js',
19
+ description: '3D JavaScript library for WebGL',
20
+ website: 'https://threejs.org',
21
+ features: ['3d-rendering', 'particles', 'animation', 'vr-ar'],
22
+ supportedAssets: ['sprite', 'audio', 'font', 'script', 'material', 'shader', 'animation'],
23
+ exportFormats: ['.html', '.js', '.ts'],
24
+ };
25
+ this.tsExporter = new TypeScriptExporter();
26
+ this.graphToAST = new GraphToAST();
27
+ }
28
+ async doExport(project, options) {
29
+ const three = options.platformOptions;
30
+ const useTS = (three === null || three === void 0 ? void 0 : three.typescript) !== false;
31
+ const bundler = (three === null || three === void 0 ? void 0 : three.bundler) || 'vite';
32
+ // 1. Generate package.json
33
+ this.exportPackageJson(project, three);
34
+ // 2. Generate HTML entry
35
+ this.exportIndexHtml(project, three);
36
+ // 3. Generate main game file
37
+ this.exportMainGame(project, options, three, useTS);
38
+ // 4. Export scenes
39
+ this.exportScenes(project, options, useTS);
40
+ // 5. Export scripts
41
+ await this.exportScripts(project, options, useTS);
42
+ // 6. Export utilities
43
+ this.exportUtilities(three, useTS);
44
+ // 7. Export shaders
45
+ this.exportShaders(project);
46
+ // 8. Generate bundler config
47
+ if (bundler !== 'none') {
48
+ this.exportBundlerConfig(bundler, useTS);
49
+ }
50
+ // 9. Generate tsconfig if TypeScript
51
+ if (useTS) {
52
+ this.exportTSConfig();
53
+ }
54
+ }
55
+ exportPackageJson(project, three) {
56
+ const useTS = (three === null || three === void 0 ? void 0 : three.typescript) !== false;
57
+ const bundler = (three === null || three === void 0 ? void 0 : three.bundler) || 'vite';
58
+ const threeVersion = (three === null || three === void 0 ? void 0 : three.version) || '^0.162.0';
59
+ const dependencies = {
60
+ three: threeVersion,
61
+ };
62
+ // Add physics engine
63
+ if ((three === null || three === void 0 ? void 0 : three.physics) === 'cannon') {
64
+ dependencies['cannon-es'] = '^0.20.0';
65
+ }
66
+ else if ((three === null || three === void 0 ? void 0 : three.physics) === 'rapier') {
67
+ dependencies['@dimforge/rapier3d'] = '^0.12.0';
68
+ }
69
+ // Add post-processing
70
+ if (three === null || three === void 0 ? void 0 : three.postProcessing) {
71
+ dependencies['postprocessing'] = '^6.0.0';
72
+ }
73
+ const packageJson = {
74
+ name: project.name.toLowerCase().replace(/\s+/g, '-'),
75
+ version: project.version,
76
+ description: project.description || `${project.name} - 3D game built with Nice2Dev`,
77
+ type: 'module',
78
+ scripts: {
79
+ dev: bundler === 'vite'
80
+ ? 'vite'
81
+ : bundler === 'webpack'
82
+ ? 'webpack serve'
83
+ : 'parcel index.html',
84
+ build: bundler === 'vite'
85
+ ? 'vite build'
86
+ : bundler === 'webpack'
87
+ ? 'webpack'
88
+ : 'parcel build index.html',
89
+ preview: bundler === 'vite' ? 'vite preview' : 'serve dist',
90
+ },
91
+ dependencies,
92
+ devDependencies: {
93
+ ...(useTS ? { typescript: '^5.0.0', '@types/three': '^0.162.0' } : {}),
94
+ ...(bundler === 'vite' ? { vite: '^5.0.0' } : {}),
95
+ ...(bundler === 'webpack'
96
+ ? {
97
+ webpack: '^5.0.0',
98
+ 'webpack-cli': '^5.0.0',
99
+ 'webpack-dev-server': '^4.0.0',
100
+ 'ts-loader': '^9.0.0',
101
+ }
102
+ : {}),
103
+ },
104
+ };
105
+ this.addTextFile('package.json', JSON.stringify(packageJson, null, 2));
106
+ }
107
+ exportIndexHtml(project, three) {
108
+ const html = `<!DOCTYPE html>
109
+ <html lang="en">
110
+ <head>
111
+ <meta charset="UTF-8">
112
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
113
+ <title>${project.name}</title>
114
+ <style>
115
+ * {
116
+ margin: 0;
117
+ padding: 0;
118
+ box-sizing: border-box;
119
+ }
120
+
121
+ html, body {
122
+ width: 100%;
123
+ height: 100%;
124
+ overflow: hidden;
125
+ }
126
+
127
+ body {
128
+ background-color: ${project.settings.backgroundColor};
129
+ }
130
+
131
+ #game-container {
132
+ width: 100%;
133
+ height: 100%;
134
+ }
135
+
136
+ canvas {
137
+ display: block;
138
+ width: 100%;
139
+ height: 100%;
140
+ }
141
+
142
+ #loading-screen {
143
+ position: fixed;
144
+ top: 0;
145
+ left: 0;
146
+ width: 100%;
147
+ height: 100%;
148
+ background: ${project.settings.backgroundColor};
149
+ display: flex;
150
+ flex-direction: column;
151
+ justify-content: center;
152
+ align-items: center;
153
+ z-index: 1000;
154
+ transition: opacity 0.5s ease;
155
+ }
156
+
157
+ #loading-screen.hidden {
158
+ opacity: 0;
159
+ pointer-events: none;
160
+ }
161
+
162
+ .loading-bar {
163
+ width: 200px;
164
+ height: 4px;
165
+ background: rgba(255, 255, 255, 0.2);
166
+ border-radius: 2px;
167
+ overflow: hidden;
168
+ }
169
+
170
+ .loading-bar-fill {
171
+ width: 0%;
172
+ height: 100%;
173
+ background: white;
174
+ transition: width 0.3s ease;
175
+ }
176
+
177
+ .loading-text {
178
+ color: white;
179
+ font-family: sans-serif;
180
+ margin-bottom: 10px;
181
+ }
182
+ </style>
183
+ </head>
184
+ <body>
185
+ <div id="loading-screen">
186
+ <div class="loading-text">Loading...</div>
187
+ <div class="loading-bar">
188
+ <div class="loading-bar-fill" id="loading-progress"></div>
189
+ </div>
190
+ </div>
191
+ <div id="game-container"></div>
192
+ <script type="module" src="/src/main.ts"></script>
193
+ </body>
194
+ </html>
195
+ `;
196
+ this.addTextFile('index.html', html);
197
+ }
198
+ exportMainGame(project, options, three, useTS) {
199
+ var _a, _b, _c, _d, _e, _f;
200
+ const ext = useTS ? 'ts' : 'js';
201
+ const { width, height } = project.settings.resolution;
202
+ const hasPhysics = (three === null || three === void 0 ? void 0 : three.physics) && three.physics !== 'none';
203
+ const hasXR = three === null || three === void 0 ? void 0 : three.xr;
204
+ const hasOrbitControls = three === null || three === void 0 ? void 0 : three.orbitControls;
205
+ const hasPostProcessing = three === null || three === void 0 ? void 0 : three.postProcessing;
206
+ let imports = `import * as THREE from 'three';
207
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
208
+ import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
209
+ `;
210
+ if (hasOrbitControls) {
211
+ imports += `import { OrbitControls } from 'three/addons/controls/OrbitControls.js';\n`;
212
+ }
213
+ if (hasXR) {
214
+ imports += `import { VRButton } from 'three/addons/webxr/VRButton.js';\n`;
215
+ }
216
+ if (hasPostProcessing) {
217
+ imports += `import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
218
+ import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
219
+ import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
220
+ `;
221
+ }
222
+ if (hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon') {
223
+ imports += `import * as CANNON from 'cannon-es';\n`;
224
+ }
225
+ imports += `
226
+ import { GameManager } from './game/GameManager${useTS ? '' : '.js'}';
227
+ import { AssetLoader } from './game/AssetLoader${useTS ? '' : '.js'}';
228
+ import { InputManager } from './game/InputManager${useTS ? '' : '.js'}';
229
+ `;
230
+ // Scene imports
231
+ for (const scene of project.scenes) {
232
+ const sceneName = this.sanitizeName(scene.name);
233
+ imports += `import { ${sceneName}Scene } from './scenes/${sceneName}${useTS ? '' : '.js'}';\n`;
234
+ }
235
+ const main = `${imports}
236
+
237
+ ${useTS
238
+ ? `
239
+ interface GameConfig {
240
+ container: HTMLElement;
241
+ width: number;
242
+ height: number;
243
+ }
244
+ `
245
+ : ''}
246
+
247
+ class Game {
248
+ ${useTS ? 'private renderer: THREE.WebGLRenderer;' : ''}
249
+ ${useTS ? 'private camera: THREE.PerspectiveCamera;' : ''}
250
+ ${useTS ? 'private scene: THREE.Scene;' : ''}
251
+ ${useTS ? 'private clock: THREE.Clock;' : ''}
252
+ ${useTS ? 'private gameManager: GameManager;' : ''}
253
+ ${useTS ? 'private assetLoader: AssetLoader;' : ''}
254
+ ${useTS ? 'private inputManager: InputManager;' : ''}
255
+ ${hasOrbitControls && useTS ? 'private controls: OrbitControls;' : ''}
256
+ ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon' && useTS ? 'private world: CANNON.World;' : ''}
257
+ ${hasPostProcessing && useTS ? 'private composer: EffectComposer;' : ''}
258
+
259
+ async init()${useTS ? ': Promise<void>' : ''} {
260
+ const container = document.getElementById('game-container');
261
+ if (!container) throw new Error('Container not found');
262
+
263
+ // Initialize renderer
264
+ this.renderer = new THREE.WebGLRenderer({
265
+ antialias: ${!((_a = project.settings.rendering) === null || _a === void 0 ? void 0 : _a.pixelArt)},
266
+ alpha: false,
267
+ powerPreference: 'high-performance',
268
+ });
269
+ this.renderer.setSize(window.innerWidth, window.innerHeight);
270
+ this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
271
+ this.renderer.shadowMap.enabled = true;
272
+ this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
273
+ this.renderer.outputColorSpace = THREE.SRGBColorSpace;
274
+ this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
275
+ this.renderer.toneMappingExposure = 1;
276
+ container.appendChild(this.renderer.domElement);
277
+
278
+ ${hasXR
279
+ ? `
280
+ // Enable XR
281
+ this.renderer.xr.enabled = true;
282
+ document.body.appendChild(VRButton.createButton(this.renderer));
283
+ `
284
+ : ''}
285
+
286
+ // Initialize camera
287
+ this.camera = new THREE.PerspectiveCamera(
288
+ 75,
289
+ window.innerWidth / window.innerHeight,
290
+ 0.1,
291
+ 1000
292
+ );
293
+ this.camera.position.set(0, 5, 10);
294
+
295
+ // Initialize scene
296
+ this.scene = new THREE.Scene();
297
+ this.scene.background = new THREE.Color('${project.settings.backgroundColor}');
298
+
299
+ ${hasOrbitControls
300
+ ? `
301
+ // Initialize controls
302
+ this.controls = new OrbitControls(this.camera, this.renderer.domElement);
303
+ this.controls.enableDamping = true;
304
+ this.controls.dampingFactor = 0.05;
305
+ `
306
+ : ''}
307
+
308
+ ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon'
309
+ ? `
310
+ // Initialize physics
311
+ this.world = new CANNON.World();
312
+ this.world.gravity.set(
313
+ ${(_c = (_b = project.settings.physics) === null || _b === void 0 ? void 0 : _b.gravity.x) !== null && _c !== void 0 ? _c : 0},
314
+ ${(_e = (_d = project.settings.physics) === null || _d === void 0 ? void 0 : _d.gravity.y) !== null && _e !== void 0 ? _e : -9.82},
315
+ 0
316
+ );
317
+ this.world.broadphase = new CANNON.NaiveBroadphase();
318
+ `
319
+ : ''}
320
+
321
+ ${hasPostProcessing
322
+ ? `
323
+ // Initialize post-processing
324
+ this.composer = new EffectComposer(this.renderer);
325
+ this.composer.addPass(new RenderPass(this.scene, this.camera));
326
+ this.composer.addPass(new UnrealBloomPass(
327
+ new THREE.Vector2(window.innerWidth, window.innerHeight),
328
+ 0.5, // strength
329
+ 0.4, // radius
330
+ 0.85 // threshold
331
+ ));
332
+ `
333
+ : ''}
334
+
335
+ // Initialize managers
336
+ this.clock = new THREE.Clock();
337
+ this.assetLoader = new AssetLoader();
338
+ this.inputManager = new InputManager();
339
+ this.gameManager = new GameManager(
340
+ this.scene,
341
+ this.camera,
342
+ this.assetLoader,
343
+ this.inputManager
344
+ ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon' ? ', this.world' : ''}
345
+ );
346
+
347
+ // Load assets
348
+ await this.loadAssets();
349
+
350
+ // Load initial scene
351
+ const initialScene = new ${this.sanitizeName(((_f = project.scenes[0]) === null || _f === void 0 ? void 0 : _f.name) || 'Main')}Scene(this.gameManager);
352
+ await initialScene.init();
353
+ this.gameManager.setCurrentScene(initialScene);
354
+
355
+ // Hide loading screen
356
+ const loadingScreen = document.getElementById('loading-screen');
357
+ if (loadingScreen) {
358
+ loadingScreen.classList.add('hidden');
359
+ }
360
+
361
+ // Handle resize
362
+ window.addEventListener('resize', this.onResize.bind(this));
363
+
364
+ // Start game loop
365
+ ${hasXR
366
+ ? `
367
+ this.renderer.setAnimationLoop(this.animate.bind(this));
368
+ `
369
+ : `
370
+ this.animate();
371
+ `}
372
+
373
+ console.log('${project.name} initialized!');
374
+ }
375
+
376
+ private async loadAssets()${useTS ? ': Promise<void>' : ''} {
377
+ const progressBar = document.getElementById('loading-progress');
378
+
379
+ const updateProgress = (progress${useTS ? ': number' : ''}) => {
380
+ if (progressBar) {
381
+ progressBar.style.width = \`\${progress * 100}%\`;
382
+ }
383
+ };
384
+
385
+ await this.assetLoader.loadAll(updateProgress);
386
+ }
387
+
388
+ private animate(${hasXR ? 'time' + (useTS ? ': number' : '') : ''})${useTS ? ': void' : ''} {
389
+ ${hasXR ? '' : 'requestAnimationFrame(this.animate.bind(this));'}
390
+
391
+ const delta = this.clock.getDelta();
392
+
393
+ ${hasOrbitControls ? 'this.controls.update();' : ''}
394
+
395
+ ${hasPhysics && (three === null || three === void 0 ? void 0 : three.physics) === 'cannon'
396
+ ? `
397
+ // Update physics
398
+ this.world.step(1 / 60, delta, 3);
399
+ `
400
+ : ''}
401
+
402
+ // Update game
403
+ this.gameManager.update(delta);
404
+
405
+ // Update input
406
+ this.inputManager.update();
407
+
408
+ // Render
409
+ ${hasPostProcessing ? 'this.composer.render();' : 'this.renderer.render(this.scene, this.camera);'}
410
+ }
411
+
412
+ private onResize()${useTS ? ': void' : ''} {
413
+ this.camera.aspect = window.innerWidth / window.innerHeight;
414
+ this.camera.updateProjectionMatrix();
415
+ this.renderer.setSize(window.innerWidth, window.innerHeight);
416
+ ${hasPostProcessing ? 'this.composer.setSize(window.innerWidth, window.innerHeight);' : ''}
417
+ }
418
+ }
419
+
420
+ // Start game
421
+ const game = new Game();
422
+ game.init().catch(console.error);
423
+ `;
424
+ this.addTextFile(`src/main.${ext}`, main);
425
+ }
426
+ exportScenes(project, options, useTS) {
427
+ for (const scene of project.scenes) {
428
+ this.exportScene(scene, project, useTS);
429
+ }
430
+ }
431
+ exportScene(scene, project, useTS) {
432
+ const ext = useTS ? 'ts' : 'js';
433
+ const sceneName = this.sanitizeName(scene.name);
434
+ let content = `import * as THREE from 'three';
435
+ import { GameManager } from '../game/GameManager${useTS ? '' : '.js'}';
436
+ ${useTS ? `import type { GameScene } from '../game/GameManager';` : ''}
437
+
438
+ export class ${sceneName}Scene ${useTS ? 'implements GameScene' : ''} {
439
+ ${useTS ? 'public name: string;' : ''}
440
+ ${useTS ? 'public container: THREE.Group;' : ''}
441
+ ${useTS ? 'private gameManager: GameManager;' : ''}
442
+ ${useTS ? 'private entities: Map<string, THREE.Object3D> = new Map();' : ''}
443
+ ${useTS ? 'private lights: THREE.Light[] = [];' : ''}
444
+
445
+ constructor(gameManager${useTS ? ': GameManager' : ''}) {
446
+ this.name = '${scene.name}';
447
+ this.gameManager = gameManager;
448
+ this.container = new THREE.Group();
449
+ ${useTS
450
+ ? ''
451
+ : `
452
+ this.entities = new Map();
453
+ this.lights = [];`}
454
+ }
455
+
456
+ async init()${useTS ? ': Promise<void>' : ''} {
457
+ // Add default lighting
458
+ this.setupLighting();
459
+
460
+ // Create entities
461
+ `;
462
+ // Create entities
463
+ for (const entity of scene.entities) {
464
+ content += this.generateEntityCode(entity, project, useTS);
465
+ }
466
+ content += `
467
+ // Add container to scene
468
+ this.gameManager.scene.add(this.container);
469
+ }
470
+
471
+ private setupLighting()${useTS ? ': void' : ''} {
472
+ // Ambient light
473
+ const ambient = new THREE.AmbientLight(0xffffff, 0.4);
474
+ this.container.add(ambient);
475
+ this.lights.push(ambient);
476
+
477
+ // Directional light (sun)
478
+ const directional = new THREE.DirectionalLight(0xffffff, 0.8);
479
+ directional.position.set(10, 20, 10);
480
+ directional.castShadow = true;
481
+ directional.shadow.mapSize.width = 2048;
482
+ directional.shadow.mapSize.height = 2048;
483
+ directional.shadow.camera.near = 0.1;
484
+ directional.shadow.camera.far = 100;
485
+ directional.shadow.camera.left = -20;
486
+ directional.shadow.camera.right = 20;
487
+ directional.shadow.camera.top = 20;
488
+ directional.shadow.camera.bottom = -20;
489
+ this.container.add(directional);
490
+ this.lights.push(directional);
491
+ }
492
+
493
+ update(delta${useTS ? ': number' : ''})${useTS ? ': void' : ''} {
494
+ // Update logic for scene entities
495
+ }
496
+
497
+ destroy()${useTS ? ': void' : ''} {
498
+ // Clean up
499
+ this.container.traverse((object) => {
500
+ if (object ${useTS ? 'instanceof THREE.Mesh' : '.isMesh'}) {
501
+ object.geometry.dispose();
502
+ if (Array.isArray(object.material)) {
503
+ object.material.forEach(m => m.dispose());
504
+ } else {
505
+ object.material.dispose();
506
+ }
507
+ }
508
+ });
509
+
510
+ this.gameManager.scene.remove(this.container);
511
+ this.entities.clear();
512
+ }
513
+ }
514
+ `;
515
+ this.addTextFile(`src/scenes/${sceneName}.${ext}`, content);
516
+ }
517
+ generateEntityCode(entity, project, useTS) {
518
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
519
+ let code = `
520
+ // Entity: ${entity.name}
521
+ {
522
+ `;
523
+ // Determine what kind of object to create based on components
524
+ const hasMesh = entity.components.some((c) => c.type === 'mesh' ||
525
+ c.type === 'box' ||
526
+ c.type === 'sphere' ||
527
+ c.type === 'plane' ||
528
+ c.type === 'cylinder');
529
+ const hasModel = entity.components.some((c) => c.type === 'model');
530
+ const hasLight = entity.components.some((c) => c.type.includes('light'));
531
+ if (hasLight) {
532
+ const lightComp = entity.components.find((c) => c.type.includes('light'));
533
+ if (lightComp) {
534
+ code += this.generateLightCode(entity, lightComp, useTS);
535
+ }
536
+ }
537
+ else if (hasModel) {
538
+ const modelComp = entity.components.find((c) => c.type === 'model');
539
+ if (modelComp) {
540
+ code += this.generateModelCode(entity, modelComp, project, useTS);
541
+ }
542
+ }
543
+ else if (hasMesh) {
544
+ code += this.generateMeshCode(entity, project, useTS);
545
+ }
546
+ else {
547
+ // Empty group
548
+ code += ` const entity = new THREE.Group();
549
+ entity.name = '${entity.name}';
550
+ `;
551
+ }
552
+ code += `
553
+ entity.position.set(${(_b = (_a = entity.position) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0}, ${(_d = (_c = entity.position) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0}, 0);
554
+ entity.rotation.z = ${(_e = entity.rotation) !== null && _e !== void 0 ? _e : 0};
555
+ entity.scale.set(${(_g = (_f = entity.scale) === null || _f === void 0 ? void 0 : _f.x) !== null && _g !== void 0 ? _g : 1}, ${(_j = (_h = entity.scale) === null || _h === void 0 ? void 0 : _h.y) !== null && _j !== void 0 ? _j : 1}, 1);
556
+
557
+ this.container.add(entity);
558
+ this.entities.set('${entity.id}', entity);
559
+ }
560
+ `;
561
+ // Process children
562
+ if (entity.children) {
563
+ for (const child of entity.children) {
564
+ code += this.generateEntityCode(child, project, useTS);
565
+ }
566
+ }
567
+ return code;
568
+ }
569
+ generateMeshCode(entity, project, useTS) {
570
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
571
+ const meshComp = entity.components.find((c) => c.type === 'mesh' ||
572
+ c.type === 'box' ||
573
+ c.type === 'sphere' ||
574
+ c.type === 'plane' ||
575
+ c.type === 'cylinder');
576
+ if (!meshComp)
577
+ return ' const entity = new THREE.Group();\n';
578
+ const meshProps = (_a = meshComp.properties) !== null && _a !== void 0 ? _a : {};
579
+ let geometryCode = '';
580
+ let materialCode = '';
581
+ // Geometry
582
+ switch (meshComp.type) {
583
+ case 'box':
584
+ geometryCode = `new THREE.BoxGeometry(${(_b = meshProps.width) !== null && _b !== void 0 ? _b : 1}, ${(_c = meshProps.height) !== null && _c !== void 0 ? _c : 1}, ${(_d = meshProps.depth) !== null && _d !== void 0 ? _d : 1})`;
585
+ break;
586
+ case 'sphere':
587
+ geometryCode = `new THREE.SphereGeometry(${(_e = meshProps.radius) !== null && _e !== void 0 ? _e : 0.5}, 32, 16)`;
588
+ break;
589
+ case 'plane':
590
+ geometryCode = `new THREE.PlaneGeometry(${(_f = meshProps.width) !== null && _f !== void 0 ? _f : 10}, ${(_g = meshProps.height) !== null && _g !== void 0 ? _g : 10})`;
591
+ break;
592
+ case 'cylinder':
593
+ geometryCode = `new THREE.CylinderGeometry(${(_h = meshProps.radiusTop) !== null && _h !== void 0 ? _h : 0.5}, ${(_j = meshProps.radiusBottom) !== null && _j !== void 0 ? _j : 0.5}, ${(_k = meshProps.height) !== null && _k !== void 0 ? _k : 1}, 32)`;
594
+ break;
595
+ default:
596
+ geometryCode = 'new THREE.BoxGeometry(1, 1, 1)';
597
+ }
598
+ // Material
599
+ const color = (_l = meshProps.color) !== null && _l !== void 0 ? _l : '#ffffff';
600
+ const materialId = meshProps.materialId;
601
+ const material = materialId ? project.assets.find((a) => a.id === materialId) : null;
602
+ if (material) {
603
+ const matColor = (_o = (_m = material.metadata) === null || _m === void 0 ? void 0 : _m.color) !== null && _o !== void 0 ? _o : color;
604
+ materialCode = `new THREE.MeshStandardMaterial({
605
+ color: '${matColor}',
606
+ roughness: ${(_q = (_p = material.metadata) === null || _p === void 0 ? void 0 : _p.roughness) !== null && _q !== void 0 ? _q : 0.5},
607
+ metalness: ${(_s = (_r = material.metadata) === null || _r === void 0 ? void 0 : _r.metalness) !== null && _s !== void 0 ? _s : 0.5},
608
+ })`;
609
+ }
610
+ else {
611
+ materialCode = `new THREE.MeshStandardMaterial({ color: '${color}' })`;
612
+ }
613
+ return ` const geometry = ${geometryCode};
614
+ const material = ${materialCode};
615
+ const entity = new THREE.Mesh(geometry, material);
616
+ entity.name = '${entity.name}';
617
+ entity.castShadow = true;
618
+ entity.receiveShadow = true;
619
+ `;
620
+ }
621
+ generateModelCode(entity, component, project, useTS) {
622
+ var _a;
623
+ const compProps = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
624
+ const modelPath = compProps.path;
625
+ return ` // Model loading is handled asynchronously
626
+ const entity = new THREE.Group();
627
+ entity.name = '${entity.name}';
628
+ ${modelPath
629
+ ? `
630
+ this.gameManager.assetLoader.getModel('${modelPath}').then(model => {
631
+ entity.add(model.scene.clone());
632
+ });`
633
+ : ''}
634
+ `;
635
+ }
636
+ generateLightCode(entity, component, useTS) {
637
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
638
+ const compProps = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
639
+ const color = (_b = compProps.color) !== null && _b !== void 0 ? _b : '#ffffff';
640
+ const intensity = (_c = compProps.intensity) !== null && _c !== void 0 ? _c : 1;
641
+ switch (component.type) {
642
+ case 'point-light':
643
+ return ` const entity = new THREE.PointLight('${color}', ${intensity}, ${(_d = compProps.distance) !== null && _d !== void 0 ? _d : 100});
644
+ entity.name = '${entity.name}';
645
+ entity.castShadow = ${(_e = compProps.castShadow) !== null && _e !== void 0 ? _e : true};
646
+ `;
647
+ case 'spot-light':
648
+ return ` const entity = new THREE.SpotLight('${color}', ${intensity});
649
+ entity.name = '${entity.name}';
650
+ entity.angle = ${(_f = compProps.angle) !== null && _f !== void 0 ? _f : Math.PI / 6};
651
+ entity.penumbra = ${(_g = compProps.penumbra) !== null && _g !== void 0 ? _g : 0.5};
652
+ entity.castShadow = ${(_h = compProps.castShadow) !== null && _h !== void 0 ? _h : true};
653
+ `;
654
+ case 'directional-light':
655
+ return ` const entity = new THREE.DirectionalLight('${color}', ${intensity});
656
+ entity.name = '${entity.name}';
657
+ entity.castShadow = ${(_j = compProps.castShadow) !== null && _j !== void 0 ? _j : true};
658
+ `;
659
+ case 'ambient-light':
660
+ return ` const entity = new THREE.AmbientLight('${color}', ${intensity});
661
+ entity.name = '${entity.name}';
662
+ `;
663
+ case 'hemisphere-light':
664
+ const groundColor = (_k = compProps.groundColor) !== null && _k !== void 0 ? _k : '#444444';
665
+ return ` const entity = new THREE.HemisphereLight('${color}', '${groundColor}', ${intensity});
666
+ entity.name = '${entity.name}';
667
+ `;
668
+ default:
669
+ return ` const entity = new THREE.Group();
670
+ entity.name = '${entity.name}';
671
+ `;
672
+ }
673
+ }
674
+ async exportScripts(project, options, useTS) {
675
+ for (const script of project.scripts) {
676
+ try {
677
+ const ast = this.graphToAST.convert(script);
678
+ const result = this.tsExporter.export(ast, {
679
+ includeDebugComments: options.debug,
680
+ });
681
+ for (const file of result.files) {
682
+ this.addTextFile(`src/scripts/${file.path}`, file.content);
683
+ }
684
+ }
685
+ catch (error) {
686
+ this.addWarning('SCRIPT_EXPORT_ERROR', `Failed to export script "${script.name}": ${error}`);
687
+ }
688
+ }
689
+ }
690
+ exportUtilities(three, useTS) {
691
+ const ext = useTS ? 'ts' : 'js';
692
+ const hasPhysics = (three === null || three === void 0 ? void 0 : three.physics) === 'cannon';
693
+ // GameManager
694
+ const gameManager = `import * as THREE from 'three';
695
+ import { AssetLoader } from './AssetLoader${useTS ? '' : '.js'}';
696
+ import { InputManager } from './InputManager${useTS ? '' : '.js'}';
697
+ ${hasPhysics ? `import * as CANNON from 'cannon-es';` : ''}
698
+
699
+ ${useTS
700
+ ? `
701
+ export interface GameScene {
702
+ name: string;
703
+ container: THREE.Group;
704
+ init(): Promise<void>;
705
+ update(delta: number): void;
706
+ destroy(): void;
707
+ }
708
+ `
709
+ : ''}
710
+
711
+ export class GameManager {
712
+ ${useTS ? 'public scene: THREE.Scene;' : ''}
713
+ ${useTS ? 'public camera: THREE.Camera;' : ''}
714
+ ${useTS ? 'public assetLoader: AssetLoader;' : ''}
715
+ ${useTS ? 'public input: InputManager;' : ''}
716
+ ${hasPhysics && useTS ? 'public world: CANNON.World;' : ''}
717
+ ${useTS ? 'private currentScene: GameScene | null = null;' : ''}
718
+ ${useTS ? 'private entities: Map<string, THREE.Object3D> = new Map();' : ''}
719
+ ${useTS ? 'private isPaused: boolean = false;' : ''}
720
+
721
+ constructor(
722
+ scene${useTS ? ': THREE.Scene' : ''},
723
+ camera${useTS ? ': THREE.Camera' : ''},
724
+ assetLoader${useTS ? ': AssetLoader' : ''},
725
+ inputManager${useTS ? ': InputManager' : ''}
726
+ ${hasPhysics ? `, world${useTS ? ': CANNON.World' : ''}` : ''}
727
+ ) {
728
+ this.scene = scene;
729
+ this.camera = camera;
730
+ this.assetLoader = assetLoader;
731
+ this.input = inputManager;
732
+ ${hasPhysics ? 'this.world = world;' : ''}
733
+ ${useTS
734
+ ? ''
735
+ : `
736
+ this.currentScene = null;
737
+ this.entities = new Map();
738
+ this.isPaused = false;`}
739
+ }
740
+
741
+ setCurrentScene(scene${useTS ? ': GameScene' : ''})${useTS ? ': void' : ''} {
742
+ if (this.currentScene) {
743
+ this.currentScene.destroy();
744
+ }
745
+ this.currentScene = scene;
746
+ }
747
+
748
+ registerEntity(id${useTS ? ': string' : ''}, entity${useTS ? ': THREE.Object3D' : ''})${useTS ? ': void' : ''} {
749
+ this.entities.set(id, entity);
750
+ }
751
+
752
+ getEntity(id${useTS ? ': string' : ''})${useTS ? ': THREE.Object3D | undefined' : ''} {
753
+ return this.entities.get(id);
754
+ }
755
+
756
+ update(delta${useTS ? ': number' : ''})${useTS ? ': void' : ''} {
757
+ if (this.isPaused) return;
758
+
759
+ if (this.currentScene) {
760
+ this.currentScene.update(delta);
761
+ }
762
+ }
763
+
764
+ pause()${useTS ? ': void' : ''} {
765
+ this.isPaused = true;
766
+ }
767
+
768
+ resume()${useTS ? ': void' : ''} {
769
+ this.isPaused = false;
770
+ }
771
+
772
+ get paused()${useTS ? ': boolean' : ''} {
773
+ return this.isPaused;
774
+ }
775
+
776
+ // Utility methods
777
+ raycast(origin${useTS ? ': THREE.Vector3' : ''}, direction${useTS ? ': THREE.Vector3' : ''})${useTS ? ': THREE.Intersection | null' : ''} {
778
+ const raycaster = new THREE.Raycaster(origin, direction);
779
+ const intersects = raycaster.intersectObjects(this.scene.children, true);
780
+ return intersects.length > 0 ? intersects[0] : null;
781
+ }
782
+
783
+ getMouseWorldPosition(screenX${useTS ? ': number' : ''}, screenY${useTS ? ': number' : ''}, plane${useTS ? '?: THREE.Plane' : ''})${useTS ? ': THREE.Vector3 | null' : ''} {
784
+ const mouse = new THREE.Vector2(
785
+ (screenX / window.innerWidth) * 2 - 1,
786
+ -(screenY / window.innerHeight) * 2 + 1
787
+ );
788
+
789
+ const raycaster = new THREE.Raycaster();
790
+ raycaster.setFromCamera(mouse, this.camera ${useTS ? 'as THREE.PerspectiveCamera' : ''});
791
+
792
+ if (plane) {
793
+ const target = new THREE.Vector3();
794
+ raycaster.ray.intersectPlane(plane, target);
795
+ return target;
796
+ }
797
+
798
+ const intersects = raycaster.intersectObjects(this.scene.children, true);
799
+ return intersects.length > 0 ? intersects[0].point : null;
800
+ }
801
+ }
802
+ `;
803
+ this.addTextFile(`src/game/GameManager.${ext}`, gameManager);
804
+ // AssetLoader
805
+ const assetLoader = `import * as THREE from 'three';
806
+ import { GLTFLoader${useTS ? ', GLTF' : ''} } from 'three/addons/loaders/GLTFLoader.js';
807
+ import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
808
+
809
+ export class AssetLoader {
810
+ ${useTS ? 'private textureLoader: THREE.TextureLoader;' : ''}
811
+ ${useTS ? 'private gltfLoader: GLTFLoader;' : ''}
812
+ ${useTS ? 'private audioLoader: THREE.AudioLoader;' : ''}
813
+ ${useTS ? 'private textures: Map<string, THREE.Texture> = new Map();' : ''}
814
+ ${useTS ? 'private models: Map<string, GLTF> = new Map();' : ''}
815
+ ${useTS ? 'private audio: Map<string, AudioBuffer> = new Map();' : ''}
816
+
817
+ constructor() {
818
+ this.textureLoader = new THREE.TextureLoader();
819
+
820
+ const dracoLoader = new DRACOLoader();
821
+ dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
822
+
823
+ this.gltfLoader = new GLTFLoader();
824
+ this.gltfLoader.setDRACOLoader(dracoLoader);
825
+
826
+ this.audioLoader = new THREE.AudioLoader();
827
+
828
+ ${useTS
829
+ ? ''
830
+ : `
831
+ this.textures = new Map();
832
+ this.models = new Map();
833
+ this.audio = new Map();`}
834
+ }
835
+
836
+ async loadAll(onProgress${useTS ? '?: (progress: number) => void' : ''})${useTS ? ': Promise<void>' : ''} {
837
+ // Load all assets here
838
+ // This would be populated based on project assets
839
+ if (onProgress) onProgress(1);
840
+ }
841
+
842
+ async loadTexture(path${useTS ? ': string' : ''})${useTS ? ': Promise<THREE.Texture>' : ''} {
843
+ if (this.textures.has(path)) {
844
+ return this.textures.get(path)${useTS ? '!' : ''};
845
+ }
846
+
847
+ return new Promise((resolve, reject) => {
848
+ this.textureLoader.load(
849
+ path,
850
+ (texture) => {
851
+ this.textures.set(path, texture);
852
+ resolve(texture);
853
+ },
854
+ undefined,
855
+ reject
856
+ );
857
+ });
858
+ }
859
+
860
+ async loadModel(path${useTS ? ': string' : ''})${useTS ? ': Promise<GLTF>' : ''} {
861
+ if (this.models.has(path)) {
862
+ return this.models.get(path)${useTS ? '!' : ''};
863
+ }
864
+
865
+ return new Promise((resolve, reject) => {
866
+ this.gltfLoader.load(
867
+ path,
868
+ (gltf) => {
869
+ this.models.set(path, gltf);
870
+ resolve(gltf);
871
+ },
872
+ undefined,
873
+ reject
874
+ );
875
+ });
876
+ }
877
+
878
+ getTexture(path${useTS ? ': string' : ''})${useTS ? ': THREE.Texture | undefined' : ''} {
879
+ return this.textures.get(path);
880
+ }
881
+
882
+ getModel(path${useTS ? ': string' : ''})${useTS ? ': Promise<GLTF>' : ''} {
883
+ return this.loadModel(path);
884
+ }
885
+
886
+ getAudio(path${useTS ? ': string' : ''})${useTS ? ': AudioBuffer | undefined' : ''} {
887
+ return this.audio.get(path);
888
+ }
889
+ }
890
+ `;
891
+ this.addTextFile(`src/game/AssetLoader.${ext}`, assetLoader);
892
+ // InputManager
893
+ const inputManager = `import * as THREE from 'three';
894
+
895
+ export class InputManager {
896
+ ${useTS ? 'private keys: Set<string> = new Set();' : ''}
897
+ ${useTS ? 'private keysJustPressed: Set<string> = new Set();' : ''}
898
+ ${useTS ? 'private keysJustReleased: Set<string> = new Set();' : ''}
899
+ ${useTS ? 'private mousePosition: THREE.Vector2 = new THREE.Vector2();' : ''}
900
+ ${useTS ? 'private mouseButtons: Set<number> = new Set();' : ''}
901
+ ${useTS ? 'private mouseDelta: THREE.Vector2 = new THREE.Vector2();' : ''}
902
+ ${useTS ? 'private wheelDelta: number = 0;' : ''}
903
+
904
+ constructor() {
905
+ ${useTS
906
+ ? ''
907
+ : `
908
+ this.keys = new Set();
909
+ this.keysJustPressed = new Set();
910
+ this.keysJustReleased = new Set();
911
+ this.mousePosition = new THREE.Vector2();
912
+ this.mouseButtons = new Set();
913
+ this.mouseDelta = new THREE.Vector2();
914
+ this.wheelDelta = 0;`}
915
+
916
+ window.addEventListener('keydown', this.onKeyDown.bind(this));
917
+ window.addEventListener('keyup', this.onKeyUp.bind(this));
918
+ window.addEventListener('mousemove', this.onMouseMove.bind(this));
919
+ window.addEventListener('mousedown', this.onMouseDown.bind(this));
920
+ window.addEventListener('mouseup', this.onMouseUp.bind(this));
921
+ window.addEventListener('wheel', this.onWheel.bind(this));
922
+ window.addEventListener('contextmenu', (e) => e.preventDefault());
923
+ }
924
+
925
+ private onKeyDown(e${useTS ? ': KeyboardEvent' : ''})${useTS ? ': void' : ''} {
926
+ if (!this.keys.has(e.code)) {
927
+ this.keysJustPressed.add(e.code);
928
+ }
929
+ this.keys.add(e.code);
930
+ }
931
+
932
+ private onKeyUp(e${useTS ? ': KeyboardEvent' : ''})${useTS ? ': void' : ''} {
933
+ this.keys.delete(e.code);
934
+ this.keysJustReleased.add(e.code);
935
+ }
936
+
937
+ private onMouseMove(e${useTS ? ': MouseEvent' : ''})${useTS ? ': void' : ''} {
938
+ this.mouseDelta.set(e.movementX, e.movementY);
939
+ this.mousePosition.set(e.clientX, e.clientY);
940
+ }
941
+
942
+ private onMouseDown(e${useTS ? ': MouseEvent' : ''})${useTS ? ': void' : ''} {
943
+ this.mouseButtons.add(e.button);
944
+ }
945
+
946
+ private onMouseUp(e${useTS ? ': MouseEvent' : ''})${useTS ? ': void' : ''} {
947
+ this.mouseButtons.delete(e.button);
948
+ }
949
+
950
+ private onWheel(e${useTS ? ': WheelEvent' : ''})${useTS ? ': void' : ''} {
951
+ this.wheelDelta = e.deltaY;
952
+ }
953
+
954
+ isKeyPressed(code${useTS ? ': string' : ''})${useTS ? ': boolean' : ''} {
955
+ return this.keys.has(code);
956
+ }
957
+
958
+ isKeyJustPressed(code${useTS ? ': string' : ''})${useTS ? ': boolean' : ''} {
959
+ return this.keysJustPressed.has(code);
960
+ }
961
+
962
+ isKeyJustReleased(code${useTS ? ': string' : ''})${useTS ? ': boolean' : ''} {
963
+ return this.keysJustReleased.has(code);
964
+ }
965
+
966
+ isMouseButtonPressed(button${useTS ? ': number' : ''})${useTS ? ': boolean' : ''} {
967
+ return this.mouseButtons.has(button);
968
+ }
969
+
970
+ getMousePosition()${useTS ? ': THREE.Vector2' : ''} {
971
+ return this.mousePosition.clone();
972
+ }
973
+
974
+ getMouseDelta()${useTS ? ': THREE.Vector2' : ''} {
975
+ return this.mouseDelta.clone();
976
+ }
977
+
978
+ getWheelDelta()${useTS ? ': number' : ''} {
979
+ return this.wheelDelta;
980
+ }
981
+
982
+ getAxis(positive${useTS ? ': string' : ''}, negative${useTS ? ': string' : ''})${useTS ? ': number' : ''} {
983
+ let value = 0;
984
+ if (this.keys.has(positive)) value += 1;
985
+ if (this.keys.has(negative)) value -= 1;
986
+ return value;
987
+ }
988
+
989
+ update()${useTS ? ': void' : ''} {
990
+ this.keysJustPressed.clear();
991
+ this.keysJustReleased.clear();
992
+ this.mouseDelta.set(0, 0);
993
+ this.wheelDelta = 0;
994
+ }
995
+ }
996
+ `;
997
+ this.addTextFile(`src/game/InputManager.${ext}`, inputManager);
998
+ }
999
+ exportShaders(project) {
1000
+ var _a, _b, _c, _d;
1001
+ // Export shader assets
1002
+ const shaders = project.assets.filter((a) => a.type === 'shader');
1003
+ for (const shader of shaders) {
1004
+ const vertexShader = (_b = (_a = shader.metadata) === null || _a === void 0 ? void 0 : _a.vertex) !== null && _b !== void 0 ? _b : `
1005
+ varying vec2 vUv;
1006
+
1007
+ void main() {
1008
+ vUv = uv;
1009
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
1010
+ }`;
1011
+ const fragmentShader = (_d = (_c = shader.metadata) === null || _c === void 0 ? void 0 : _c.fragment) !== null && _d !== void 0 ? _d : `
1012
+ varying vec2 vUv;
1013
+
1014
+ void main() {
1015
+ gl_FragColor = vec4(vUv, 0.5, 1.0);
1016
+ }`;
1017
+ this.addTextFile(`src/shaders/${this.sanitizeName(shader.name)}.vert`, vertexShader);
1018
+ this.addTextFile(`src/shaders/${this.sanitizeName(shader.name)}.frag`, fragmentShader);
1019
+ }
1020
+ }
1021
+ exportBundlerConfig(bundler, useTS) {
1022
+ if (bundler === 'vite') {
1023
+ this.addTextFile('vite.config.ts', `import { defineConfig } from 'vite';
1024
+
1025
+ export default defineConfig({
1026
+ base: './',
1027
+ build: {
1028
+ outDir: 'dist',
1029
+ assetsDir: 'assets',
1030
+ sourcemap: true,
1031
+ },
1032
+ server: {
1033
+ port: 3000,
1034
+ open: true,
1035
+ },
1036
+ assetsInclude: ['**/*.glb', '**/*.gltf', '**/*.hdr'],
1037
+ });
1038
+ `);
1039
+ }
1040
+ else if (bundler === 'webpack') {
1041
+ this.addTextFile('webpack.config.js', `const path = require('path');
1042
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
1043
+
1044
+ module.exports = {
1045
+ entry: './src/main.${useTS ? 'ts' : 'js'}',
1046
+ output: {
1047
+ filename: 'bundle.js',
1048
+ path: path.resolve(__dirname, 'dist'),
1049
+ },
1050
+ resolve: {
1051
+ extensions: ['.ts', '.js'],
1052
+ alias: {
1053
+ 'three/addons': path.resolve(__dirname, 'node_modules/three/examples/jsm'),
1054
+ },
1055
+ },
1056
+ module: {
1057
+ rules: [
1058
+ {
1059
+ test: /\\.ts$/,
1060
+ use: 'ts-loader',
1061
+ exclude: /node_modules/,
1062
+ },
1063
+ {
1064
+ test: /\\.(glb|gltf|hdr)$/,
1065
+ type: 'asset/resource',
1066
+ },
1067
+ ],
1068
+ },
1069
+ plugins: [
1070
+ new HtmlWebpackPlugin({
1071
+ template: 'index.html',
1072
+ }),
1073
+ ],
1074
+ devServer: {
1075
+ static: './dist',
1076
+ port: 3000,
1077
+ open: true,
1078
+ },
1079
+ };
1080
+ `);
1081
+ }
1082
+ }
1083
+ exportTSConfig() {
1084
+ const tsconfig = {
1085
+ compilerOptions: {
1086
+ target: 'ES2020',
1087
+ useDefineForClassFields: true,
1088
+ module: 'ESNext',
1089
+ lib: ['ES2020', 'DOM', 'DOM.Iterable'],
1090
+ skipLibCheck: true,
1091
+ moduleResolution: 'bundler',
1092
+ allowImportingTsExtensions: true,
1093
+ resolveJsonModule: true,
1094
+ isolatedModules: true,
1095
+ noEmit: true,
1096
+ strict: true,
1097
+ noUnusedLocals: true,
1098
+ noUnusedParameters: true,
1099
+ noFallthroughCasesInSwitch: true,
1100
+ paths: {
1101
+ 'three/addons/*': ['node_modules/three/examples/jsm/*'],
1102
+ },
1103
+ },
1104
+ include: ['src'],
1105
+ };
1106
+ this.addTextFile('tsconfig.json', JSON.stringify(tsconfig, null, 2));
1107
+ }
1108
+ sanitizeName(name) {
1109
+ return name.replace(/[^a-zA-Z0-9]/g, '');
1110
+ }
1111
+ }
1112
+
1113
+ export { ThreeJSExporter };
1114
+ //# sourceMappingURL=ThreeJSExporter.js.map