@nice2dev/ui-graphics 1.3.15 → 1.3.17

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 (294) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/animation/AnimatedPerson.js +470 -143
  3. package/dist/cjs/animation/AnimationEditor.js +289 -101
  4. package/dist/cjs/animation/Audience.js +83 -61
  5. package/dist/cjs/animation/BodyRenderer.js +69 -28
  6. package/dist/cjs/animation/animationHelper.js +281 -288
  7. package/dist/cjs/animation/characterTypes.js +200 -203
  8. package/dist/cjs/animation/choreoDSL.js +205 -219
  9. package/dist/cjs/animation/choreography.js +4 -32
  10. package/dist/cjs/animation/karaokeIntegration.js +68 -77
  11. package/dist/cjs/animation/lottieExport.js +108 -114
  12. package/dist/cjs/animation/motionPath.js +225 -248
  13. package/dist/cjs/animation/physics.js +227 -254
  14. package/dist/cjs/animation/rig/RigPlayer.js +53 -56
  15. package/dist/cjs/animation/rig/RiggedBody.js +71 -26
  16. package/dist/cjs/animation/rig/choreoRigBridge.js +72 -77
  17. package/dist/cjs/animation/rig/ik.js +13 -18
  18. package/dist/cjs/animation/rig/poseOps.js +34 -41
  19. package/dist/cjs/animation/rig/presets.js +64 -72
  20. package/dist/cjs/animation/rig/rigMath.js +25 -32
  21. package/dist/cjs/animation/rig/rigTypes.js +59 -63
  22. package/dist/cjs/animation/shapes/arms.js +31 -13
  23. package/dist/cjs/animation/shapes/eyes.js +129 -47
  24. package/dist/cjs/animation/shapes/hair.js +72 -45
  25. package/dist/cjs/animation/shapes/heads.js +131 -57
  26. package/dist/cjs/animation/shapes/headwear.js +47 -38
  27. package/dist/cjs/animation/shapes/legs.js +31 -13
  28. package/dist/cjs/animation/shapes/mouths.js +120 -44
  29. package/dist/cjs/animation/shapes/noses.js +80 -25
  30. package/dist/cjs/animation/shapes/outfits.js +101 -39
  31. package/dist/cjs/animation/shapes/torsos.js +15 -11
  32. package/dist/cjs/animation/spineExport.js +103 -121
  33. package/dist/cjs/core/LocalUI.js +108 -43
  34. package/dist/cjs/core/NiceBrushEngine.js +758 -552
  35. package/dist/cjs/core/collaboration.js +249 -251
  36. package/dist/cjs/core/colorBlindness.js +100 -115
  37. package/dist/cjs/core/dragDrop.js +155 -158
  38. package/dist/cjs/core/editorAsk.js +51 -41
  39. package/dist/cjs/core/fixes.js +140 -171
  40. package/dist/cjs/core/gridGuides.js +166 -201
  41. package/dist/cjs/core/historyVisual.js +156 -135
  42. package/dist/cjs/core/i18n.js +13 -14
  43. package/dist/cjs/core/integrations.js +238 -249
  44. package/dist/cjs/core/minimap.js +149 -151
  45. package/dist/cjs/core/plugins.js +98 -113
  46. package/dist/cjs/core/rtl.js +71 -83
  47. package/dist/cjs/core/shortcuts.js +196 -225
  48. package/dist/cjs/core/theme.js +142 -149
  49. package/dist/cjs/core/yjsCollaboration.js +232 -293
  50. package/dist/cjs/design/design-tools.js +12 -22
  51. package/dist/cjs/font/NiceFontEditor.js +877 -316
  52. package/dist/cjs/font/fontFormatUtils.js +388 -448
  53. package/dist/cjs/game/GameAsset2dEditor.js +1201 -392
  54. package/dist/cjs/game/GameAsset2dEditor.module.css.js +146 -5
  55. package/dist/cjs/game/gameAssetTypes.js +7 -16
  56. package/dist/cjs/game/gameAssetUtils.js +390 -413
  57. package/dist/cjs/game/useGameAssetEditor.js +820 -763
  58. package/dist/cjs/index.js +81 -84
  59. package/dist/cjs/nice2dev-ui-graphics.css +1 -1
  60. package/dist/cjs/node_modules/lib0/array.js +8 -70
  61. package/dist/cjs/node_modules/lib0/binary.js +3 -20
  62. package/dist/cjs/node_modules/lib0/broadcastchannel.js +24 -86
  63. package/dist/cjs/node_modules/lib0/buffer.js +15 -82
  64. package/dist/cjs/node_modules/lib0/conditions.js +3 -16
  65. package/dist/cjs/node_modules/lib0/decoding.js +108 -287
  66. package/dist/cjs/node_modules/lib0/dom.js +14 -44
  67. package/dist/cjs/node_modules/lib0/encoding.js +68 -418
  68. package/dist/cjs/node_modules/lib0/environment.js +26 -92
  69. package/dist/cjs/node_modules/lib0/error.js +5 -29
  70. package/dist/cjs/node_modules/lib0/function.js +27 -66
  71. package/dist/cjs/node_modules/lib0/iterator.js +8 -33
  72. package/dist/cjs/node_modules/lib0/logging.common.js +12 -22
  73. package/dist/cjs/node_modules/lib0/logging.js +32 -71
  74. package/dist/cjs/node_modules/lib0/map.js +16 -86
  75. package/dist/cjs/node_modules/lib0/math.js +3 -32
  76. package/dist/cjs/node_modules/lib0/number.js +4 -15
  77. package/dist/cjs/node_modules/lib0/object.js +14 -88
  78. package/dist/cjs/node_modules/lib0/observable.js +38 -78
  79. package/dist/cjs/node_modules/lib0/pair.js +3 -20
  80. package/dist/cjs/node_modules/lib0/prng.js +8 -77
  81. package/dist/cjs/node_modules/lib0/promise.js +6 -30
  82. package/dist/cjs/node_modules/lib0/random.js +8 -23
  83. package/dist/cjs/node_modules/lib0/schema.js +313 -687
  84. package/dist/cjs/node_modules/lib0/set.js +3 -10
  85. package/dist/cjs/node_modules/lib0/storage.js +20 -55
  86. package/dist/cjs/node_modules/lib0/string.js +17 -72
  87. package/dist/cjs/node_modules/lib0/symbol.js +2 -12
  88. package/dist/cjs/node_modules/lib0/time.js +2 -15
  89. package/dist/cjs/node_modules/lib0/trait/equality.js +3 -28
  90. package/dist/cjs/node_modules/lib0/url.js +4 -18
  91. package/dist/cjs/node_modules/lib0/webcrypto.js +2 -5
  92. package/dist/cjs/node_modules/y-protocols/auth.js +5 -19
  93. package/dist/cjs/node_modules/y-protocols/awareness.js +53 -116
  94. package/dist/cjs/node_modules/y-protocols/sync.js +16 -103
  95. package/dist/cjs/node_modules/y-websocket/src/y-websocket.js +77 -219
  96. package/dist/cjs/node_modules/yjs/dist/yjs.js +2128 -4868
  97. package/dist/cjs/photo/FilterThumb.js +37 -25
  98. package/dist/cjs/photo/NiceAITools.js +679 -467
  99. package/dist/cjs/photo/PhotoEditor.js +34 -20
  100. package/dist/cjs/photo/PhotoEditor.module.css.js +296 -5
  101. package/dist/cjs/photo/PhotoEditorCanvas.js +250 -91
  102. package/dist/cjs/photo/PhotoEditorLeftPanel.js +1086 -224
  103. package/dist/cjs/photo/PhotoEditorToolbar.js +135 -19
  104. package/dist/cjs/photo/photoEditorActions.js +89 -72
  105. package/dist/cjs/photo/photoEditorTypes.js +29 -32
  106. package/dist/cjs/photo/photoFilters.js +959 -985
  107. package/dist/cjs/photo/photoOverlays.js +899 -945
  108. package/dist/cjs/photo/photoSelection.js +427 -499
  109. package/dist/cjs/photo/usePhotoEditor.js +739 -741
  110. package/dist/cjs/pixel/HSVPicker.js +191 -175
  111. package/dist/cjs/pixel/PixelEditor.js +159 -48
  112. package/dist/cjs/pixel/PixelEditor.module.css.js +209 -5
  113. package/dist/cjs/pixel/PixelEditorCanvas.js +29 -16
  114. package/dist/cjs/pixel/PixelEditorMenuBar.js +160 -162
  115. package/dist/cjs/pixel/PixelEditorRightPanel.js +377 -45
  116. package/dist/cjs/pixel/PixelEditorStatusBar.js +47 -20
  117. package/dist/cjs/pixel/PixelEditorTimeline.js +106 -23
  118. package/dist/cjs/pixel/PixelEditorToolbar.js +99 -21
  119. package/dist/cjs/pixel/SpriteGeneratorPanel.js +483 -303
  120. package/dist/cjs/pixel/animalGeneratorPresets.js +776 -601
  121. package/dist/cjs/pixel/asepriteFormat.js +511 -560
  122. package/dist/cjs/pixel/buildingGeneratorPresets.js +693 -520
  123. package/dist/cjs/pixel/characterGeneratorPresets.js +644 -544
  124. package/dist/cjs/pixel/pixel-pro.js +52 -63
  125. package/dist/cjs/pixel/pixelEditorExports.js +388 -428
  126. package/dist/cjs/pixel/pixelEditorTypes.js +91 -108
  127. package/dist/cjs/pixel/pixelEditorUtils.js +519 -561
  128. package/dist/cjs/pixel/spriteGeneratorCore.js +206 -257
  129. package/dist/cjs/pixel/usePixelEditor.js +1321 -1343
  130. package/dist/cjs/texture/Nice3DTexturePainter.js +707 -440
  131. package/dist/cjs/ui/NiceUIDesigner.js +954 -527
  132. package/dist/cjs/vector/NiceSvgToCode.js +586 -446
  133. package/dist/cjs/vector/VectorEditor.js +290 -117
  134. package/dist/cjs/vector/VectorEditor.module.css.js +86 -5
  135. package/dist/cjs/vector/VectorEditorMenuBar.js +333 -275
  136. package/dist/cjs/vector/VectorEditorRightPanel.js +1094 -371
  137. package/dist/cjs/vector/VectorEditorShapeRenderer.js +198 -60
  138. package/dist/cjs/vector/VectorEditorStatusBar.js +39 -13
  139. package/dist/cjs/vector/useVectorEditor.js +848 -889
  140. package/dist/cjs/vector/vectorAnimation.js +110 -137
  141. package/dist/cjs/vector/vectorBooleanOps.js +398 -485
  142. package/dist/cjs/vector/vectorEditorExport.js +201 -203
  143. package/dist/cjs/vector/vectorEditorImport.js +173 -189
  144. package/dist/cjs/vector/vectorEditorTypes.js +42 -49
  145. package/dist/cjs/vector/vectorGradients.js +151 -174
  146. package/dist/cjs/vector/vectorIconExport.js +52 -59
  147. package/dist/cjs/vector/vectorIconImport.js +169 -219
  148. package/dist/esm/animation/AnimatedPerson.js +470 -141
  149. package/dist/esm/animation/AnimationEditor.js +290 -100
  150. package/dist/esm/animation/Audience.js +83 -59
  151. package/dist/esm/animation/BodyRenderer.js +71 -25
  152. package/dist/esm/animation/animationHelper.js +284 -287
  153. package/dist/esm/animation/characterTypes.js +204 -202
  154. package/dist/esm/animation/choreoDSL.js +212 -218
  155. package/dist/esm/animation/choreography.js +8 -31
  156. package/dist/esm/animation/karaokeIntegration.js +74 -76
  157. package/dist/esm/animation/lottieExport.js +112 -113
  158. package/dist/esm/animation/motionPath.js +235 -247
  159. package/dist/esm/animation/physics.js +235 -253
  160. package/dist/esm/animation/rig/RigPlayer.js +53 -54
  161. package/dist/esm/animation/rig/RiggedBody.js +71 -24
  162. package/dist/esm/animation/rig/choreoRigBridge.js +74 -76
  163. package/dist/esm/animation/rig/ik.js +14 -17
  164. package/dist/esm/animation/rig/poseOps.js +37 -40
  165. package/dist/esm/animation/rig/presets.js +70 -71
  166. package/dist/esm/animation/rig/rigMath.js +28 -31
  167. package/dist/esm/animation/rig/rigTypes.js +62 -62
  168. package/dist/esm/animation/shapes/arms.js +32 -12
  169. package/dist/esm/animation/shapes/eyes.js +135 -46
  170. package/dist/esm/animation/shapes/hair.js +80 -44
  171. package/dist/esm/animation/shapes/heads.js +140 -56
  172. package/dist/esm/animation/shapes/headwear.js +54 -37
  173. package/dist/esm/animation/shapes/legs.js +32 -12
  174. package/dist/esm/animation/shapes/mouths.js +127 -43
  175. package/dist/esm/animation/shapes/noses.js +87 -24
  176. package/dist/esm/animation/shapes/outfits.js +106 -38
  177. package/dist/esm/animation/shapes/torsos.js +16 -10
  178. package/dist/esm/animation/spineExport.js +106 -120
  179. package/dist/esm/core/LocalUI.js +111 -42
  180. package/dist/esm/core/NiceBrushEngine.js +761 -551
  181. package/dist/esm/core/collaboration.js +255 -250
  182. package/dist/esm/core/colorBlindness.js +106 -114
  183. package/dist/esm/core/dragDrop.js +157 -157
  184. package/dist/esm/core/editorAsk.js +53 -40
  185. package/dist/esm/core/fixes.js +145 -170
  186. package/dist/esm/core/gridGuides.js +178 -200
  187. package/dist/esm/core/historyVisual.js +158 -134
  188. package/dist/esm/core/i18n.js +15 -13
  189. package/dist/esm/core/integrations.js +244 -248
  190. package/dist/esm/core/minimap.js +151 -150
  191. package/dist/esm/core/plugins.js +102 -112
  192. package/dist/esm/core/rtl.js +77 -82
  193. package/dist/esm/core/shortcuts.js +200 -224
  194. package/dist/esm/core/theme.js +150 -148
  195. package/dist/esm/core/yjsCollaboration.js +240 -292
  196. package/dist/esm/design/design-tools.js +13 -21
  197. package/dist/esm/font/NiceFontEditor.js +880 -315
  198. package/dist/esm/font/fontFormatUtils.js +394 -447
  199. package/dist/esm/game/GameAsset2dEditor.js +1202 -391
  200. package/dist/esm/game/GameAsset2dEditor.module.css.js +146 -3
  201. package/dist/esm/game/gameAssetTypes.js +8 -15
  202. package/dist/esm/game/gameAssetUtils.js +408 -412
  203. package/dist/esm/game/useGameAssetEditor.js +821 -762
  204. package/dist/esm/index.js +332 -69
  205. package/dist/esm/nice2dev-ui-graphics.css +1 -1
  206. package/dist/esm/node_modules/lib0/array.js +15 -69
  207. package/dist/esm/node_modules/lib0/binary.js +14 -19
  208. package/dist/esm/node_modules/lib0/broadcastchannel.js +27 -85
  209. package/dist/esm/node_modules/lib0/buffer.js +20 -80
  210. package/dist/esm/node_modules/lib0/conditions.js +4 -15
  211. package/dist/esm/node_modules/lib0/decoding.js +128 -286
  212. package/dist/esm/node_modules/lib0/dom.js +20 -43
  213. package/dist/esm/node_modules/lib0/encoding.js +90 -415
  214. package/dist/esm/node_modules/lib0/environment.js +33 -91
  215. package/dist/esm/node_modules/lib0/error.js +8 -28
  216. package/dist/esm/node_modules/lib0/function.js +31 -65
  217. package/dist/esm/node_modules/lib0/iterator.js +11 -32
  218. package/dist/esm/node_modules/lib0/logging.common.js +22 -21
  219. package/dist/esm/node_modules/lib0/logging.js +44 -70
  220. package/dist/esm/node_modules/lib0/map.js +21 -85
  221. package/dist/esm/node_modules/lib0/math.js +9 -31
  222. package/dist/esm/node_modules/lib0/number.js +7 -14
  223. package/dist/esm/node_modules/lib0/object.js +26 -87
  224. package/dist/esm/node_modules/lib0/observable.js +40 -77
  225. package/dist/esm/node_modules/lib0/pair.js +5 -19
  226. package/dist/esm/node_modules/lib0/prng.js +15 -76
  227. package/dist/esm/node_modules/lib0/promise.js +7 -29
  228. package/dist/esm/node_modules/lib0/random.js +10 -22
  229. package/dist/esm/node_modules/lib0/schema.js +367 -686
  230. package/dist/esm/node_modules/lib0/set.js +4 -9
  231. package/dist/esm/node_modules/lib0/storage.js +23 -54
  232. package/dist/esm/node_modules/lib0/string.js +26 -71
  233. package/dist/esm/node_modules/lib0/symbol.js +3 -11
  234. package/dist/esm/node_modules/lib0/time.js +3 -14
  235. package/dist/esm/node_modules/lib0/trait/equality.js +5 -27
  236. package/dist/esm/node_modules/lib0/url.js +5 -17
  237. package/dist/esm/node_modules/lib0/webcrypto.js +3 -4
  238. package/dist/esm/node_modules/y-protocols/auth.js +7 -18
  239. package/dist/esm/node_modules/y-protocols/awareness.js +58 -115
  240. package/dist/esm/node_modules/y-protocols/sync.js +26 -102
  241. package/dist/esm/node_modules/y-websocket/src/y-websocket.js +82 -218
  242. package/dist/esm/node_modules/yjs/dist/yjs.js +2263 -4899
  243. package/dist/esm/photo/FilterThumb.js +37 -23
  244. package/dist/esm/photo/NiceAITools.js +685 -466
  245. package/dist/esm/photo/PhotoEditor.js +34 -18
  246. package/dist/esm/photo/PhotoEditor.module.css.js +296 -3
  247. package/dist/esm/photo/PhotoEditorCanvas.js +250 -89
  248. package/dist/esm/photo/PhotoEditorLeftPanel.js +1086 -222
  249. package/dist/esm/photo/PhotoEditorToolbar.js +135 -17
  250. package/dist/esm/photo/photoEditorActions.js +93 -71
  251. package/dist/esm/photo/photoEditorTypes.js +32 -31
  252. package/dist/esm/photo/photoFilters.js +967 -984
  253. package/dist/esm/photo/photoOverlays.js +913 -944
  254. package/dist/esm/photo/photoSelection.js +438 -498
  255. package/dist/esm/photo/usePhotoEditor.js +740 -740
  256. package/dist/esm/pixel/HSVPicker.js +192 -174
  257. package/dist/esm/pixel/PixelEditor.js +160 -47
  258. package/dist/esm/pixel/PixelEditor.module.css.js +209 -3
  259. package/dist/esm/pixel/PixelEditorCanvas.js +29 -14
  260. package/dist/esm/pixel/PixelEditorMenuBar.js +160 -160
  261. package/dist/esm/pixel/PixelEditorRightPanel.js +377 -43
  262. package/dist/esm/pixel/PixelEditorStatusBar.js +47 -18
  263. package/dist/esm/pixel/PixelEditorTimeline.js +106 -21
  264. package/dist/esm/pixel/PixelEditorToolbar.js +99 -19
  265. package/dist/esm/pixel/SpriteGeneratorPanel.js +483 -301
  266. package/dist/esm/pixel/animalGeneratorPresets.js +782 -600
  267. package/dist/esm/pixel/asepriteFormat.js +517 -559
  268. package/dist/esm/pixel/buildingGeneratorPresets.js +699 -519
  269. package/dist/esm/pixel/characterGeneratorPresets.js +650 -543
  270. package/dist/esm/pixel/pixel-pro.js +53 -62
  271. package/dist/esm/pixel/pixelEditorExports.js +397 -427
  272. package/dist/esm/pixel/pixelEditorTypes.js +103 -107
  273. package/dist/esm/pixel/pixelEditorUtils.js +551 -560
  274. package/dist/esm/pixel/spriteGeneratorCore.js +223 -256
  275. package/dist/esm/pixel/usePixelEditor.js +1322 -1342
  276. package/dist/esm/texture/Nice3DTexturePainter.js +709 -439
  277. package/dist/esm/ui/NiceUIDesigner.js +957 -526
  278. package/dist/esm/vector/NiceSvgToCode.js +589 -445
  279. package/dist/esm/vector/VectorEditor.js +291 -116
  280. package/dist/esm/vector/VectorEditor.module.css.js +86 -3
  281. package/dist/esm/vector/VectorEditorMenuBar.js +333 -273
  282. package/dist/esm/vector/VectorEditorRightPanel.js +1094 -369
  283. package/dist/esm/vector/VectorEditorShapeRenderer.js +199 -59
  284. package/dist/esm/vector/VectorEditorStatusBar.js +39 -11
  285. package/dist/esm/vector/useVectorEditor.js +849 -888
  286. package/dist/esm/vector/vectorAnimation.js +115 -136
  287. package/dist/esm/vector/vectorBooleanOps.js +401 -484
  288. package/dist/esm/vector/vectorEditorExport.js +207 -202
  289. package/dist/esm/vector/vectorEditorImport.js +174 -188
  290. package/dist/esm/vector/vectorEditorTypes.js +50 -48
  291. package/dist/esm/vector/vectorGradients.js +158 -173
  292. package/dist/esm/vector/vectorIconExport.js +53 -58
  293. package/dist/esm/vector/vectorIconImport.js +171 -218
  294. package/package.json +9 -15
