@nice2dev/game-engine 1.0.2 → 1.0.3

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 +2 -2
@@ -0,0 +1,759 @@
1
+ import { SceneImporter } from './SceneImporter.js';
2
+
3
+ /**
4
+ * @file AsepriteImporter.ts
5
+ * @description Import Aseprite sprite editor files (.aseprite, .ase)
6
+ * PRO-1.3: Scene Format Interoperability
7
+ *
8
+ * Supports:
9
+ * - Aseprite binary format (.aseprite, .ase)
10
+ * - Aseprite JSON export format
11
+ *
12
+ * Features:
13
+ * - Layers (normal, group, reference)
14
+ * - Frames and animation
15
+ * - Tags (animation clips)
16
+ * - Slices (9-slice, pivot)
17
+ * - Palette
18
+ * - Cel data
19
+ * - Blend modes
20
+ */
21
+ // ============================================================
22
+ // Aseprite Chunk Types
23
+ // ============================================================
24
+ const CHUNK_TYPES = {
25
+ LAYER: 0x2004,
26
+ CEL: 0x2005,
27
+ EXTERNAL_FILES: 0x2008,
28
+ TAGS: 0x2018,
29
+ PALETTE: 0x2019,
30
+ SLICE: 0x2022};
31
+ const BLEND_MODES = [
32
+ 'normal',
33
+ 'multiply',
34
+ 'screen',
35
+ 'overlay',
36
+ 'darken',
37
+ 'lighten',
38
+ 'color-dodge',
39
+ 'color-burn',
40
+ 'hard-light',
41
+ 'soft-light',
42
+ 'difference',
43
+ 'exclusion',
44
+ 'hue',
45
+ 'saturation',
46
+ 'color',
47
+ 'luminosity',
48
+ 'addition',
49
+ 'subtract',
50
+ 'divide',
51
+ ];
52
+ // ============================================================
53
+ // Aseprite Importer
54
+ // ============================================================
55
+ class AsepriteImporter extends SceneImporter {
56
+ constructor() {
57
+ super('aseprite');
58
+ this.aseFile = null;
59
+ }
60
+ async import(options) {
61
+ const startTime = Date.now();
62
+ this.options = options;
63
+ this.clearMessages();
64
+ this.aseFile = null;
65
+ const errors = await this.validate(options.sourcePath);
66
+ if (errors.some((e) => e.fatal)) {
67
+ return {
68
+ ...this.createEmptyResult(),
69
+ errors: errors,
70
+ };
71
+ }
72
+ const scenes = [];
73
+ const assets = [];
74
+ try {
75
+ const content = await this.readFile(options.sourcePath);
76
+ // Detect format: binary or JSON
77
+ if (typeof content === 'string') {
78
+ // JSON export
79
+ const json = JSON.parse(content);
80
+ const spriteSheet = this.parseJsonExport(json, options.sourcePath);
81
+ assets.push(this.createSpriteSheetAsset(spriteSheet, json.meta.image));
82
+ }
83
+ else {
84
+ // Binary format
85
+ this.aseFile = this.parseBinaryFile(content);
86
+ if (this.aseFile) {
87
+ // Create sprite sheet asset
88
+ const spriteSheet = this.createSpriteSheetFromBinary();
89
+ assets.push(this.createSpriteSheetAsset(spriteSheet, options.sourcePath));
90
+ // Create palette asset if indexed color
91
+ if (this.aseFile.header.colorDepth === 8) {
92
+ assets.push(this.createPaletteAsset());
93
+ }
94
+ }
95
+ }
96
+ // Create a pseudo-scene for the sprite
97
+ if (this.aseFile || assets.length > 0) {
98
+ const scene = this.createSpriteScene(options.sourcePath);
99
+ scenes.push(scene);
100
+ }
101
+ }
102
+ catch (error) {
103
+ this.addError('IMPORT_ERROR', `Failed to import: ${error}`, options.sourcePath, undefined, true);
104
+ }
105
+ return this.createResult(scenes, assets, startTime);
106
+ }
107
+ async parseFile(content, filePath) {
108
+ if (typeof content === 'string') {
109
+ try {
110
+ const json = JSON.parse(content);
111
+ const spriteSheet = this.parseJsonExport(json, filePath);
112
+ return {
113
+ id: this.generateId(),
114
+ name: spriteSheet.name,
115
+ type: 'animation',
116
+ path: json.meta.image,
117
+ metadata: {
118
+ frames: spriteSheet.frames,
119
+ animations: spriteSheet.animations,
120
+ },
121
+ };
122
+ }
123
+ catch (_a) {
124
+ return null;
125
+ }
126
+ }
127
+ // Binary parsing returns scene with sprite entity
128
+ this.aseFile = this.parseBinaryFile(content);
129
+ if (this.aseFile) {
130
+ return this.createSpriteScene(filePath);
131
+ }
132
+ return null;
133
+ }
134
+ async validate(sourcePath) {
135
+ const errors = [];
136
+ if (!this.canHandle(sourcePath)) {
137
+ errors.push({
138
+ code: 'INVALID_FORMAT',
139
+ message: `File ${sourcePath} is not a valid Aseprite file`,
140
+ file: sourcePath,
141
+ fatal: true,
142
+ });
143
+ }
144
+ return errors;
145
+ }
146
+ // ----------------------------------------
147
+ // JSON Export Parsing
148
+ // ----------------------------------------
149
+ parseJsonExport(json, filePath) {
150
+ const frames = [];
151
+ const animations = {};
152
+ // Parse frames (can be object or array)
153
+ const frameEntries = Array.isArray(json.frames)
154
+ ? json.frames.map((f, i) => [`frame_${i}`, f])
155
+ : Object.entries(json.frames);
156
+ for (const [name, frameData] of frameEntries) {
157
+ frames.push({
158
+ name,
159
+ x: frameData.frame.x,
160
+ y: frameData.frame.y,
161
+ width: frameData.frame.w,
162
+ height: frameData.frame.h,
163
+ sourceWidth: frameData.sourceSize.w,
164
+ sourceHeight: frameData.sourceSize.h,
165
+ offsetX: frameData.spriteSourceSize.x,
166
+ offsetY: frameData.spriteSourceSize.y,
167
+ trimmed: frameData.trimmed,
168
+ });
169
+ }
170
+ // Parse frame tags as animations
171
+ if (json.meta.frameTags) {
172
+ for (const tag of json.meta.frameTags) {
173
+ const animFrames = [];
174
+ for (let i = tag.from; i <= tag.to; i++) {
175
+ const frame = frameEntries[i][1];
176
+ animFrames.push({
177
+ index: i,
178
+ duration: frame.duration,
179
+ x: frameEntries[i][1].frame.x,
180
+ y: frameEntries[i][1].frame.y,
181
+ width: frameEntries[i][1].frame.w,
182
+ height: frameEntries[i][1].frame.h,
183
+ });
184
+ }
185
+ animations[tag.name] = {
186
+ name: tag.name,
187
+ frames: animFrames,
188
+ loop: true, // Determine from direction
189
+ };
190
+ }
191
+ }
192
+ // If no tags, create a default animation with all frames
193
+ if (Object.keys(animations).length === 0 && frames.length > 0) {
194
+ const allFrames = frameEntries.map(([_, f], index) => ({
195
+ index,
196
+ duration: f.duration,
197
+ x: f.frame.x,
198
+ y: f.frame.y,
199
+ width: f.frame.w,
200
+ height: f.frame.h,
201
+ }));
202
+ animations['default'] = {
203
+ name: 'default',
204
+ frames: allFrames,
205
+ loop: true,
206
+ };
207
+ }
208
+ return {
209
+ name: filePath.substring(filePath.lastIndexOf('/') + 1).replace(/\.\w+$/, ''),
210
+ imagePath: json.meta.image,
211
+ frames,
212
+ animations,
213
+ };
214
+ }
215
+ // ----------------------------------------
216
+ // Binary Format Parsing
217
+ // ----------------------------------------
218
+ parseBinaryFile(buffer) {
219
+ const view = new DataView(buffer);
220
+ let offset = 0;
221
+ // Read header
222
+ const header = this.readHeader(view, offset);
223
+ offset += 128; // Header is always 128 bytes
224
+ if (header.magicNumber !== 0xa5e0) {
225
+ this.addError('INVALID_MAGIC', 'Invalid Aseprite file magic number');
226
+ return null;
227
+ }
228
+ const file = {
229
+ header,
230
+ frames: [],
231
+ palette: { size: 0, colors: [], firstColorIndex: 0, lastColorIndex: 0 },
232
+ layers: [],
233
+ tags: [],
234
+ slices: [],
235
+ };
236
+ // Read frames
237
+ for (let f = 0; f < header.frames; f++) {
238
+ const frame = this.readFrame(view, offset, file);
239
+ file.frames.push(frame);
240
+ offset += this.getFrameSize(view, offset);
241
+ }
242
+ // Build layer hierarchy
243
+ this.buildLayerHierarchy(file.layers);
244
+ return file;
245
+ }
246
+ readHeader(view, offset) {
247
+ return {
248
+ fileSize: view.getUint32(offset, true),
249
+ magicNumber: view.getUint16(offset + 4, true),
250
+ frames: view.getUint16(offset + 6, true),
251
+ width: view.getUint16(offset + 8, true),
252
+ height: view.getUint16(offset + 10, true),
253
+ colorDepth: view.getUint16(offset + 12, true),
254
+ flags: view.getUint32(offset + 14, true),
255
+ speed: view.getUint16(offset + 18, true),
256
+ transparentIndex: view.getUint8(offset + 28),
257
+ numColors: view.getUint16(offset + 32, true),
258
+ pixelWidth: view.getUint8(offset + 34),
259
+ pixelHeight: view.getUint8(offset + 35),
260
+ gridX: view.getInt16(offset + 36, true),
261
+ gridY: view.getInt16(offset + 38, true),
262
+ gridWidth: view.getUint16(offset + 40, true),
263
+ gridHeight: view.getUint16(offset + 42, true),
264
+ };
265
+ }
266
+ readFrame(view, offset, file) {
267
+ view.getUint32(offset, true);
268
+ const frameMagic = view.getUint16(offset + 4, true);
269
+ if (frameMagic !== 0xf1fa) {
270
+ this.addWarning('INVALID_FRAME_MAGIC', `Invalid frame magic at offset ${offset}`);
271
+ }
272
+ const oldChunks = view.getUint16(offset + 6, true);
273
+ const duration = view.getUint16(offset + 8, true);
274
+ const newChunks = view.getUint32(offset + 12, true);
275
+ const numChunks = newChunks === 0 ? oldChunks : newChunks;
276
+ const frame = {
277
+ duration,
278
+ chunks: [],
279
+ cels: [],
280
+ };
281
+ let chunkOffset = offset + 16;
282
+ for (let c = 0; c < numChunks; c++) {
283
+ const chunkSize = view.getUint32(chunkOffset, true);
284
+ const chunkType = view.getUint16(chunkOffset + 4, true);
285
+ const chunkData = new Uint8Array(view.buffer, chunkOffset + 6, chunkSize - 6);
286
+ this.processChunk(chunkType, chunkData, frame, file);
287
+ frame.chunks.push({
288
+ type: chunkType,
289
+ data: chunkData.buffer,
290
+ });
291
+ chunkOffset += chunkSize;
292
+ }
293
+ return frame;
294
+ }
295
+ getFrameSize(view, offset) {
296
+ return view.getUint32(offset, true);
297
+ }
298
+ processChunk(type, data, frame, file) {
299
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
300
+ switch (type) {
301
+ case CHUNK_TYPES.LAYER:
302
+ file.layers.push(this.readLayerChunk(view));
303
+ break;
304
+ case CHUNK_TYPES.CEL:
305
+ frame.cels.push(this.readCelChunk(view, data, file.header));
306
+ break;
307
+ case CHUNK_TYPES.TAGS:
308
+ file.tags.push(...this.readTagsChunk(view));
309
+ break;
310
+ case CHUNK_TYPES.PALETTE:
311
+ file.palette = this.readPaletteChunk(view);
312
+ break;
313
+ case CHUNK_TYPES.SLICE:
314
+ file.slices.push(this.readSliceChunk(view));
315
+ break;
316
+ case CHUNK_TYPES.EXTERNAL_FILES:
317
+ file.externalFiles = this.readExternalFilesChunk(view);
318
+ break;
319
+ }
320
+ }
321
+ readLayerChunk(view) {
322
+ const flags = view.getUint16(0, true);
323
+ const typeNum = view.getUint16(2, true);
324
+ const childLevel = view.getUint16(4, true);
325
+ // Skip default width/height at 6 and 8
326
+ const blendModeNum = view.getUint16(10, true);
327
+ const opacity = view.getUint8(12);
328
+ // Skip 3 reserved bytes
329
+ const nameLength = view.getUint16(16, true);
330
+ const name = this.readString(view, 18, nameLength);
331
+ let tilesetIndex;
332
+ if (typeNum === 2 && view.byteLength > 18 + nameLength) {
333
+ tilesetIndex = view.getUint32(18 + nameLength, true);
334
+ }
335
+ return {
336
+ flags,
337
+ type: typeNum === 0 ? 'normal' : typeNum === 1 ? 'group' : 'tilemap',
338
+ childLevel,
339
+ blendMode: BLEND_MODES[blendModeNum] || 'normal',
340
+ opacity,
341
+ name,
342
+ tilesetIndex,
343
+ visible: (flags & 0x0001) !== 0,
344
+ editable: (flags & 0x0002) !== 0,
345
+ lockMovement: (flags & 0x0004) !== 0,
346
+ background: (flags & 0x0008) !== 0,
347
+ continuous: (flags & 0x0010) !== 0,
348
+ collapsed: (flags & 0x0020) !== 0,
349
+ reference: (flags & 0x0040) !== 0,
350
+ children: [],
351
+ };
352
+ }
353
+ readCelChunk(view, data, header) {
354
+ const layerIndex = view.getUint16(0, true);
355
+ const x = view.getInt16(2, true);
356
+ const y = view.getInt16(4, true);
357
+ const opacity = view.getUint8(6);
358
+ const celType = view.getUint16(7, true);
359
+ const zIndex = view.getInt16(9, true);
360
+ const cel = {
361
+ layerIndex,
362
+ x,
363
+ y,
364
+ opacity,
365
+ celType: celType === 0
366
+ ? 'raw'
367
+ : celType === 1
368
+ ? 'linked'
369
+ : celType === 2
370
+ ? 'compressed'
371
+ : 'compressed-tilemap',
372
+ zIndex,
373
+ };
374
+ // Skip 5 reserved bytes, then read type-specific data
375
+ let offset = 16;
376
+ if (celType === 1) {
377
+ // Linked cel
378
+ cel.linkedFrame = view.getUint16(offset, true);
379
+ }
380
+ else if (celType === 0 || celType === 2) {
381
+ // Raw or compressed pixel data
382
+ cel.width = view.getUint16(offset, true);
383
+ cel.height = view.getUint16(offset + 2, true);
384
+ if (celType === 0) {
385
+ // Raw pixels
386
+ const bytesPerPixel = header.colorDepth / 8;
387
+ const pixelCount = cel.width * cel.height * bytesPerPixel;
388
+ cel.pixels = new Uint8Array(data.slice(offset + 4, offset + 4 + pixelCount));
389
+ }
390
+ else {
391
+ // Compressed (zlib)
392
+ // Would need zlib decompression here
393
+ // For now, store compressed data reference
394
+ cel.pixels = new Uint8Array(data.slice(offset + 4));
395
+ }
396
+ }
397
+ else if (celType === 3) {
398
+ // Compressed tilemap
399
+ cel.width = view.getUint16(offset, true);
400
+ cel.height = view.getUint16(offset + 2, true);
401
+ cel.tileWidth = view.getUint16(offset + 4, true);
402
+ cel.tileHeight = view.getUint16(offset + 6, true);
403
+ // Tile data follows (compressed)
404
+ }
405
+ return cel;
406
+ }
407
+ readTagsChunk(view) {
408
+ const tags = [];
409
+ const numTags = view.getUint16(0, true);
410
+ // Skip 8 reserved bytes
411
+ let offset = 10;
412
+ for (let i = 0; i < numTags; i++) {
413
+ const fromFrame = view.getUint16(offset, true);
414
+ const toFrame = view.getUint16(offset + 2, true);
415
+ const directionNum = view.getUint8(offset + 4);
416
+ const repeat = view.getUint16(offset + 5, true);
417
+ // Skip 6 reserved bytes
418
+ // Skip deprecated RGB bytes at offset + 13
419
+ // Skip 1 extra byte
420
+ const nameLength = view.getUint16(offset + 17, true);
421
+ const name = this.readString(view, offset + 19, nameLength);
422
+ tags.push({
423
+ fromFrame,
424
+ toFrame,
425
+ direction: directionNum === 0
426
+ ? 'forward'
427
+ : directionNum === 1
428
+ ? 'reverse'
429
+ : directionNum === 2
430
+ ? 'pingpong'
431
+ : 'pingpong-reverse',
432
+ repeat,
433
+ name,
434
+ color: { red: 0, green: 0, blue: 0, alpha: 255 },
435
+ });
436
+ offset += 19 + nameLength;
437
+ }
438
+ return tags;
439
+ }
440
+ readPaletteChunk(view) {
441
+ const size = view.getUint32(0, true);
442
+ const firstColorIndex = view.getUint32(4, true);
443
+ const lastColorIndex = view.getUint32(8, true);
444
+ // Skip 8 reserved bytes
445
+ const colors = [];
446
+ let offset = 20;
447
+ for (let i = firstColorIndex; i <= lastColorIndex; i++) {
448
+ const hasName = view.getUint16(offset, true) & 0x0001;
449
+ const red = view.getUint8(offset + 2);
450
+ const green = view.getUint8(offset + 3);
451
+ const blue = view.getUint8(offset + 4);
452
+ const alpha = view.getUint8(offset + 5);
453
+ let name;
454
+ offset += 6;
455
+ if (hasName) {
456
+ const nameLength = view.getUint16(offset, true);
457
+ name = this.readString(view, offset + 2, nameLength);
458
+ offset += 2 + nameLength;
459
+ }
460
+ colors[i] = { red, green, blue, alpha, name };
461
+ }
462
+ return { size, colors, firstColorIndex, lastColorIndex };
463
+ }
464
+ readSliceChunk(view) {
465
+ const numKeys = view.getUint32(0, true);
466
+ const flags = view.getUint32(4, true);
467
+ // Skip 4 reserved bytes
468
+ const nameLength = view.getUint16(12, true);
469
+ const name = this.readString(view, 14, nameLength);
470
+ const has9Slices = (flags & 0x0001) !== 0;
471
+ const hasPivot = (flags & 0x0002) !== 0;
472
+ const keys = [];
473
+ let offset = 14 + nameLength;
474
+ for (let i = 0; i < numKeys; i++) {
475
+ const frameNumber = view.getUint32(offset, true);
476
+ const x = view.getInt32(offset + 4, true);
477
+ const y = view.getInt32(offset + 8, true);
478
+ const width = view.getUint32(offset + 12, true);
479
+ const height = view.getUint32(offset + 16, true);
480
+ offset += 20;
481
+ const key = { frameNumber, x, y, width, height };
482
+ if (has9Slices) {
483
+ key.centerX = view.getInt32(offset, true);
484
+ key.centerY = view.getInt32(offset + 4, true);
485
+ key.centerWidth = view.getUint32(offset + 8, true);
486
+ key.centerHeight = view.getUint32(offset + 12, true);
487
+ offset += 16;
488
+ }
489
+ if (hasPivot) {
490
+ key.pivotX = view.getInt32(offset, true);
491
+ key.pivotY = view.getInt32(offset + 4, true);
492
+ offset += 8;
493
+ }
494
+ keys.push(key);
495
+ }
496
+ return { name, flags, keys, has9Slices, hasPivot };
497
+ }
498
+ readExternalFilesChunk(view) {
499
+ const files = [];
500
+ const numEntries = view.getUint32(0, true);
501
+ // Skip 8 reserved bytes
502
+ let offset = 12;
503
+ for (let i = 0; i < numEntries; i++) {
504
+ const id = view.getUint32(offset, true);
505
+ const typeNum = view.getUint8(offset + 4);
506
+ // Skip 7 reserved bytes
507
+ const pathLength = view.getUint16(offset + 12, true);
508
+ const path = this.readString(view, offset + 14, pathLength);
509
+ const typeMap = {
510
+ 0: 'external-palette',
511
+ 1: 'external-tileset',
512
+ 2: 'extension',
513
+ 3: 'extension-property',
514
+ };
515
+ files.push({
516
+ id,
517
+ type: typeMap[typeNum] || 'extension',
518
+ path,
519
+ });
520
+ offset += 14 + pathLength;
521
+ }
522
+ return files;
523
+ }
524
+ readString(view, offset, length) {
525
+ const bytes = new Uint8Array(view.buffer, view.byteOffset + offset, length);
526
+ return new TextDecoder('utf-8').decode(bytes);
527
+ }
528
+ buildLayerHierarchy(layers) {
529
+ const stack = [];
530
+ for (let i = 0; i < layers.length; i++) {
531
+ const layer = layers[i];
532
+ // Pop stack until we find the parent level
533
+ while (stack.length > layer.childLevel) {
534
+ stack.pop();
535
+ }
536
+ // Set parent
537
+ if (stack.length > 0) {
538
+ layer.parent = stack[stack.length - 1];
539
+ layers[layer.parent].children.push(i);
540
+ }
541
+ // Push this layer if it's a group
542
+ if (layer.type === 'group') {
543
+ stack.push(i);
544
+ }
545
+ }
546
+ }
547
+ // ----------------------------------------
548
+ // Conversion
549
+ // ----------------------------------------
550
+ createSpriteSheetFromBinary() {
551
+ if (!this.aseFile) {
552
+ return { name: 'unknown', imagePath: '', frames: [] };
553
+ }
554
+ const frames = [];
555
+ const animations = {};
556
+ // Create frames
557
+ for (let i = 0; i < this.aseFile.frames.length; i++) {
558
+ frames.push({
559
+ name: `frame_${i}`,
560
+ x: 0,
561
+ y: i * this.aseFile.header.height,
562
+ width: this.aseFile.header.width,
563
+ height: this.aseFile.header.height,
564
+ });
565
+ }
566
+ // Create animations from tags
567
+ for (const tag of this.aseFile.tags) {
568
+ const animFrames = [];
569
+ for (let i = tag.fromFrame; i <= tag.toFrame; i++) {
570
+ animFrames.push({
571
+ index: i,
572
+ duration: this.aseFile.frames[i].duration,
573
+ x: 0,
574
+ y: i * this.aseFile.header.height,
575
+ width: this.aseFile.header.width,
576
+ height: this.aseFile.header.height,
577
+ });
578
+ }
579
+ animations[tag.name] = {
580
+ name: tag.name,
581
+ frames: animFrames,
582
+ loop: tag.repeat === 0, // 0 means infinite loop
583
+ };
584
+ }
585
+ // Default animation if no tags
586
+ if (Object.keys(animations).length === 0) {
587
+ const allFrames = this.aseFile.frames.map((f, i) => ({
588
+ index: i,
589
+ duration: f.duration,
590
+ x: 0,
591
+ y: i * this.aseFile.header.height,
592
+ width: this.aseFile.header.width,
593
+ height: this.aseFile.header.height,
594
+ }));
595
+ animations['default'] = {
596
+ name: 'default',
597
+ frames: allFrames,
598
+ loop: true,
599
+ };
600
+ }
601
+ return {
602
+ name: 'sprite',
603
+ imagePath: '',
604
+ frames,
605
+ animations,
606
+ };
607
+ }
608
+ createSpriteSheetAsset(spriteSheet, imagePath) {
609
+ var _a, _b, _c, _d, _e;
610
+ return {
611
+ id: this.generateId(),
612
+ name: spriteSheet.name,
613
+ type: 'animation',
614
+ path: imagePath,
615
+ data: {
616
+ frames: spriteSheet.frames,
617
+ animations: spriteSheet.animations,
618
+ width: (_a = this.aseFile) === null || _a === void 0 ? void 0 : _a.header.width,
619
+ height: (_b = this.aseFile) === null || _b === void 0 ? void 0 : _b.header.height,
620
+ colorDepth: (_c = this.aseFile) === null || _c === void 0 ? void 0 : _c.header.colorDepth,
621
+ layers: (_d = this.aseFile) === null || _d === void 0 ? void 0 : _d.layers.map((l) => ({
622
+ name: l.name,
623
+ type: l.type,
624
+ blendMode: l.blendMode,
625
+ opacity: l.opacity,
626
+ visible: l.visible,
627
+ })),
628
+ slices: (_e = this.aseFile) === null || _e === void 0 ? void 0 : _e.slices.map((s) => ({
629
+ name: s.name,
630
+ has9Slices: s.has9Slices,
631
+ hasPivot: s.hasPivot,
632
+ keys: s.keys,
633
+ })),
634
+ },
635
+ };
636
+ }
637
+ createPaletteAsset() {
638
+ var _a;
639
+ return {
640
+ id: this.generateId(),
641
+ name: 'palette',
642
+ type: 'data',
643
+ path: '',
644
+ data: {
645
+ colors: (_a = this.aseFile) === null || _a === void 0 ? void 0 : _a.palette.colors.map((c) => ({
646
+ r: c.red,
647
+ g: c.green,
648
+ b: c.blue,
649
+ a: c.alpha,
650
+ name: c.name,
651
+ })),
652
+ },
653
+ };
654
+ }
655
+ createSpriteScene(filePath) {
656
+ var _a, _b, _c, _d, _e;
657
+ const name = filePath.substring(filePath.lastIndexOf('/') + 1).replace(/\.\w+$/, '');
658
+ const width = ((_a = this.aseFile) === null || _a === void 0 ? void 0 : _a.header.width) || 64;
659
+ const height = ((_b = this.aseFile) === null || _b === void 0 ? void 0 : _b.header.height) || 64;
660
+ const entities = [];
661
+ // Create entity for each layer
662
+ if (this.aseFile) {
663
+ for (let i = 0; i < this.aseFile.layers.length; i++) {
664
+ const layer = this.aseFile.layers[i];
665
+ if (layer.type === 'normal') {
666
+ entities.push({
667
+ id: this.generateId(),
668
+ name: layer.name,
669
+ components: [
670
+ {
671
+ type: 'Transform',
672
+ data: { position: { x: 0, y: 0 }, rotation: 0, scale: { x: 1, y: 1 } },
673
+ },
674
+ {
675
+ type: 'Sprite',
676
+ data: {
677
+ layer: layer.name,
678
+ blendMode: layer.blendMode,
679
+ opacity: layer.opacity / 255,
680
+ },
681
+ },
682
+ ],
683
+ children: [],
684
+ tags: ['layer'],
685
+ active: layer.visible,
686
+ });
687
+ }
688
+ }
689
+ }
690
+ // Add main sprite entity
691
+ entities.unshift({
692
+ id: this.generateId(),
693
+ name: name,
694
+ components: [
695
+ {
696
+ type: 'Transform',
697
+ data: { position: { x: width / 2, y: height / 2 }, rotation: 0, scale: { x: 1, y: 1 } },
698
+ },
699
+ {
700
+ type: 'AnimatedSprite',
701
+ data: {
702
+ spriteSheet: name,
703
+ currentAnimation: ((_d = (_c = this.aseFile) === null || _c === void 0 ? void 0 : _c.tags[0]) === null || _d === void 0 ? void 0 : _d.name) || 'default',
704
+ playing: true,
705
+ loop: true,
706
+ },
707
+ },
708
+ ],
709
+ children: [],
710
+ tags: ['sprite'],
711
+ active: true,
712
+ });
713
+ return {
714
+ id: this.generateId(),
715
+ name,
716
+ entities,
717
+ settings: {
718
+ width,
719
+ height,
720
+ backgroundColor: ((_e = this.aseFile) === null || _e === void 0 ? void 0 : _e.header.colorDepth) === 8
721
+ ? this.paletteColorToHex(this.aseFile.header.transparentIndex)
722
+ : '#00000000',
723
+ },
724
+ };
725
+ }
726
+ paletteColorToHex(index) {
727
+ var _a;
728
+ if (!((_a = this.aseFile) === null || _a === void 0 ? void 0 : _a.palette.colors[index]))
729
+ return '#000000';
730
+ const c = this.aseFile.palette.colors[index];
731
+ return `#${c.red.toString(16).padStart(2, '0')}${c.green.toString(16).padStart(2, '0')}${c.blue.toString(16).padStart(2, '0')}`;
732
+ }
733
+ // ----------------------------------------
734
+ // Helper Methods
735
+ // ----------------------------------------
736
+ async readFile(path) {
737
+ var _a;
738
+ if (typeof globalThis.process !== 'undefined' && ((_a = globalThis.process.versions) === null || _a === void 0 ? void 0 : _a.node)) {
739
+ const fs = await import('fs');
740
+ // Check if it's JSON or binary
741
+ if (path.endsWith('.json')) {
742
+ return fs.readFileSync(path, 'utf-8');
743
+ }
744
+ const buffer = fs.readFileSync(path);
745
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
746
+ }
747
+ else if (typeof fetch !== 'undefined') {
748
+ const response = await fetch(path);
749
+ if (path.endsWith('.json')) {
750
+ return response.text();
751
+ }
752
+ return response.arrayBuffer();
753
+ }
754
+ throw new Error('Unable to read file in current environment');
755
+ }
756
+ }
757
+
758
+ export { AsepriteImporter };
759
+ //# sourceMappingURL=AsepriteImporter.js.map