@@ -1,462 +1,458 @@
1
- import { DEFAULT_PROJECT_SETTINGS } from './gameAssetTypes.js';
2
-
3
- /**
4
- * gameAssetUtils.ts — Utilities for GameAsset2dEditor
5
- */
6
- /* ────────────────────────────────────────────────────────────────
7
- ID GENERATION
8
- ──────────────────────────────────────────────────────────────── */
1
+ import { DEFAULT_PROJECT_SETTINGS } from "./gameAssetTypes.js";
9
2
  let idCounter = 0;
10
- const generateId = (prefix = 'id') => `${prefix}_${++idCounter}_${Date.now().toString(36)}`;
11
- /* ────────────────────────────────────────────────────────────────
12
- IMAGE UTILITIES
13
- ──────────────────────────────────────────────────────────────── */
3
+ const generateId = (prefix = "id") => `${prefix}_${++idCounter}_${Date.now().toString(36)}`;
14
4
  const imageDataToDataUrl = (imageData) => {
15
- const canvas = document.createElement('canvas');
16
- canvas.width = imageData.width;
17
- canvas.height = imageData.height;
18
- const ctx = canvas.getContext('2d');
19
- ctx.putImageData(imageData, 0, 0);
20
- return canvas.toDataURL('image/png');
5
+ const canvas = document.createElement("canvas");
6
+ canvas.width = imageData.width;
7
+ canvas.height = imageData.height;
8
+ const ctx = canvas.getContext("2d");
9
+ ctx.putImageData(imageData, 0, 0);
10
+ return canvas.toDataURL("image/png");
21
11
  };
22
12
  const dataUrlToImageData = async (dataUrl) => {
23
- return new Promise((resolve, reject) => {
24
- const img = new Image();
25
- img.onload = () => {
26
- const canvas = document.createElement('canvas');
27
- canvas.width = img.width;
28
- canvas.height = img.height;
29
- const ctx = canvas.getContext('2d');
30
- ctx.drawImage(img, 0, 0);
31
- resolve(ctx.getImageData(0, 0, img.width, img.height));
32
- };
33
- img.onerror = reject;
34
- img.src = dataUrl;
35
- });
13
+ return new Promise((resolve, reject) => {
14
+ const img = new Image();
15
+ img.onload = () => {
16
+ const canvas = document.createElement("canvas");
17
+ canvas.width = img.width;
18
+ canvas.height = img.height;
19
+ const ctx = canvas.getContext("2d");
20
+ ctx.drawImage(img, 0, 0);
21
+ resolve(ctx.getImageData(0, 0, img.width, img.height));
22
+ };
23
+ img.onerror = reject;
24
+ img.src = dataUrl;
25
+ });
36
26
  };
37
27
  const loadImage = (src) => {
38
- return new Promise((resolve, reject) => {
39
- const img = new Image();
40
- img.onload = () => resolve(img);
41
- img.onerror = reject;
42
- img.src = src;
43
- });
28
+ return new Promise((resolve, reject) => {
29
+ const img = new Image();
30
+ img.onload = () => resolve(img);
31
+ img.onerror = reject;
32
+ img.src = src;
33
+ });
44
34
  };
45
- /* ────────────────────────────────────────────────────────────────
46
- TILE UTILITIES
47
- ──────────────────────────────────────────────────────────────── */
48
35
  const createTileFromImage = (imageData, name) => {
49
- return {
50
- id: generateId('tile'),
51
- name,
52
- image: imageData,
53
- thumbnail: imageDataToDataUrl(imageData),
54
- width: imageData.width,
55
- height: imageData.height,
56
- properties: {},
57
- };
36
+ return {
37
+ id: generateId("tile"),
38
+ name,
39
+ image: imageData,
40
+ thumbnail: imageDataToDataUrl(imageData),
41
+ width: imageData.width,
42
+ height: imageData.height,
43
+ properties: {}
44
+ };
58
45
  };
59
46
  const createEmptyTileLayer = (name, mapWidth, mapHeight) => {
60
- const tiles = [];
61
- for (let y = 0; y < mapHeight; y++) {
62
- tiles.push(new Array(mapWidth).fill(null));
63
- }
64
- return {
65
- id: generateId('layer'),
66
- name,
67
- visible: true,
68
- locked: false,
69
- opacity: 1,
70
- tiles,
71
- parallaxX: 1,
72
- parallaxY: 1,
73
- offsetX: 0,
74
- offsetY: 0,
75
- zIndex: 0,
76
- };
47
+ const tiles = [];
48
+ for (let y = 0; y < mapHeight; y++) {
49
+ tiles.push(new Array(mapWidth).fill(null));
50
+ }
51
+ return {
52
+ id: generateId("layer"),
53
+ name,
54
+ visible: true,
55
+ locked: false,
56
+ opacity: 1,
57
+ tiles,
58
+ parallaxX: 1,
59
+ parallaxY: 1,
60
+ offsetX: 0,
61
+ offsetY: 0,
62
+ zIndex: 0
63
+ };
77
64
  };
78
- const createEmptyTileMap = (name, width, height, tileWidth, tileHeight, mode = '2d') => {
79
- const mapMode = mode === 'tilemap' ? '2d' : mode;
80
- return {
81
- id: generateId('map'),
82
- name,
83
- mode: mapMode,
84
- width,
85
- height,
86
- tileWidth,
87
- tileHeight,
88
- layers: [createEmptyTileLayer('Layer 1', width, height)],
89
- properties: {},
90
- // Document data (saved with the tile map). audit-allow: literal-color
91
- backgroundColor: '#1a1a2e',
92
- };
65
+ const createEmptyTileMap = (name, width, height, tileWidth, tileHeight, mode = "2d") => {
66
+ const mapMode = mode === "tilemap" ? "2d" : mode;
67
+ return {
68
+ id: generateId("map"),
69
+ name,
70
+ mode: mapMode,
71
+ width,
72
+ height,
73
+ tileWidth,
74
+ tileHeight,
75
+ layers: [createEmptyTileLayer("Layer 1", width, height)],
76
+ properties: {},
77
+ // Document data (saved with the tile map). audit-allow: literal-color
78
+ backgroundColor: "#1a1a2e"
79
+ };
93
80
  };
94
- /* ────────────────────────────────────────────────────────────────
95
- SPRITE SHEET UTILITIES
96
- ──────────────────────────────────────────────────────────────── */
97
81
  const autoSliceSpriteSheet = (imageData, frameWidth, frameHeight, padding = 0) => {
98
- const frames = [];
99
- const cols = Math.floor((imageData.width + padding) / (frameWidth + padding));
100
- const rows = Math.floor((imageData.height + padding) / (frameHeight + padding));
101
- for (let row = 0; row < rows; row++) {
102
- for (let col = 0; col < cols; col++) {
103
- frames.push({
104
- id: generateId('frame'),
105
- name: `frame_${row}_${col}`,
106
- x: col * (frameWidth + padding),
107
- y: row * (frameHeight + padding),
108
- width: frameWidth,
109
- height: frameHeight,
110
- pivotX: 0.5,
111
- pivotY: 0.5,
112
- });
113
- }
82
+ const frames = [];
83
+ const cols = Math.floor((imageData.width + padding) / (frameWidth + padding));
84
+ const rows = Math.floor((imageData.height + padding) / (frameHeight + padding));
85
+ for (let row = 0; row < rows; row++) {
86
+ for (let col = 0; col < cols; col++) {
87
+ frames.push({
88
+ id: generateId("frame"),
89
+ name: `frame_${row}_${col}`,
90
+ x: col * (frameWidth + padding),
91
+ y: row * (frameHeight + padding),
92
+ width: frameWidth,
93
+ height: frameHeight,
94
+ pivotX: 0.5,
95
+ pivotY: 0.5
96
+ });
114
97
  }
115
- return frames;
98
+ }
99
+ return frames;
116
100
  };
117
101
  const detectFrames = (imageData) => {
118
- // Simple edge detection - find bounding boxes of non-transparent regions
119
- const frames = [];
120
- const visited = new Set();
121
- const { data, width, height } = imageData;
122
- const isTransparent = (x, y) => {
123
- if (x < 0 || y < 0 || x >= width || y >= height) {
124
- return true;
125
- }
126
- const idx = (y * width + x) * 4;
127
- return data[idx + 3] < 10; // alpha threshold
128
- };
129
- const floodFillBounds = (startX, startY) => {
130
- let minX = startX, maxX = startX, minY = startY, maxY = startY;
131
- const stack = [[startX, startY]];
132
- while (stack.length > 0) {
133
- const [x, y] = stack.pop();
134
- const key = `${x},${y}`;
135
- if (visited.has(key) || isTransparent(x, y)) {
136
- continue;
137
- }
138
- visited.add(key);
139
- minX = Math.min(minX, x);
140
- maxX = Math.max(maxX, x);
141
- minY = Math.min(minY, y);
142
- maxY = Math.max(maxY, y);
143
- stack.push([x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1]);
144
- }
145
- return { minX, maxX, minY, maxY };
146
- };
147
- for (let y = 0; y < height; y++) {
148
- for (let x = 0; x < width; x++) {
149
- const key = `${x},${y}`;
150
- if (!visited.has(key) && !isTransparent(x, y)) {
151
- const bounds = floodFillBounds(x, y);
152
- const frameWidth = bounds.maxX - bounds.minX + 1;
153
- const frameHeight = bounds.maxY - bounds.minY + 1;
154
- if (frameWidth > 1 && frameHeight > 1) {
155
- frames.push({
156
- id: generateId('frame'),
157
- name: `sprite_${frames.length}`,
158
- x: bounds.minX,
159
- y: bounds.minY,
160
- width: frameWidth,
161
- height: frameHeight,
162
- pivotX: 0.5,
163
- pivotY: 1.0, // bottom center for most sprites
164
- });
165
- }
166
- }
102
+ const frames = [];
103
+ const visited = /* @__PURE__ */ new Set();
104
+ const { data, width, height } = imageData;
105
+ const isTransparent = (x, y) => {
106
+ if (x < 0 || y < 0 || x >= width || y >= height) {
107
+ return true;
108
+ }
109
+ const idx = (y * width + x) * 4;
110
+ return data[idx + 3] < 10;
111
+ };
112
+ const floodFillBounds = (startX, startY) => {
113
+ let minX = startX, maxX = startX, minY = startY, maxY = startY;
114
+ const stack = [[startX, startY]];
115
+ while (stack.length > 0) {
116
+ const [x, y] = stack.pop();
117
+ const key = `${x},${y}`;
118
+ if (visited.has(key) || isTransparent(x, y)) {
119
+ continue;
120
+ }
121
+ visited.add(key);
122
+ minX = Math.min(minX, x);
123
+ maxX = Math.max(maxX, x);
124
+ minY = Math.min(minY, y);
125
+ maxY = Math.max(maxY, y);
126
+ stack.push([x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1]);
127
+ }
128
+ return { minX, maxX, minY, maxY };
129
+ };
130
+ for (let y = 0; y < height; y++) {
131
+ for (let x = 0; x < width; x++) {
132
+ const key = `${x},${y}`;
133
+ if (!visited.has(key) && !isTransparent(x, y)) {
134
+ const bounds = floodFillBounds(x, y);
135
+ const frameWidth = bounds.maxX - bounds.minX + 1;
136
+ const frameHeight = bounds.maxY - bounds.minY + 1;
137
+ if (frameWidth > 1 && frameHeight > 1) {
138
+ frames.push({
139
+ id: generateId("frame"),
140
+ name: `sprite_${frames.length}`,
141
+ x: bounds.minX,
142
+ y: bounds.minY,
143
+ width: frameWidth,
144
+ height: frameHeight,
145
+ pivotX: 0.5,
146
+ pivotY: 1
147
+ // bottom center for most sprites
148
+ });
167
149
  }
150
+ }
168
151
  }
169
- return frames;
152
+ }
153
+ return frames;
170
154
  };
171
155
  const createSpriteAnimation = (name, frameIds, frameDelay = 100) => {
172
- return {
173
- id: generateId('anim'),
174
- name,
175
- frameIds,
176
- frameDurations: frameIds.map(() => frameDelay),
177
- loop: true,
178
- pingPong: false,
179
- };
156
+ return {
157
+ id: generateId("anim"),
158
+ name,
159
+ frameIds,
160
+ frameDurations: frameIds.map(() => frameDelay),
161
+ loop: true,
162
+ pingPong: false
163
+ };
180
164
  };
181
- /* ────────────────────────────────────────────────────────────────
182
- EFFECTS PROCESSING
183
- ──────────────────────────────────────────────────────────────── */
184
165
  const applyEffect = (imageData, effect) => {
185
- const canvas = document.createElement('canvas');
186
- canvas.width = imageData.width;
187
- canvas.height = imageData.height;
188
- const ctx = canvas.getContext('2d');
189
- ctx.putImageData(imageData, 0, 0);
190
- const data = imageData.data.slice();
191
- const result = new ImageData(new Uint8ClampedArray(data), imageData.width, imageData.height);
192
- switch (effect.type) {
193
- case 'brightness': {
194
- const value = effect.params.value || 0;
195
- for (let i = 0; i < data.length; i += 4) {
196
- result.data[i] = Math.min(255, Math.max(0, data[i] + value));
197
- result.data[i + 1] = Math.min(255, Math.max(0, data[i + 1] + value));
198
- result.data[i + 2] = Math.min(255, Math.max(0, data[i + 2] + value));
199
- }
200
- break;
201
- }
202
- case 'contrast': {
203
- const factor = (259 * (effect.params.value + 255)) /
204
- (255 * (259 - effect.params.value));
205
- for (let i = 0; i < data.length; i += 4) {
206
- result.data[i] = Math.min(255, Math.max(0, factor * (data[i] - 128) + 128));
207
- result.data[i + 1] = Math.min(255, Math.max(0, factor * (data[i + 1] - 128) + 128));
208
- result.data[i + 2] = Math.min(255, Math.max(0, factor * (data[i + 2] - 128) + 128));
209
- }
210
- break;
211
- }
212
- case 'invert': {
213
- for (let i = 0; i < data.length; i += 4) {
214
- result.data[i] = 255 - data[i];
215
- result.data[i + 1] = 255 - data[i + 1];
216
- result.data[i + 2] = 255 - data[i + 2];
217
- }
218
- break;
219
- }
220
- case 'saturation': {
221
- const value = (effect.params.value + 100) / 100;
222
- for (let i = 0; i < data.length; i += 4) {
223
- const r = data[i], g = data[i + 1], b = data[i + 2];
224
- const gray = 0.2989 * r + 0.587 * g + 0.114 * b;
225
- result.data[i] = Math.min(255, Math.max(0, gray + (r - gray) * value));
226
- result.data[i + 1] = Math.min(255, Math.max(0, gray + (g - gray) * value));
227
- result.data[i + 2] = Math.min(255, Math.max(0, gray + (b - gray) * value));
228
- }
229
- break;
230
- }
231
- case 'hue-shift': {
232
- const degrees = effect.params.degrees || 0;
233
- const cos = Math.cos((degrees * Math.PI) / 180);
234
- const sin = Math.sin((degrees * Math.PI) / 180);
235
- for (let i = 0; i < data.length; i += 4) {
236
- const r = data[i], g = data[i + 1], b = data[i + 2];
237
- result.data[i] = Math.min(255, Math.max(0, (0.213 + cos * 0.787 - sin * 0.213) * r +
238
- (0.715 - cos * 0.715 - sin * 0.715) * g +
239
- (0.072 - cos * 0.072 + sin * 0.928) * b));
240
- result.data[i + 1] = Math.min(255, Math.max(0, (0.213 - cos * 0.213 + sin * 0.143) * r +
241
- (0.715 + cos * 0.285 + sin * 0.14) * g +
242
- (0.072 - cos * 0.072 - sin * 0.283) * b));
243
- result.data[i + 2] = Math.min(255, Math.max(0, (0.213 - cos * 0.213 - sin * 0.787) * r +
244
- (0.715 - cos * 0.715 + sin * 0.715) * g +
245
- (0.072 + cos * 0.928 + sin * 0.072) * b));
166
+ const canvas = document.createElement("canvas");
167
+ canvas.width = imageData.width;
168
+ canvas.height = imageData.height;
169
+ const ctx = canvas.getContext("2d");
170
+ ctx.putImageData(imageData, 0, 0);
171
+ const data = imageData.data.slice();
172
+ const result = new ImageData(new Uint8ClampedArray(data), imageData.width, imageData.height);
173
+ switch (effect.type) {
174
+ case "brightness": {
175
+ const value = effect.params.value || 0;
176
+ for (let i = 0; i < data.length; i += 4) {
177
+ result.data[i] = Math.min(255, Math.max(0, data[i] + value));
178
+ result.data[i + 1] = Math.min(255, Math.max(0, data[i + 1] + value));
179
+ result.data[i + 2] = Math.min(255, Math.max(0, data[i + 2] + value));
180
+ }
181
+ break;
182
+ }
183
+ case "contrast": {
184
+ const factor = 259 * (effect.params.value + 255) / (255 * (259 - effect.params.value));
185
+ for (let i = 0; i < data.length; i += 4) {
186
+ result.data[i] = Math.min(255, Math.max(0, factor * (data[i] - 128) + 128));
187
+ result.data[i + 1] = Math.min(255, Math.max(0, factor * (data[i + 1] - 128) + 128));
188
+ result.data[i + 2] = Math.min(255, Math.max(0, factor * (data[i + 2] - 128) + 128));
189
+ }
190
+ break;
191
+ }
192
+ case "invert": {
193
+ for (let i = 0; i < data.length; i += 4) {
194
+ result.data[i] = 255 - data[i];
195
+ result.data[i + 1] = 255 - data[i + 1];
196
+ result.data[i + 2] = 255 - data[i + 2];
197
+ }
198
+ break;
199
+ }
200
+ case "saturation": {
201
+ const value = (effect.params.value + 100) / 100;
202
+ for (let i = 0; i < data.length; i += 4) {
203
+ const r = data[i], g = data[i + 1], b = data[i + 2];
204
+ const gray = 0.2989 * r + 0.587 * g + 0.114 * b;
205
+ result.data[i] = Math.min(255, Math.max(0, gray + (r - gray) * value));
206
+ result.data[i + 1] = Math.min(255, Math.max(0, gray + (g - gray) * value));
207
+ result.data[i + 2] = Math.min(255, Math.max(0, gray + (b - gray) * value));
208
+ }
209
+ break;
210
+ }
211
+ case "hue-shift": {
212
+ const degrees = effect.params.degrees || 0;
213
+ const cos = Math.cos(degrees * Math.PI / 180);
214
+ const sin = Math.sin(degrees * Math.PI / 180);
215
+ for (let i = 0; i < data.length; i += 4) {
216
+ const r = data[i], g = data[i + 1], b = data[i + 2];
217
+ result.data[i] = Math.min(
218
+ 255,
219
+ Math.max(
220
+ 0,
221
+ (0.213 + cos * 0.787 - sin * 0.213) * r + (0.715 - cos * 0.715 - sin * 0.715) * g + (0.072 - cos * 0.072 + sin * 0.928) * b
222
+ )
223
+ );
224
+ result.data[i + 1] = Math.min(
225
+ 255,
226
+ Math.max(
227
+ 0,
228
+ (0.213 - cos * 0.213 + sin * 0.143) * r + (0.715 + cos * 0.285 + sin * 0.14) * g + (0.072 - cos * 0.072 - sin * 0.283) * b
229
+ )
230
+ );
231
+ result.data[i + 2] = Math.min(
232
+ 255,
233
+ Math.max(
234
+ 0,
235
+ (0.213 - cos * 0.213 - sin * 0.787) * r + (0.715 - cos * 0.715 + sin * 0.715) * g + (0.072 + cos * 0.928 + sin * 0.072) * b
236
+ )
237
+ );
238
+ }
239
+ break;
240
+ }
241
+ case "tint": {
242
+ const color = effect.params.color || "#ffffff";
243
+ const amount = effect.params.amount || 0.5;
244
+ const tr = parseInt(color.slice(1, 3), 16);
245
+ const tg = parseInt(color.slice(3, 5), 16);
246
+ const tb = parseInt(color.slice(5, 7), 16);
247
+ for (let i = 0; i < data.length; i += 4) {
248
+ result.data[i] = Math.round(data[i] * (1 - amount) + tr * amount);
249
+ result.data[i + 1] = Math.round(data[i + 1] * (1 - amount) + tg * amount);
250
+ result.data[i + 2] = Math.round(data[i + 2] * (1 - amount) + tb * amount);
251
+ }
252
+ break;
253
+ }
254
+ case "pixelate": {
255
+ const size = effect.params.size || 4;
256
+ const { width, height } = imageData;
257
+ for (let y = 0; y < height; y += size) {
258
+ for (let x = 0; x < width; x += size) {
259
+ let r = 0, g = 0, b = 0, a = 0, count = 0;
260
+ for (let dy = 0; dy < size && y + dy < height; dy++) {
261
+ for (let dx = 0; dx < size && x + dx < width; dx++) {
262
+ const idx = ((y + dy) * width + (x + dx)) * 4;
263
+ r += data[idx];
264
+ g += data[idx + 1];
265
+ b += data[idx + 2];
266
+ a += data[idx + 3];
267
+ count++;
246
268
  }
247
- break;
248
- }
249
- case 'tint': {
250
- // 6-digit hex: parsed below with slice(1, 3) etc. (a var() or #fff parsed as NaN).
251
- const color = effect.params.color || '#ffffff';
252
- const amount = effect.params.amount || 0.5;
253
- const tr = parseInt(color.slice(1, 3), 16);
254
- const tg = parseInt(color.slice(3, 5), 16);
255
- const tb = parseInt(color.slice(5, 7), 16);
256
- for (let i = 0; i < data.length; i += 4) {
257
- result.data[i] = Math.round(data[i] * (1 - amount) + tr * amount);
258
- result.data[i + 1] = Math.round(data[i + 1] * (1 - amount) + tg * amount);
259
- result.data[i + 2] = Math.round(data[i + 2] * (1 - amount) + tb * amount);
269
+ }
270
+ r = Math.round(r / count);
271
+ g = Math.round(g / count);
272
+ b = Math.round(b / count);
273
+ a = Math.round(a / count);
274
+ for (let dy = 0; dy < size && y + dy < height; dy++) {
275
+ for (let dx = 0; dx < size && x + dx < width; dx++) {
276
+ const idx = ((y + dy) * width + (x + dx)) * 4;
277
+ result.data[idx] = r;
278
+ result.data[idx + 1] = g;
279
+ result.data[idx + 2] = b;
280
+ result.data[idx + 3] = a;
260
281
  }
261
- break;
282
+ }
262
283
  }
263
- case 'pixelate': {
264
- const size = effect.params.size || 4;
265
- const { width, height } = imageData;
266
- for (let y = 0; y < height; y += size) {
267
- for (let x = 0; x < width; x += size) {
268
- let r = 0, g = 0, b = 0, a = 0, count = 0;
269
- for (let dy = 0; dy < size && y + dy < height; dy++) {
270
- for (let dx = 0; dx < size && x + dx < width; dx++) {
271
- const idx = ((y + dy) * width + (x + dx)) * 4;
272
- r += data[idx];
273
- g += data[idx + 1];
274
- b += data[idx + 2];
275
- a += data[idx + 3];
276
- count++;
277
- }
278
- }
279
- r = Math.round(r / count);
280
- g = Math.round(g / count);
281
- b = Math.round(b / count);
282
- a = Math.round(a / count);
283
- for (let dy = 0; dy < size && y + dy < height; dy++) {
284
- for (let dx = 0; dx < size && x + dx < width; dx++) {
285
- const idx = ((y + dy) * width + (x + dx)) * 4;
286
- result.data[idx] = r;
287
- result.data[idx + 1] = g;
288
- result.data[idx + 2] = b;
289
- result.data[idx + 3] = a;
290
- }
291
- }
284
+ }
285
+ break;
286
+ }
287
+ case "outline": {
288
+ const color = effect.params.color || "#000000";
289
+ const thickness = effect.params.thickness || 1;
290
+ const or = parseInt(color.slice(1, 3), 16);
291
+ const og = parseInt(color.slice(3, 5), 16);
292
+ const ob = parseInt(color.slice(5, 7), 16);
293
+ const { width, height } = imageData;
294
+ for (let y = 0; y < height; y++) {
295
+ for (let x = 0; x < width; x++) {
296
+ const idx = (y * width + x) * 4;
297
+ if (data[idx + 3] < 128) {
298
+ let hasOpaqueNeighbor = false;
299
+ for (let dy = -thickness; dy <= thickness && !hasOpaqueNeighbor; dy++) {
300
+ for (let dx = -thickness; dx <= thickness && !hasOpaqueNeighbor; dx++) {
301
+ if (dx === 0 && dy === 0) {
302
+ continue;
292
303
  }
293
- }
294
- break;
295
- }
296
- case 'outline': {
297
- const color = effect.params.color || '#000000';
298
- const thickness = effect.params.thickness || 1;
299
- const or = parseInt(color.slice(1, 3), 16);
300
- const og = parseInt(color.slice(3, 5), 16);
301
- const ob = parseInt(color.slice(5, 7), 16);
302
- const { width, height } = imageData;
303
- for (let y = 0; y < height; y++) {
304
- for (let x = 0; x < width; x++) {
305
- const idx = (y * width + x) * 4;
306
- if (data[idx + 3] < 128) {
307
- // Check neighbors for opaque pixels
308
- let hasOpaqueNeighbor = false;
309
- for (let dy = -thickness; dy <= thickness && !hasOpaqueNeighbor; dy++) {
310
- for (let dx = -thickness; dx <= thickness && !hasOpaqueNeighbor; dx++) {
311
- if (dx === 0 && dy === 0) {
312
- continue;
313
- }
314
- const nx = x + dx, ny = y + dy;
315
- if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
316
- const nidx = (ny * width + nx) * 4;
317
- if (data[nidx + 3] >= 128) {
318
- hasOpaqueNeighbor = true;
319
- }
320
- }
321
- }
322
- }
323
- if (hasOpaqueNeighbor) {
324
- result.data[idx] = or;
325
- result.data[idx + 1] = og;
326
- result.data[idx + 2] = ob;
327
- result.data[idx + 3] = 255;
328
- }
329
- }
304
+ const nx = x + dx, ny = y + dy;
305
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
306
+ const nidx = (ny * width + nx) * 4;
307
+ if (data[nidx + 3] >= 128) {
308
+ hasOpaqueNeighbor = true;
309
+ }
330
310
  }
311
+ }
312
+ }
313
+ if (hasOpaqueNeighbor) {
314
+ result.data[idx] = or;
315
+ result.data[idx + 1] = og;
316
+ result.data[idx + 2] = ob;
317
+ result.data[idx + 3] = 255;
331
318
  }
332
- break;
319
+ }
333
320
  }
334
- // Add more effects as needed
321
+ }
322
+ break;
335
323
  }
336
- return result;
324
+ }
325
+ return result;
337
326
  };
338
327
  const applyEffects = (imageData, effects) => {
339
- return effects
340
- .filter((e) => e.enabled)
341
- .reduce((img, effect) => applyEffect(img, effect), imageData);
328
+ return effects.filter((e) => e.enabled).reduce((img, effect) => applyEffect(img, effect), imageData);
342
329
  };
343
- /* ────────────────────────────────────────────────────────────────
344
- EXPORT UTILITIES
345
- ──────────────────────────────────────────────────────────────── */
346
330
  const exportToTiledJson = (tileMap, tileSets) => {
347
- const tilesetData = tileSets.map((tile, index) => ({
348
- firstgid: index + 1,
349
- columns: 1,
350
- image: tile.thumbnail,
351
- imageheight: tile.height,
352
- imagewidth: tile.width,
353
- margin: 0,
354
- name: tile.name,
355
- spacing: 0,
356
- tilecount: 1,
357
- tileheight: tile.height,
358
- tilewidth: tile.width,
359
- }));
360
- const layerData = tileMap.layers.map((layer) => {
361
- var _a;
362
- const data = [];
363
- for (let y = 0; y < tileMap.height; y++) {
364
- for (let x = 0; x < tileMap.width; x++) {
365
- const tileId = (_a = layer.tiles[y]) === null || _a === void 0 ? void 0 : _a[x];
366
- if (tileId) {
367
- const tileIndex = tileSets.findIndex((t) => t.id === tileId);
368
- data.push(tileIndex >= 0 ? tileIndex + 1 : 0);
369
- }
370
- else {
371
- data.push(0);
372
- }
373
- }
331
+ const tilesetData = tileSets.map((tile, index) => ({
332
+ firstgid: index + 1,
333
+ columns: 1,
334
+ image: tile.thumbnail,
335
+ imageheight: tile.height,
336
+ imagewidth: tile.width,
337
+ margin: 0,
338
+ name: tile.name,
339
+ spacing: 0,
340
+ tilecount: 1,
341
+ tileheight: tile.height,
342
+ tilewidth: tile.width
343
+ }));
344
+ const layerData = tileMap.layers.map((layer) => {
345
+ const data = [];
346
+ for (let y = 0; y < tileMap.height; y++) {
347
+ for (let x = 0; x < tileMap.width; x++) {
348
+ const tileId = layer.tiles[y]?.[x];
349
+ if (tileId) {
350
+ const tileIndex = tileSets.findIndex((t) => t.id === tileId);
351
+ data.push(tileIndex >= 0 ? tileIndex + 1 : 0);
352
+ } else {
353
+ data.push(0);
374
354
  }
375
- return {
376
- data,
377
- height: tileMap.height,
378
- id: 1,
379
- name: layer.name,
380
- opacity: layer.opacity,
381
- type: 'tilelayer',
382
- visible: layer.visible,
383
- width: tileMap.width,
384
- x: 0,
385
- y: 0,
386
- };
387
- });
355
+ }
356
+ }
388
357
  return {
389
- type: 'map',
390
- version: '1.10',
391
- tiledversion: '1.10.2',
392
- width: tileMap.width,
393
- height: tileMap.height,
394
- tilewidth: tileMap.tileWidth,
395
- tileheight: tileMap.tileHeight,
396
- layers: layerData,
397
- tilesets: tilesetData,
358
+ data,
359
+ height: tileMap.height,
360
+ id: 1,
361
+ name: layer.name,
362
+ opacity: layer.opacity,
363
+ type: "tilelayer",
364
+ visible: layer.visible,
365
+ width: tileMap.width,
366
+ x: 0,
367
+ y: 0
398
368
  };
369
+ });
370
+ return {
371
+ type: "map",
372
+ version: "1.10",
373
+ tiledversion: "1.10.2",
374
+ width: tileMap.width,
375
+ height: tileMap.height,
376
+ tilewidth: tileMap.tileWidth,
377
+ tileheight: tileMap.tileHeight,
378
+ layers: layerData,
379
+ tilesets: tilesetData
380
+ };
399
381
  };
400
382
  const downloadJson = (data, filename) => {
401
- const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
402
- const url = URL.createObjectURL(blob);
403
- const a = document.createElement('a');
404
- a.href = url;
405
- a.download = filename;
406
- a.click();
407
- URL.revokeObjectURL(url);
383
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
384
+ const url = URL.createObjectURL(blob);
385
+ const a = document.createElement("a");
386
+ a.href = url;
387
+ a.download = filename;
388
+ a.click();
389
+ URL.revokeObjectURL(url);
408
390
  };
409
391
  const downloadPng = (canvas, filename) => {
410
- const url = canvas.toDataURL('image/png');
411
- const a = document.createElement('a');
412
- a.href = url;
413
- a.download = filename;
414
- a.click();
392
+ const url = canvas.toDataURL("image/png");
393
+ const a = document.createElement("a");
394
+ a.href = url;
395
+ a.download = filename;
396
+ a.click();
415
397
  };
416
- /* ────────────────────────────────────────────────────────────────
417
- PROJECT UTILITIES
418
- ──────────────────────────────────────────────────────────────── */
419
398
  const createEmptyProject = (name) => ({
420
- id: generateId('project'),
421
- name,
422
- tileSets: [],
423
- tileMaps: [],
424
- spriteSheets: [],
425
- stateMachines: [],
426
- effectPresets: [],
427
- settings: { ...DEFAULT_PROJECT_SETTINGS },
399
+ id: generateId("project"),
400
+ name,
401
+ tileSets: [],
402
+ tileMaps: [],
403
+ spriteSheets: [],
404
+ stateMachines: [],
405
+ effectPresets: [],
406
+ settings: { ...DEFAULT_PROJECT_SETTINGS }
428
407
  });
429
408
  const serializeProject = (project) => {
430
- // Convert ImageData to base64 for serialization
431
- const serializable = {
432
- ...project,
433
- tileSets: project.tileSets.map((tile) => ({
434
- ...tile,
435
- image: null, // Skip ImageData, use thumbnail
436
- })),
437
- spriteSheets: project.spriteSheets.map((sheet) => ({
438
- ...sheet,
439
- image: null,
440
- imageData: null,
441
- })),
442
- };
443
- return JSON.stringify(serializable, null, 2);
409
+ const serializable = {
410
+ ...project,
411
+ tileSets: project.tileSets.map((tile) => ({
412
+ ...tile,
413
+ image: null
414
+ // Skip ImageData, use thumbnail
415
+ })),
416
+ spriteSheets: project.spriteSheets.map((sheet) => ({
417
+ ...sheet,
418
+ image: null,
419
+ imageData: null
420
+ }))
421
+ };
422
+ return JSON.stringify(serializable, null, 2);
444
423
  };
445
424
  const deserializeProject = async (json) => {
446
- const data = JSON.parse(json);
447
- // Restore ImageData from thumbnails
448
- for (const tile of data.tileSets) {
449
- if (tile.thumbnail) {
450
- tile.image = await dataUrlToImageData(tile.thumbnail);
451
- }
425
+ const data = JSON.parse(json);
426
+ for (const tile of data.tileSets) {
427
+ if (tile.thumbnail) {
428
+ tile.image = await dataUrlToImageData(tile.thumbnail);
452
429
  }
453
- for (const sheet of data.spriteSheets) {
454
- if (sheet.dataUrl) {
455
- sheet.image = await loadImage(sheet.dataUrl);
456
- sheet.imageData = await dataUrlToImageData(sheet.dataUrl);
457
- }
430
+ }
431
+ for (const sheet of data.spriteSheets) {
432
+ if (sheet.dataUrl) {
433
+ sheet.image = await loadImage(sheet.dataUrl);
434
+ sheet.imageData = await dataUrlToImageData(sheet.dataUrl);
458
435
  }
459
- return data;
436
+ }
437
+ return data;
438
+ };
439
+ export {
440
+ applyEffect,
441
+ applyEffects,
442
+ autoSliceSpriteSheet,
443
+ createEmptyProject,
444
+ createEmptyTileLayer,
445
+ createEmptyTileMap,
446
+ createSpriteAnimation,
447
+ createTileFromImage,
448
+ dataUrlToImageData,
449
+ deserializeProject,
450
+ detectFrames,
451
+ downloadJson,
452
+ downloadPng,
453
+ exportToTiledJson,
454
+ generateId,
455
+ imageDataToDataUrl,
456
+ loadImage,
457
+ serializeProject
460
458
  };
461
-
462
- export { applyEffect, applyEffects, autoSliceSpriteSheet, createEmptyProject, createEmptyTileLayer, createEmptyTileMap, createSpriteAnimation, createTileFromImage, dataUrlToImageData, deserializeProject, detectFrames, downloadJson, downloadPng, exportToTiledJson, generateId, imageDataToDataUrl, loadImage, serializeProject };