@nice2dev/ui-graphics 1.1.0 → 1.1.1

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 (391) hide show
  1. package/dist/cjs/animation/AnimatedPerson.js +69 -63
  2. package/dist/cjs/animation/AnimatedPerson.js.map +1 -1
  3. package/dist/cjs/animation/AnimationEditor.js +27 -20
  4. package/dist/cjs/animation/AnimationEditor.js.map +1 -1
  5. package/dist/cjs/animation/Audience.js +17 -11
  6. package/dist/cjs/animation/Audience.js.map +1 -1
  7. package/dist/cjs/animation/BodyRenderer.js +7 -7
  8. package/dist/cjs/animation/BodyRenderer.js.map +1 -1
  9. package/dist/cjs/animation/animationHelper.js +83 -52
  10. package/dist/cjs/animation/animationHelper.js.map +1 -1
  11. package/dist/cjs/animation/characterTypes.js +171 -30
  12. package/dist/cjs/animation/characterTypes.js.map +1 -1
  13. package/dist/cjs/animation/choreoDSL.js +114 -62
  14. package/dist/cjs/animation/choreoDSL.js.map +1 -1
  15. package/dist/cjs/animation/karaokeIntegration.js +10 -11
  16. package/dist/cjs/animation/karaokeIntegration.js.map +1 -1
  17. package/dist/cjs/animation/lottieExport.js +15 -9
  18. package/dist/cjs/animation/lottieExport.js.map +1 -1
  19. package/dist/cjs/animation/motionPath.js +125 -30
  20. package/dist/cjs/animation/motionPath.js.map +1 -1
  21. package/dist/cjs/animation/physics.js +157 -57
  22. package/dist/cjs/animation/physics.js.map +1 -1
  23. package/dist/cjs/animation/rig/RigPlayer.js +7 -6
  24. package/dist/cjs/animation/rig/RigPlayer.js.map +1 -1
  25. package/dist/cjs/animation/rig/RiggedBody.js +7 -7
  26. package/dist/cjs/animation/rig/RiggedBody.js.map +1 -1
  27. package/dist/cjs/animation/rig/choreoRigBridge.js +52 -29
  28. package/dist/cjs/animation/rig/choreoRigBridge.js.map +1 -1
  29. package/dist/cjs/animation/rig/poseOps.js +6 -3
  30. package/dist/cjs/animation/rig/poseOps.js.map +1 -1
  31. package/dist/cjs/animation/shapes/arms.js +7 -6
  32. package/dist/cjs/animation/shapes/arms.js.map +1 -1
  33. package/dist/cjs/animation/shapes/eyes.js +31 -18
  34. package/dist/cjs/animation/shapes/eyes.js.map +1 -1
  35. package/dist/cjs/animation/shapes/hair.js +39 -23
  36. package/dist/cjs/animation/shapes/hair.js.map +1 -1
  37. package/dist/cjs/animation/shapes/heads.js +47 -29
  38. package/dist/cjs/animation/shapes/heads.js.map +1 -1
  39. package/dist/cjs/animation/shapes/headwear.js +26 -14
  40. package/dist/cjs/animation/shapes/headwear.js.map +1 -1
  41. package/dist/cjs/animation/shapes/legs.js +7 -6
  42. package/dist/cjs/animation/shapes/legs.js.map +1 -1
  43. package/dist/cjs/animation/shapes/mouths.js +28 -18
  44. package/dist/cjs/animation/shapes/mouths.js.map +1 -1
  45. package/dist/cjs/animation/shapes/noses.js +18 -9
  46. package/dist/cjs/animation/shapes/noses.js.map +1 -1
  47. package/dist/cjs/animation/shapes/outfits.js +25 -14
  48. package/dist/cjs/animation/shapes/outfits.js.map +1 -1
  49. package/dist/cjs/animation/shapes/torsos.js +5 -4
  50. package/dist/cjs/animation/shapes/torsos.js.map +1 -1
  51. package/dist/cjs/animation/spineExport.js +33 -26
  52. package/dist/cjs/animation/spineExport.js.map +1 -1
  53. package/dist/cjs/core/LocalUI.js +16 -16
  54. package/dist/cjs/core/LocalUI.js.map +1 -1
  55. package/dist/cjs/core/NiceBrushEngine.js +205 -69
  56. package/dist/cjs/core/NiceBrushEngine.js.map +1 -1
  57. package/dist/cjs/core/collaboration.js +35 -21
  58. package/dist/cjs/core/collaboration.js.map +1 -1
  59. package/dist/cjs/core/colorBlindness.js +64 -24
  60. package/dist/cjs/core/colorBlindness.js.map +1 -1
  61. package/dist/cjs/core/dragDrop.js +34 -26
  62. package/dist/cjs/core/dragDrop.js.map +1 -1
  63. package/dist/cjs/core/fixes.js +26 -14
  64. package/dist/cjs/core/fixes.js.map +1 -1
  65. package/dist/cjs/core/gridGuides.js +24 -16
  66. package/dist/cjs/core/gridGuides.js.map +1 -1
  67. package/dist/cjs/core/historyVisual.js +42 -23
  68. package/dist/cjs/core/historyVisual.js.map +1 -1
  69. package/dist/cjs/core/integrations.js +65 -48
  70. package/dist/cjs/core/integrations.js.map +1 -1
  71. package/dist/cjs/core/minimap.js +40 -24
  72. package/dist/cjs/core/minimap.js.map +1 -1
  73. package/dist/cjs/core/plugins.js +10 -6
  74. package/dist/cjs/core/plugins.js.map +1 -1
  75. package/dist/cjs/core/rtl.js +32 -27
  76. package/dist/cjs/core/rtl.js.map +1 -1
  77. package/dist/cjs/core/shortcuts.js +77 -39
  78. package/dist/cjs/core/shortcuts.js.map +1 -1
  79. package/dist/cjs/core/theme.js +68 -61
  80. package/dist/cjs/core/theme.js.map +1 -1
  81. package/dist/cjs/core/yjsCollaboration.js +61 -28
  82. package/dist/cjs/core/yjsCollaboration.js.map +1 -1
  83. package/dist/cjs/font/NiceFontEditor.js +160 -57
  84. package/dist/cjs/font/NiceFontEditor.js.map +1 -1
  85. package/dist/cjs/font/fontFormatUtils.js +37 -24
  86. package/dist/cjs/font/fontFormatUtils.js.map +1 -1
  87. package/dist/cjs/game/GameAsset2dEditor.js +73 -60
  88. package/dist/cjs/game/GameAsset2dEditor.js.map +1 -1
  89. package/dist/cjs/game/gameAssetUtils.js +18 -13
  90. package/dist/cjs/game/gameAssetUtils.js.map +1 -1
  91. package/dist/cjs/game/useGameAssetEditor.js +160 -143
  92. package/dist/cjs/game/useGameAssetEditor.js.map +1 -1
  93. package/dist/cjs/icon/NiceIconEditor.js +329 -106
  94. package/dist/cjs/icon/NiceIconEditor.js.map +1 -1
  95. package/dist/cjs/packages/ui/dist/NiceErrorBoundary-D75yr_WE.js +572 -0
  96. package/dist/cjs/packages/ui/dist/NiceErrorBoundary-D75yr_WE.js.map +1 -0
  97. package/dist/cjs/packages/ui/dist/NiceForm-CKoJA6NG.js +4979 -0
  98. package/dist/cjs/packages/ui/dist/NiceForm-CKoJA6NG.js.map +1 -0
  99. package/dist/cjs/packages/ui/dist/NiceModal-1QX7NhyH.js +98 -0
  100. package/dist/cjs/packages/ui/dist/NiceModal-1QX7NhyH.js.map +1 -0
  101. package/dist/cjs/packages/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js +5244 -0
  102. package/dist/cjs/packages/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js.map +1 -0
  103. package/dist/cjs/packages/ui/dist/NicePagination-DbE-uOkl.js +174 -0
  104. package/dist/cjs/packages/ui/dist/NicePagination-DbE-uOkl.js.map +1 -0
  105. package/dist/cjs/packages/ui/dist/NicePinCodeInput-B8cI8zu8.js +10459 -0
  106. package/dist/cjs/packages/ui/dist/NicePinCodeInput-B8cI8zu8.js.map +1 -0
  107. package/dist/cjs/packages/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js +6313 -0
  108. package/dist/cjs/packages/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js.map +1 -0
  109. package/dist/cjs/packages/ui/dist/NiceTabs-DzLHzwuA.js +1639 -0
  110. package/dist/cjs/packages/ui/dist/NiceTabs-DzLHzwuA.js.map +1 -0
  111. package/dist/cjs/packages/ui/dist/NiceWindow-DeC83yfE.js +807 -0
  112. package/dist/cjs/packages/ui/dist/NiceWindow-DeC83yfE.js.map +1 -0
  113. package/dist/cjs/packages/ui/dist/charts-BAS21jkC.js +3833 -0
  114. package/dist/cjs/packages/ui/dist/charts-BAS21jkC.js.map +1 -0
  115. package/dist/cjs/packages/ui/dist/core-Da43q-pO.js +11683 -0
  116. package/dist/cjs/packages/ui/dist/core-Da43q-pO.js.map +1 -0
  117. package/dist/cjs/packages/ui/dist/index-pAuGTbuB.js +28876 -0
  118. package/dist/cjs/packages/ui/dist/index-pAuGTbuB.js.map +1 -0
  119. package/dist/cjs/photo/FilterThumb.js +7 -5
  120. package/dist/cjs/photo/FilterThumb.js.map +1 -1
  121. package/dist/cjs/photo/NiceAITools.js +78 -32
  122. package/dist/cjs/photo/NiceAITools.js.map +1 -1
  123. package/dist/cjs/photo/PhotoEditor.js +4 -4
  124. package/dist/cjs/photo/PhotoEditor.js.map +1 -1
  125. package/dist/cjs/photo/PhotoEditorCanvas.js +56 -22
  126. package/dist/cjs/photo/PhotoEditorCanvas.js.map +1 -1
  127. package/dist/cjs/photo/PhotoEditorLeftPanel.js +106 -48
  128. package/dist/cjs/photo/PhotoEditorLeftPanel.js.map +1 -1
  129. package/dist/cjs/photo/PhotoEditorToolbar.js +2 -2
  130. package/dist/cjs/photo/PhotoEditorToolbar.js.map +1 -1
  131. package/dist/cjs/photo/photoEditorActions.js +27 -18
  132. package/dist/cjs/photo/photoEditorActions.js.map +1 -1
  133. package/dist/cjs/photo/photoFilters.js +316 -81
  134. package/dist/cjs/photo/photoFilters.js.map +1 -1
  135. package/dist/cjs/photo/photoOverlays.js +521 -165
  136. package/dist/cjs/photo/photoOverlays.js.map +1 -1
  137. package/dist/cjs/photo/photoSelection.js +69 -35
  138. package/dist/cjs/photo/photoSelection.js.map +1 -1
  139. package/dist/cjs/photo/usePhotoEditor.js +203 -97
  140. package/dist/cjs/photo/usePhotoEditor.js.map +1 -1
  141. package/dist/cjs/pixel/HSVPicker.js +32 -19
  142. package/dist/cjs/pixel/HSVPicker.js.map +1 -1
  143. package/dist/cjs/pixel/PixelEditor.js +25 -14
  144. package/dist/cjs/pixel/PixelEditor.js.map +1 -1
  145. package/dist/cjs/pixel/PixelEditorCanvas.js +2 -2
  146. package/dist/cjs/pixel/PixelEditorCanvas.js.map +1 -1
  147. package/dist/cjs/pixel/PixelEditorMenuBar.js +3 -3
  148. package/dist/cjs/pixel/PixelEditorMenuBar.js.map +1 -1
  149. package/dist/cjs/pixel/PixelEditorRightPanel.js +28 -8
  150. package/dist/cjs/pixel/PixelEditorRightPanel.js.map +1 -1
  151. package/dist/cjs/pixel/PixelEditorStatusBar.js +2 -2
  152. package/dist/cjs/pixel/PixelEditorStatusBar.js.map +1 -1
  153. package/dist/cjs/pixel/PixelEditorTimeline.js +3 -4
  154. package/dist/cjs/pixel/PixelEditorTimeline.js.map +1 -1
  155. package/dist/cjs/pixel/PixelEditorToolbar.js +3 -3
  156. package/dist/cjs/pixel/PixelEditorToolbar.js.map +1 -1
  157. package/dist/cjs/pixel/SpriteGeneratorPanel.js +136 -54
  158. package/dist/cjs/pixel/SpriteGeneratorPanel.js.map +1 -1
  159. package/dist/cjs/pixel/asepriteFormat.js +122 -38
  160. package/dist/cjs/pixel/asepriteFormat.js.map +1 -1
  161. package/dist/cjs/pixel/characterGeneratorPresets.js +208 -54
  162. package/dist/cjs/pixel/characterGeneratorPresets.js.map +1 -1
  163. package/dist/cjs/pixel/pixelEditorExports.js +42 -35
  164. package/dist/cjs/pixel/pixelEditorExports.js.map +1 -1
  165. package/dist/cjs/pixel/pixelEditorTypes.js +67 -33
  166. package/dist/cjs/pixel/pixelEditorTypes.js.map +1 -1
  167. package/dist/cjs/pixel/pixelEditorUtils.js +62 -38
  168. package/dist/cjs/pixel/pixelEditorUtils.js.map +1 -1
  169. package/dist/cjs/pixel/spriteGeneratorCore.js +47 -24
  170. package/dist/cjs/pixel/spriteGeneratorCore.js.map +1 -1
  171. package/dist/cjs/pixel/usePixelEditor.js +475 -213
  172. package/dist/cjs/pixel/usePixelEditor.js.map +1 -1
  173. package/dist/cjs/texture/Nice3DTexturePainter.js +201 -71
  174. package/dist/cjs/texture/Nice3DTexturePainter.js.map +1 -1
  175. package/dist/cjs/ui/NiceUIDesigner.js +280 -91
  176. package/dist/cjs/ui/NiceUIDesigner.js.map +1 -1
  177. package/dist/cjs/vector/NiceSvgToCode.js +96 -34
  178. package/dist/cjs/vector/NiceSvgToCode.js.map +1 -1
  179. package/dist/cjs/vector/VectorEditor.js +14 -13
  180. package/dist/cjs/vector/VectorEditor.js.map +1 -1
  181. package/dist/cjs/vector/VectorEditorMenuBar.js +7 -6
  182. package/dist/cjs/vector/VectorEditorMenuBar.js.map +1 -1
  183. package/dist/cjs/vector/VectorEditorRightPanel.js +87 -32
  184. package/dist/cjs/vector/VectorEditorRightPanel.js.map +1 -1
  185. package/dist/cjs/vector/VectorEditorShapeRenderer.js +17 -15
  186. package/dist/cjs/vector/VectorEditorShapeRenderer.js.map +1 -1
  187. package/dist/cjs/vector/VectorEditorStatusBar.js.map +1 -1
  188. package/dist/cjs/vector/useVectorEditor.js +312 -122
  189. package/dist/cjs/vector/useVectorEditor.js.map +1 -1
  190. package/dist/cjs/vector/vectorBooleanOps.js +60 -42
  191. package/dist/cjs/vector/vectorBooleanOps.js.map +1 -1
  192. package/dist/cjs/vector/vectorEditorExport.js +40 -34
  193. package/dist/cjs/vector/vectorEditorExport.js.map +1 -1
  194. package/dist/cjs/vector/vectorGradients.js +41 -40
  195. package/dist/cjs/vector/vectorGradients.js.map +1 -1
  196. package/dist/esm/animation/AnimatedPerson.js +69 -63
  197. package/dist/esm/animation/AnimatedPerson.js.map +1 -1
  198. package/dist/esm/animation/AnimationEditor.js +27 -20
  199. package/dist/esm/animation/AnimationEditor.js.map +1 -1
  200. package/dist/esm/animation/Audience.js +17 -11
  201. package/dist/esm/animation/Audience.js.map +1 -1
  202. package/dist/esm/animation/BodyRenderer.js +7 -7
  203. package/dist/esm/animation/BodyRenderer.js.map +1 -1
  204. package/dist/esm/animation/animationHelper.js +83 -52
  205. package/dist/esm/animation/animationHelper.js.map +1 -1
  206. package/dist/esm/animation/characterTypes.js +171 -30
  207. package/dist/esm/animation/characterTypes.js.map +1 -1
  208. package/dist/esm/animation/choreoDSL.js +114 -62
  209. package/dist/esm/animation/choreoDSL.js.map +1 -1
  210. package/dist/esm/animation/karaokeIntegration.js +10 -11
  211. package/dist/esm/animation/karaokeIntegration.js.map +1 -1
  212. package/dist/esm/animation/lottieExport.js +15 -9
  213. package/dist/esm/animation/lottieExport.js.map +1 -1
  214. package/dist/esm/animation/motionPath.js +125 -30
  215. package/dist/esm/animation/motionPath.js.map +1 -1
  216. package/dist/esm/animation/physics.js +157 -57
  217. package/dist/esm/animation/physics.js.map +1 -1
  218. package/dist/esm/animation/rig/RigPlayer.js +7 -6
  219. package/dist/esm/animation/rig/RigPlayer.js.map +1 -1
  220. package/dist/esm/animation/rig/RiggedBody.js +7 -7
  221. package/dist/esm/animation/rig/RiggedBody.js.map +1 -1
  222. package/dist/esm/animation/rig/choreoRigBridge.js +52 -29
  223. package/dist/esm/animation/rig/choreoRigBridge.js.map +1 -1
  224. package/dist/esm/animation/rig/poseOps.js +6 -3
  225. package/dist/esm/animation/rig/poseOps.js.map +1 -1
  226. package/dist/esm/animation/shapes/arms.js +7 -6
  227. package/dist/esm/animation/shapes/arms.js.map +1 -1
  228. package/dist/esm/animation/shapes/eyes.js +31 -18
  229. package/dist/esm/animation/shapes/eyes.js.map +1 -1
  230. package/dist/esm/animation/shapes/hair.js +39 -23
  231. package/dist/esm/animation/shapes/hair.js.map +1 -1
  232. package/dist/esm/animation/shapes/heads.js +47 -29
  233. package/dist/esm/animation/shapes/heads.js.map +1 -1
  234. package/dist/esm/animation/shapes/headwear.js +26 -14
  235. package/dist/esm/animation/shapes/headwear.js.map +1 -1
  236. package/dist/esm/animation/shapes/legs.js +7 -6
  237. package/dist/esm/animation/shapes/legs.js.map +1 -1
  238. package/dist/esm/animation/shapes/mouths.js +28 -18
  239. package/dist/esm/animation/shapes/mouths.js.map +1 -1
  240. package/dist/esm/animation/shapes/noses.js +18 -9
  241. package/dist/esm/animation/shapes/noses.js.map +1 -1
  242. package/dist/esm/animation/shapes/outfits.js +25 -14
  243. package/dist/esm/animation/shapes/outfits.js.map +1 -1
  244. package/dist/esm/animation/shapes/torsos.js +5 -4
  245. package/dist/esm/animation/shapes/torsos.js.map +1 -1
  246. package/dist/esm/animation/spineExport.js +33 -26
  247. package/dist/esm/animation/spineExport.js.map +1 -1
  248. package/dist/esm/core/LocalUI.js +16 -16
  249. package/dist/esm/core/LocalUI.js.map +1 -1
  250. package/dist/esm/core/NiceBrushEngine.js +205 -69
  251. package/dist/esm/core/NiceBrushEngine.js.map +1 -1
  252. package/dist/esm/core/collaboration.js +35 -21
  253. package/dist/esm/core/collaboration.js.map +1 -1
  254. package/dist/esm/core/colorBlindness.js +64 -24
  255. package/dist/esm/core/colorBlindness.js.map +1 -1
  256. package/dist/esm/core/dragDrop.js +34 -26
  257. package/dist/esm/core/dragDrop.js.map +1 -1
  258. package/dist/esm/core/fixes.js +26 -14
  259. package/dist/esm/core/fixes.js.map +1 -1
  260. package/dist/esm/core/gridGuides.js +24 -16
  261. package/dist/esm/core/gridGuides.js.map +1 -1
  262. package/dist/esm/core/historyVisual.js +42 -23
  263. package/dist/esm/core/historyVisual.js.map +1 -1
  264. package/dist/esm/core/integrations.js +65 -48
  265. package/dist/esm/core/integrations.js.map +1 -1
  266. package/dist/esm/core/minimap.js +40 -24
  267. package/dist/esm/core/minimap.js.map +1 -1
  268. package/dist/esm/core/plugins.js +10 -6
  269. package/dist/esm/core/plugins.js.map +1 -1
  270. package/dist/esm/core/rtl.js +32 -27
  271. package/dist/esm/core/rtl.js.map +1 -1
  272. package/dist/esm/core/shortcuts.js +77 -39
  273. package/dist/esm/core/shortcuts.js.map +1 -1
  274. package/dist/esm/core/theme.js +68 -61
  275. package/dist/esm/core/theme.js.map +1 -1
  276. package/dist/esm/core/yjsCollaboration.js +61 -28
  277. package/dist/esm/core/yjsCollaboration.js.map +1 -1
  278. package/dist/esm/font/NiceFontEditor.js +160 -57
  279. package/dist/esm/font/NiceFontEditor.js.map +1 -1
  280. package/dist/esm/font/fontFormatUtils.js +37 -24
  281. package/dist/esm/font/fontFormatUtils.js.map +1 -1
  282. package/dist/esm/game/GameAsset2dEditor.js +73 -60
  283. package/dist/esm/game/GameAsset2dEditor.js.map +1 -1
  284. package/dist/esm/game/gameAssetUtils.js +18 -13
  285. package/dist/esm/game/gameAssetUtils.js.map +1 -1
  286. package/dist/esm/game/useGameAssetEditor.js +160 -143
  287. package/dist/esm/game/useGameAssetEditor.js.map +1 -1
  288. package/dist/esm/icon/NiceIconEditor.js +329 -106
  289. package/dist/esm/icon/NiceIconEditor.js.map +1 -1
  290. package/dist/esm/packages/ui/dist/NiceErrorBoundary-D75yr_WE.js +563 -0
  291. package/dist/esm/packages/ui/dist/NiceErrorBoundary-D75yr_WE.js.map +1 -0
  292. package/dist/esm/packages/ui/dist/NiceForm-CKoJA6NG.js +4960 -0
  293. package/dist/esm/packages/ui/dist/NiceForm-CKoJA6NG.js.map +1 -0
  294. package/dist/esm/packages/ui/dist/NiceModal-1QX7NhyH.js +96 -0
  295. package/dist/esm/packages/ui/dist/NiceModal-1QX7NhyH.js.map +1 -0
  296. package/dist/esm/packages/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js +5201 -0
  297. package/dist/esm/packages/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js.map +1 -0
  298. package/dist/esm/packages/ui/dist/NicePagination-DbE-uOkl.js +172 -0
  299. package/dist/esm/packages/ui/dist/NicePagination-DbE-uOkl.js.map +1 -0
  300. package/dist/esm/packages/ui/dist/NicePinCodeInput-B8cI8zu8.js +10408 -0
  301. package/dist/esm/packages/ui/dist/NicePinCodeInput-B8cI8zu8.js.map +1 -0
  302. package/dist/esm/packages/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js +6296 -0
  303. package/dist/esm/packages/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js.map +1 -0
  304. package/dist/esm/packages/ui/dist/NiceTabs-DzLHzwuA.js +1630 -0
  305. package/dist/esm/packages/ui/dist/NiceTabs-DzLHzwuA.js.map +1 -0
  306. package/dist/esm/packages/ui/dist/NiceWindow-DeC83yfE.js +796 -0
  307. package/dist/esm/packages/ui/dist/NiceWindow-DeC83yfE.js.map +1 -0
  308. package/dist/esm/packages/ui/dist/charts-BAS21jkC.js +3809 -0
  309. package/dist/esm/packages/ui/dist/charts-BAS21jkC.js.map +1 -0
  310. package/dist/esm/packages/ui/dist/core-Da43q-pO.js +11502 -0
  311. package/dist/esm/packages/ui/dist/core-Da43q-pO.js.map +1 -0
  312. package/dist/esm/packages/ui/dist/index-pAuGTbuB.js +28792 -0
  313. package/dist/esm/packages/ui/dist/index-pAuGTbuB.js.map +1 -0
  314. package/dist/esm/photo/FilterThumb.js +7 -5
  315. package/dist/esm/photo/FilterThumb.js.map +1 -1
  316. package/dist/esm/photo/NiceAITools.js +78 -32
  317. package/dist/esm/photo/NiceAITools.js.map +1 -1
  318. package/dist/esm/photo/PhotoEditor.js +4 -4
  319. package/dist/esm/photo/PhotoEditor.js.map +1 -1
  320. package/dist/esm/photo/PhotoEditorCanvas.js +56 -22
  321. package/dist/esm/photo/PhotoEditorCanvas.js.map +1 -1
  322. package/dist/esm/photo/PhotoEditorLeftPanel.js +106 -48
  323. package/dist/esm/photo/PhotoEditorLeftPanel.js.map +1 -1
  324. package/dist/esm/photo/PhotoEditorToolbar.js +2 -2
  325. package/dist/esm/photo/PhotoEditorToolbar.js.map +1 -1
  326. package/dist/esm/photo/photoEditorActions.js +27 -18
  327. package/dist/esm/photo/photoEditorActions.js.map +1 -1
  328. package/dist/esm/photo/photoFilters.js +316 -81
  329. package/dist/esm/photo/photoFilters.js.map +1 -1
  330. package/dist/esm/photo/photoOverlays.js +521 -165
  331. package/dist/esm/photo/photoOverlays.js.map +1 -1
  332. package/dist/esm/photo/photoSelection.js +69 -35
  333. package/dist/esm/photo/photoSelection.js.map +1 -1
  334. package/dist/esm/photo/usePhotoEditor.js +203 -97
  335. package/dist/esm/photo/usePhotoEditor.js.map +1 -1
  336. package/dist/esm/pixel/HSVPicker.js +32 -19
  337. package/dist/esm/pixel/HSVPicker.js.map +1 -1
  338. package/dist/esm/pixel/PixelEditor.js +25 -14
  339. package/dist/esm/pixel/PixelEditor.js.map +1 -1
  340. package/dist/esm/pixel/PixelEditorCanvas.js +2 -2
  341. package/dist/esm/pixel/PixelEditorCanvas.js.map +1 -1
  342. package/dist/esm/pixel/PixelEditorMenuBar.js +3 -3
  343. package/dist/esm/pixel/PixelEditorMenuBar.js.map +1 -1
  344. package/dist/esm/pixel/PixelEditorRightPanel.js +28 -8
  345. package/dist/esm/pixel/PixelEditorRightPanel.js.map +1 -1
  346. package/dist/esm/pixel/PixelEditorStatusBar.js +2 -2
  347. package/dist/esm/pixel/PixelEditorStatusBar.js.map +1 -1
  348. package/dist/esm/pixel/PixelEditorTimeline.js +3 -4
  349. package/dist/esm/pixel/PixelEditorTimeline.js.map +1 -1
  350. package/dist/esm/pixel/PixelEditorToolbar.js +3 -3
  351. package/dist/esm/pixel/PixelEditorToolbar.js.map +1 -1
  352. package/dist/esm/pixel/SpriteGeneratorPanel.js +136 -54
  353. package/dist/esm/pixel/SpriteGeneratorPanel.js.map +1 -1
  354. package/dist/esm/pixel/asepriteFormat.js +122 -38
  355. package/dist/esm/pixel/asepriteFormat.js.map +1 -1
  356. package/dist/esm/pixel/characterGeneratorPresets.js +208 -54
  357. package/dist/esm/pixel/characterGeneratorPresets.js.map +1 -1
  358. package/dist/esm/pixel/pixelEditorExports.js +42 -35
  359. package/dist/esm/pixel/pixelEditorExports.js.map +1 -1
  360. package/dist/esm/pixel/pixelEditorTypes.js +67 -33
  361. package/dist/esm/pixel/pixelEditorTypes.js.map +1 -1
  362. package/dist/esm/pixel/pixelEditorUtils.js +62 -38
  363. package/dist/esm/pixel/pixelEditorUtils.js.map +1 -1
  364. package/dist/esm/pixel/spriteGeneratorCore.js +47 -24
  365. package/dist/esm/pixel/spriteGeneratorCore.js.map +1 -1
  366. package/dist/esm/pixel/usePixelEditor.js +475 -213
  367. package/dist/esm/pixel/usePixelEditor.js.map +1 -1
  368. package/dist/esm/texture/Nice3DTexturePainter.js +201 -71
  369. package/dist/esm/texture/Nice3DTexturePainter.js.map +1 -1
  370. package/dist/esm/ui/NiceUIDesigner.js +280 -91
  371. package/dist/esm/ui/NiceUIDesigner.js.map +1 -1
  372. package/dist/esm/vector/NiceSvgToCode.js +96 -34
  373. package/dist/esm/vector/NiceSvgToCode.js.map +1 -1
  374. package/dist/esm/vector/VectorEditor.js +14 -13
  375. package/dist/esm/vector/VectorEditor.js.map +1 -1
  376. package/dist/esm/vector/VectorEditorMenuBar.js +7 -6
  377. package/dist/esm/vector/VectorEditorMenuBar.js.map +1 -1
  378. package/dist/esm/vector/VectorEditorRightPanel.js +87 -32
  379. package/dist/esm/vector/VectorEditorRightPanel.js.map +1 -1
  380. package/dist/esm/vector/VectorEditorShapeRenderer.js +17 -15
  381. package/dist/esm/vector/VectorEditorShapeRenderer.js.map +1 -1
  382. package/dist/esm/vector/VectorEditorStatusBar.js.map +1 -1
  383. package/dist/esm/vector/useVectorEditor.js +312 -122
  384. package/dist/esm/vector/useVectorEditor.js.map +1 -1
  385. package/dist/esm/vector/vectorBooleanOps.js +60 -42
  386. package/dist/esm/vector/vectorBooleanOps.js.map +1 -1
  387. package/dist/esm/vector/vectorEditorExport.js +40 -34
  388. package/dist/esm/vector/vectorEditorExport.js.map +1 -1
  389. package/dist/esm/vector/vectorGradients.js +41 -40
  390. package/dist/esm/vector/vectorGradients.js.map +1 -1
  391. package/package.json +2 -2
@@ -1,8 +1,8 @@
1
1
  import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
2
2
  import { aseColorToHex, parseAseFile } from './asepriteFormat.js';
3
- import { DEFAULT_BRUSH, createBlankImageData, cloneImageData, bresenhamLine, setPixel, drawGradient, applyDitherStamp, applyBrushStamp, getPixel, rgbaToHex, getSymmetryPoints, floodFill, copySelection, clearSelection, pasteAt, flipH, flipV, rotateCW } from './pixelEditorUtils.js';
4
- import { lid, DEFAULT_PALETTE, celKey, hex2t, inB, plotEllipse } from './pixelEditorTypes.js';
5
3
  import { exportAse, exportPNG, exportJPG, exportWebP, exportBMP, exportSVG, exportSheet } from './pixelEditorExports.js';
4
+ import { lid, DEFAULT_PALETTE, celKey, hex2t, inB, plotEllipse } from './pixelEditorTypes.js';
5
+ import { DEFAULT_BRUSH, createBlankImageData, cloneImageData, bresenhamLine, setPixel, drawGradient, applyDitherStamp, applyBrushStamp, getPixel, rgbaToHex, getSymmetryPoints, floodFill, copySelection, clearSelection, pasteAt, flipH, flipV, rotateCW } from './pixelEditorUtils.js';
6
6
 
7
7
  /**
8
8
  * usePixelEditor — custom hook encapsulating ALL state, refs, callbacks,
@@ -17,15 +17,22 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
17
17
  const [dw, setDw] = useState(initialWidth);
18
18
  const [dh, setDh] = useState(initialHeight);
19
19
  const [layers, setLayers] = useState(() => [
20
- { id: lid(), name: "Background", visible: true, opacity: 255, locked: false, blendMode: "normal" },
20
+ {
21
+ id: lid(),
22
+ name: 'Background',
23
+ visible: true,
24
+ opacity: 255,
25
+ locked: false,
26
+ blendMode: 'normal',
27
+ },
21
28
  ]);
22
29
  const [aLi, setALi] = useState(0);
23
30
  const [fc, setFc] = useState(1);
24
31
  const [afi, setAfi] = useState(0);
25
32
  const [fDur, setFDur] = useState([100]);
26
- const [tool, setTool] = useState("pencil");
27
- const [col1, setCol1] = useState("#000000");
28
- const [col2, setCol2] = useState("#ffffff");
33
+ const [tool, setTool] = useState('pencil');
34
+ const [col1, setCol1] = useState('#000000');
35
+ const [col2, setCol2] = useState('#ffffff');
29
36
  const [brush, setBrush] = useState({ ...DEFAULT_BRUSH });
30
37
  const [zoom, setZoom] = useState(8);
31
38
  const [px, setPx] = useState(0);
@@ -41,7 +48,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
41
48
  const [nh, setNh] = useState(64);
42
49
  const [sel, setSel] = useState(null);
43
50
  const [tick, setTick] = useState(0);
44
- const [symmetry, setSymmetry] = useState("none");
51
+ const [symmetry, setSymmetry] = useState('none');
45
52
  const [shapeFilled, setShapeFilled] = useState(false);
46
53
  const [pressure, setPressure] = useState(0.5);
47
54
  const [showHSV, setShowHSV] = useState(false);
@@ -77,8 +84,9 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
77
84
  const scr2art = useCallback((cx, cy) => {
78
85
  var _a;
79
86
  const r = (_a = boxRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
80
- if (!r)
87
+ if (!r) {
81
88
  return { x: 0, y: 0 };
89
+ }
82
90
  return {
83
91
  x: Math.floor((cx - r.left - px - r.width / 2) / zoom + dw / 2),
84
92
  y: Math.floor((cy - r.top - py - r.height / 2) / zoom + dh / 2),
@@ -95,8 +103,9 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
95
103
  layers: JSON.parse(JSON.stringify(layers)),
96
104
  frameCount: fc,
97
105
  });
98
- if (hist.current.length > 50)
106
+ if (hist.current.length > 50) {
99
107
  hist.current.shift();
108
+ }
100
109
  hIdx.current = hist.current.length - 1;
101
110
  }, [layers, fc]);
102
111
  const restoreEntry = useCallback((e) => {
@@ -107,61 +116,66 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
107
116
  setTick((t) => t + 1);
108
117
  }, []);
109
118
  const undo = useCallback(() => {
110
- if (hIdx.current <= 0)
119
+ if (hIdx.current <= 0) {
111
120
  return;
121
+ }
112
122
  hIdx.current--;
113
123
  restoreEntry(hist.current[hIdx.current]);
114
124
  }, [restoreEntry]);
115
125
  const redo = useCallback(() => {
116
- if (hIdx.current >= hist.current.length - 1)
126
+ if (hIdx.current >= hist.current.length - 1) {
117
127
  return;
128
+ }
118
129
  hIdx.current++;
119
130
  restoreEntry(hist.current[hIdx.current]);
120
131
  }, [restoreEntry]);
121
132
  /* Push initial snapshot so first undo works */
122
133
  useEffect(() => {
123
134
  if (hist.current.length === 0) {
124
- snap("initial");
135
+ snap('initial');
125
136
  }
126
137
  }, [snap]);
127
138
  /* ── composite a frame ── */
128
139
  const compFrame = useCallback((fi) => {
129
140
  const cv = new OffscreenCanvas(dw, dh);
130
- const ctx = cv.getContext("2d");
141
+ const ctx = cv.getContext('2d');
131
142
  for (let li = 0; li < layers.length; li++) {
132
- if (!layers[li].visible)
143
+ if (!layers[li].visible) {
133
144
  continue;
145
+ }
134
146
  const c = cels.current.get(celKey(fi, li));
135
- if (!c)
147
+ if (!c) {
136
148
  continue;
149
+ }
137
150
  const t = new OffscreenCanvas(dw, dh);
138
- t.getContext("2d").putImageData(c, 0, 0);
151
+ t.getContext('2d').putImageData(c, 0, 0);
139
152
  ctx.globalAlpha = layers[li].opacity / 255;
140
153
  const bm = layers[li].blendMode;
141
- if (bm !== "normal") {
154
+ if (bm !== 'normal') {
142
155
  ctx.globalCompositeOperation = bm;
143
156
  }
144
157
  else {
145
- ctx.globalCompositeOperation = "source-over";
158
+ ctx.globalCompositeOperation = 'source-over';
146
159
  }
147
160
  ctx.drawImage(t, 0, 0);
148
161
  }
149
- ctx.globalCompositeOperation = "source-over";
162
+ ctx.globalCompositeOperation = 'source-over';
150
163
  return ctx.getImageData(0, 0, dw, dh);
151
164
  }, [dw, dh, layers]);
152
165
  /* ── rendering ── */
153
166
  const render = useCallback(() => {
154
167
  const canvas = cvRef.current;
155
168
  const box = boxRef.current;
156
- if (!canvas || !box)
169
+ if (!canvas || !box) {
157
170
  return;
171
+ }
158
172
  const cw = box.clientWidth;
159
173
  const ch = box.clientHeight;
160
174
  if (canvas.width !== cw || canvas.height !== ch) {
161
175
  canvas.width = cw;
162
176
  canvas.height = ch;
163
177
  }
164
- const ctx = canvas.getContext("2d");
178
+ const ctx = canvas.getContext('2d');
165
179
  ctx.clearRect(0, 0, cw, ch);
166
180
  ctx.imageSmoothingEnabled = false;
167
181
  ctx.save();
@@ -169,23 +183,26 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
169
183
  ctx.scale(zoom, zoom);
170
184
  ctx.translate(-dw / 2, -dh / 2);
171
185
  // checkerboard
172
- for (let y = 0; y < dh; y++)
186
+ for (let y = 0; y < dh; y++) {
173
187
  for (let x = 0; x < dw; x++) {
174
- ctx.fillStyle = (x + y) % 2 === 0 ? "#3c3c3c" : "#2c2c2c";
188
+ ctx.fillStyle = (x + y) % 2 === 0 ? '#3c3c3c' : '#2c2c2c';
175
189
  ctx.fillRect(x, y, 1, 1);
176
190
  }
191
+ }
177
192
  // onion skin (prev frame)
178
193
  if (onion && afi > 0) {
179
194
  const oc = new OffscreenCanvas(dw, dh);
180
- const ox = oc.getContext("2d");
195
+ const ox = oc.getContext('2d');
181
196
  for (let li = 0; li < layers.length; li++) {
182
- if (!layers[li].visible)
197
+ if (!layers[li].visible) {
183
198
  continue;
199
+ }
184
200
  const c = cels.current.get(celKey(afi - 1, li));
185
- if (!c)
201
+ if (!c) {
186
202
  continue;
203
+ }
187
204
  const t = new OffscreenCanvas(dw, dh);
188
- t.getContext("2d").putImageData(c, 0, 0);
205
+ t.getContext('2d').putImageData(c, 0, 0);
189
206
  ox.globalAlpha = (layers[li].opacity / 255) * 0.25;
190
207
  ox.drawImage(t, 0, 0);
191
208
  }
@@ -193,95 +210,105 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
193
210
  }
194
211
  // current frame composite
195
212
  const comp = new OffscreenCanvas(dw, dh);
196
- const cc = comp.getContext("2d");
213
+ const cc = comp.getContext('2d');
197
214
  for (let li = 0; li < layers.length; li++) {
198
- if (!layers[li].visible)
215
+ if (!layers[li].visible) {
199
216
  continue;
217
+ }
200
218
  const c = cels.current.get(celKey(afi, li));
201
- if (!c)
219
+ if (!c) {
202
220
  continue;
221
+ }
203
222
  const t = new OffscreenCanvas(dw, dh);
204
- t.getContext("2d").putImageData(c, 0, 0);
223
+ t.getContext('2d').putImageData(c, 0, 0);
205
224
  cc.globalAlpha = layers[li].opacity / 255;
206
225
  const bm = layers[li].blendMode;
207
- if (bm !== "normal") {
226
+ if (bm !== 'normal') {
208
227
  cc.globalCompositeOperation = bm;
209
228
  }
210
229
  else {
211
- cc.globalCompositeOperation = "source-over";
230
+ cc.globalCompositeOperation = 'source-over';
212
231
  }
213
232
  cc.drawImage(t, 0, 0);
214
233
  }
215
- cc.globalCompositeOperation = "source-over";
234
+ cc.globalCompositeOperation = 'source-over';
216
235
  ctx.drawImage(comp, 0, 0);
217
236
  // tool preview (line / rect / ellipse while dragging)
218
237
  if (preview.current && drawing.current) {
219
238
  const pv = preview.current;
220
239
  const clr = btn.current === 2 ? hex2t(col2) : hex2t(col1);
221
240
  const pvData = cloneImageData(getCel(afi, aLi));
222
- if (tool === "line") {
241
+ if (tool === 'line') {
223
242
  bresenhamLine(pv.fr.x, pv.fr.y, pv.to.x, pv.to.y, (bx, by) => {
224
- if (inB(bx, by, dw, dh))
243
+ if (inB(bx, by, dw, dh)) {
225
244
  setPixel(pvData, bx, by, clr);
245
+ }
226
246
  });
227
247
  }
228
- else if (tool === "rect") {
248
+ else if (tool === 'rect') {
229
249
  const x1 = Math.min(pv.fr.x, pv.to.x), y1 = Math.min(pv.fr.y, pv.to.y);
230
250
  const x2 = Math.max(pv.fr.x, pv.to.x), y2 = Math.max(pv.fr.y, pv.to.y);
231
251
  if (shapeFilled) {
232
- for (let y = y1; y <= y2; y++)
233
- for (let x = x1; x <= x2; x++)
234
- if (inB(x, y, dw, dh))
252
+ for (let y = y1; y <= y2; y++) {
253
+ for (let x = x1; x <= x2; x++) {
254
+ if (inB(x, y, dw, dh)) {
235
255
  setPixel(pvData, x, y, clr);
256
+ }
257
+ }
258
+ }
236
259
  }
237
260
  else {
238
261
  for (let x = x1; x <= x2; x++) {
239
- if (inB(x, y1, dw, dh))
262
+ if (inB(x, y1, dw, dh)) {
240
263
  setPixel(pvData, x, y1, clr);
241
- if (inB(x, y2, dw, dh))
264
+ }
265
+ if (inB(x, y2, dw, dh)) {
242
266
  setPixel(pvData, x, y2, clr);
267
+ }
243
268
  }
244
269
  for (let y = y1 + 1; y < y2; y++) {
245
- if (inB(x1, y, dw, dh))
270
+ if (inB(x1, y, dw, dh)) {
246
271
  setPixel(pvData, x1, y, clr);
247
- if (inB(x2, y, dw, dh))
272
+ }
273
+ if (inB(x2, y, dw, dh)) {
248
274
  setPixel(pvData, x2, y, clr);
275
+ }
249
276
  }
250
277
  }
251
278
  }
252
- else if (tool === "ellipse") {
279
+ else if (tool === 'ellipse') {
253
280
  const cx2 = (pv.fr.x + pv.to.x) / 2, cy2 = (pv.fr.y + pv.to.y) / 2;
254
281
  const rx = Math.abs(pv.to.x - pv.fr.x) / 2, ry = Math.abs(pv.to.y - pv.fr.y) / 2;
255
282
  plotEllipse(pvData, cx2, cy2, rx, ry, clr, dw, dh, shapeFilled);
256
283
  }
257
- else if (tool === "gradient") {
284
+ else if (tool === 'gradient') {
258
285
  const c2 = btn.current === 2 ? hex2t(col1) : hex2t(col2);
259
286
  drawGradient(pvData, pv.fr.x, pv.fr.y, pv.to.x, pv.to.y, clr, c2, sel);
260
287
  }
261
288
  const pcv = new OffscreenCanvas(dw, dh);
262
- pcv.getContext("2d").putImageData(pvData, 0, 0);
289
+ pcv.getContext('2d').putImageData(pvData, 0, 0);
263
290
  ctx.globalAlpha = layers[aLi].opacity / 255;
264
291
  ctx.drawImage(pcv, 0, 0);
265
292
  ctx.globalAlpha = 1;
266
293
  }
267
294
  // symmetry guides
268
- if (symmetry !== "none") {
269
- ctx.strokeStyle = "rgba(255,100,100,0.3)";
295
+ if (symmetry !== 'none') {
296
+ ctx.strokeStyle = 'rgba(255,100,100,0.3)';
270
297
  ctx.lineWidth = 1 / zoom;
271
298
  ctx.setLineDash([4 / zoom, 4 / zoom]);
272
- if (symmetry === "h" || symmetry === "both") {
299
+ if (symmetry === 'h' || symmetry === 'both') {
273
300
  ctx.beginPath();
274
301
  ctx.moveTo(dw / 2, 0);
275
302
  ctx.lineTo(dw / 2, dh);
276
303
  ctx.stroke();
277
304
  }
278
- if (symmetry === "v" || symmetry === "both") {
305
+ if (symmetry === 'v' || symmetry === 'both') {
279
306
  ctx.beginPath();
280
307
  ctx.moveTo(0, dh / 2);
281
308
  ctx.lineTo(dw, dh / 2);
282
309
  ctx.stroke();
283
310
  }
284
- if (symmetry === "radial4") {
311
+ if (symmetry === 'radial4') {
285
312
  ctx.beginPath();
286
313
  ctx.moveTo(dw / 2, 0);
287
314
  ctx.lineTo(dw / 2, dh);
@@ -293,7 +320,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
293
320
  }
294
321
  // selection marching ants
295
322
  if (sel) {
296
- ctx.strokeStyle = "rgba(255,255,255,0.8)";
323
+ ctx.strokeStyle = 'rgba(255,255,255,0.8)';
297
324
  ctx.lineWidth = 1 / zoom;
298
325
  ctx.setLineDash([4 / zoom, 4 / zoom]);
299
326
  ctx.strokeRect(sel.x, sel.y, sel.w, sel.h);
@@ -301,7 +328,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
301
328
  }
302
329
  // grid
303
330
  if (grid && zoom >= 4) {
304
- ctx.strokeStyle = "rgba(255,255,255,0.07)";
331
+ ctx.strokeStyle = 'rgba(255,255,255,0.07)';
305
332
  ctx.lineWidth = 1 / zoom;
306
333
  for (let x = 0; x <= dw; x++) {
307
334
  ctx.beginPath();
@@ -317,16 +344,20 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
317
344
  }
318
345
  }
319
346
  // border
320
- ctx.strokeStyle = "rgba(80,100,200,0.4)";
347
+ ctx.strokeStyle = 'rgba(80,100,200,0.4)';
321
348
  ctx.lineWidth = 1 / zoom;
322
349
  ctx.strokeRect(-0.5 / zoom, -0.5 / zoom, dw + 1 / zoom, dh + 1 / zoom);
323
350
  // brush cursor preview
324
- if (cursor && inB(cursor.x, cursor.y, dw, dh) && (tool === "pencil" || tool === "eraser" || tool === "dither")) {
325
- const sz = brush.pressureSize ? Math.max(1, Math.round(brush.size * curPressure.current)) : brush.size;
351
+ if (cursor &&
352
+ inB(cursor.x, cursor.y, dw, dh) &&
353
+ (tool === 'pencil' || tool === 'eraser' || tool === 'dither')) {
354
+ const sz = brush.pressureSize
355
+ ? Math.max(1, Math.round(brush.size * curPressure.current))
356
+ : brush.size;
326
357
  const half = Math.floor(sz / 2);
327
- ctx.strokeStyle = "rgba(255,255,255,0.5)";
358
+ ctx.strokeStyle = 'rgba(255,255,255,0.5)';
328
359
  ctx.lineWidth = 1 / zoom;
329
- if (brush.shape === "circle") {
360
+ if (brush.shape === 'circle') {
330
361
  ctx.beginPath();
331
362
  ctx.arc(cursor.x + 0.5, cursor.y + 0.5, half + 0.5, 0, Math.PI * 2);
332
363
  ctx.stroke();
@@ -336,14 +367,34 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
336
367
  }
337
368
  }
338
369
  ctx.restore();
339
- }, [dw, dh, zoom, px, py, layers, afi, aLi, grid, onion, tool, col1, col2, sel, getCel, symmetry, shapeFilled, brush, cursor]);
370
+ }, [
371
+ dw,
372
+ dh,
373
+ zoom,
374
+ px,
375
+ py,
376
+ layers,
377
+ afi,
378
+ aLi,
379
+ grid,
380
+ onion,
381
+ tool,
382
+ col1,
383
+ col2,
384
+ sel,
385
+ getCel,
386
+ symmetry,
387
+ shapeFilled,
388
+ brush,
389
+ cursor,
390
+ ]);
340
391
  /* ── brush drawing with symmetry ── */
341
392
  const applyBrushAt = useCallback((x, y, erase, pr) => {
342
393
  const cel = getCel(afi, aLi);
343
394
  const clr = erase ? [0, 0, 0, 0] : hex2t(btn.current === 2 ? col2 : col1);
344
395
  const pts = getSymmetryPoints(x, y, dw, dh, symmetry);
345
396
  for (const pt of pts) {
346
- if (tool === "dither") {
397
+ if (tool === 'dither') {
347
398
  applyDitherStamp(cel, pt.x, pt.y, clr, brush.size, pr);
348
399
  }
349
400
  else {
@@ -367,22 +418,23 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
367
418
  }
368
419
  const p = scr2art(e.clientX, e.clientY);
369
420
  setCursor(p);
370
- if ((_c = layers[aLi]) === null || _c === void 0 ? void 0 : _c.locked)
421
+ if ((_c = layers[aLi]) === null || _c === void 0 ? void 0 : _c.locked) {
371
422
  return;
423
+ }
372
424
  switch (tool) {
373
- case "pencil":
374
- case "eraser":
375
- case "dither":
376
- snap(tool === "pencil" ? "Draw" : tool === "eraser" ? "Erase" : "Dither");
425
+ case 'pencil':
426
+ case 'eraser':
427
+ case 'dither':
428
+ snap(tool === 'pencil' ? 'Draw' : tool === 'eraser' ? 'Erase' : 'Dither');
377
429
  drawing.current = true;
378
430
  lastPx.current = p;
379
431
  brushDist.current = 0;
380
- applyBrushAt(p.x, p.y, tool === "eraser", pr);
432
+ applyBrushAt(p.x, p.y, tool === 'eraser', pr);
381
433
  setTick((t) => t + 1);
382
434
  break;
383
- case "fill":
435
+ case 'fill':
384
436
  if (inB(p.x, p.y, dw, dh)) {
385
- snap("Fill");
437
+ snap('Fill');
386
438
  const clr = hex2t(e.button === 2 ? col2 : col1);
387
439
  const pts = getSymmetryPoints(p.x, p.y, dw, dh, symmetry);
388
440
  const cel = getCel(afi, aLi);
@@ -394,36 +446,54 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
394
446
  setTick((t) => t + 1);
395
447
  }
396
448
  break;
397
- case "eyedropper": {
449
+ case 'eyedropper': {
398
450
  if (inB(p.x, p.y, dw, dh)) {
399
451
  const c = getPixel(getCel(afi, aLi), p.x, p.y);
400
452
  const hex = rgbaToHex(c);
401
- if (e.button === 2)
453
+ if (e.button === 2) {
402
454
  setCol2(hex);
403
- else
455
+ }
456
+ else {
404
457
  setCol1(hex);
458
+ }
405
459
  }
406
460
  break;
407
461
  }
408
- case "line":
409
- case "rect":
410
- case "ellipse":
411
- case "gradient":
462
+ case 'line':
463
+ case 'rect':
464
+ case 'ellipse':
465
+ case 'gradient':
412
466
  snap(tool[0].toUpperCase() + tool.slice(1));
413
467
  drawing.current = true;
414
468
  tStart.current = p;
415
469
  preview.current = { fr: p, to: p };
416
470
  break;
417
- case "select":
471
+ case 'select':
418
472
  drawing.current = true;
419
473
  tStart.current = p;
420
474
  break;
421
- case "move":
475
+ case 'move':
422
476
  drawing.current = true;
423
477
  lastPx.current = p;
424
478
  break;
425
479
  }
426
- }, [tool, aLi, layers, px, py, scr2art, snap, applyBrushAt, getCel, afi, col1, col2, dw, dh, symmetry]);
480
+ }, [
481
+ tool,
482
+ aLi,
483
+ layers,
484
+ px,
485
+ py,
486
+ scr2art,
487
+ snap,
488
+ applyBrushAt,
489
+ getCel,
490
+ afi,
491
+ col1,
492
+ col2,
493
+ dw,
494
+ dh,
495
+ symmetry,
496
+ ]);
427
497
  const onMove = useCallback((e) => {
428
498
  const pr = e.pressure > 0 ? e.pressure : 0.5;
429
499
  curPressure.current = pr;
@@ -435,30 +505,32 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
435
505
  }
436
506
  const p = scr2art(e.clientX, e.clientY);
437
507
  setCursor(p);
438
- if (!drawing.current)
508
+ if (!drawing.current) {
439
509
  return;
440
- if (tool === "pencil" || tool === "eraser" || tool === "dither") {
510
+ }
511
+ if (tool === 'pencil' || tool === 'eraser' || tool === 'dither') {
441
512
  const last = lastPx.current || p;
442
513
  const spacing = Math.max(1, brush.size * (brush.spacing / 100));
443
514
  const ddx = p.x - last.x, ddy = p.y - last.y;
444
515
  const dist = Math.sqrt(ddx * ddx + ddy * ddy);
445
- if (dist < 0.5)
516
+ if (dist < 0.5) {
446
517
  return;
518
+ }
447
519
  brushDist.current += dist;
448
520
  if (brushDist.current >= spacing) {
449
521
  bresenhamLine(last.x, last.y, p.x, p.y, (bx, by) => {
450
- applyBrushAt(bx, by, tool === "eraser", pr);
522
+ applyBrushAt(bx, by, tool === 'eraser', pr);
451
523
  });
452
524
  brushDist.current = 0;
453
525
  }
454
526
  lastPx.current = p;
455
527
  setTick((t) => t + 1);
456
528
  }
457
- else if (tool === "line" || tool === "rect" || tool === "ellipse" || tool === "gradient") {
529
+ else if (tool === 'line' || tool === 'rect' || tool === 'ellipse' || tool === 'gradient') {
458
530
  preview.current = { fr: tStart.current, to: p };
459
531
  setTick((t) => t + 1);
460
532
  }
461
- else if (tool === "select") {
533
+ else if (tool === 'select') {
462
534
  const s = tStart.current;
463
535
  setSel({
464
536
  x: Math.min(s.x, p.x),
@@ -467,7 +539,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
467
539
  h: Math.abs(p.y - s.y) + 1,
468
540
  });
469
541
  }
470
- else if (tool === "move" && sel) {
542
+ else if (tool === 'move' && sel) {
471
543
  const last2 = lastPx.current || p;
472
544
  const ddx = p.x - last2.x, ddy = p.y - last2.y;
473
545
  if (ddx !== 0 || ddy !== 0) {
@@ -481,18 +553,20 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
481
553
  panning.current = false;
482
554
  return;
483
555
  }
484
- if (!drawing.current)
556
+ if (!drawing.current) {
485
557
  return;
558
+ }
486
559
  drawing.current = false;
487
560
  const p = scr2art(e.clientX, e.clientY);
488
561
  const clr = btn.current === 2 ? hex2t(col2) : hex2t(col1);
489
- if (tool === "line" && tStart.current) {
562
+ if (tool === 'line' && tStart.current) {
490
563
  const cel = getCel(afi, aLi);
491
564
  getSymmetryPoints(0, 0, dw, dh, symmetry);
492
- if (symmetry === "none") {
565
+ if (symmetry === 'none') {
493
566
  bresenhamLine(tStart.current.x, tStart.current.y, p.x, p.y, (bx, by) => {
494
- if (inB(bx, by, dw, dh))
567
+ if (inB(bx, by, dw, dh)) {
495
568
  setPixel(cel, bx, by, clr);
569
+ }
496
570
  });
497
571
  }
498
572
  else {
@@ -500,42 +574,50 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
500
574
  const toPts = getSymmetryPoints(p.x, p.y, dw, dh, symmetry);
501
575
  for (let i = 0; i < fromPts.length; i++) {
502
576
  bresenhamLine(fromPts[i].x, fromPts[i].y, toPts[i].x, toPts[i].y, (bx, by) => {
503
- if (inB(bx, by, dw, dh))
577
+ if (inB(bx, by, dw, dh)) {
504
578
  setPixel(cel, bx, by, clr);
579
+ }
505
580
  });
506
581
  }
507
582
  }
508
583
  preview.current = null;
509
584
  setTick((t) => t + 1);
510
585
  }
511
- else if (tool === "rect" && tStart.current) {
586
+ else if (tool === 'rect' && tStart.current) {
512
587
  const cel = getCel(afi, aLi);
513
588
  const x1 = Math.min(tStart.current.x, p.x), y1 = Math.min(tStart.current.y, p.y);
514
589
  const x2 = Math.max(tStart.current.x, p.x), y2 = Math.max(tStart.current.y, p.y);
515
590
  if (shapeFilled) {
516
- for (let y = y1; y <= y2; y++)
517
- for (let x = x1; x <= x2; x++)
518
- if (inB(x, y, dw, dh))
591
+ for (let y = y1; y <= y2; y++) {
592
+ for (let x = x1; x <= x2; x++) {
593
+ if (inB(x, y, dw, dh)) {
519
594
  setPixel(cel, x, y, clr);
595
+ }
596
+ }
597
+ }
520
598
  }
521
599
  else {
522
600
  for (let x = x1; x <= x2; x++) {
523
- if (inB(x, y1, dw, dh))
601
+ if (inB(x, y1, dw, dh)) {
524
602
  setPixel(cel, x, y1, clr);
525
- if (inB(x, y2, dw, dh))
603
+ }
604
+ if (inB(x, y2, dw, dh)) {
526
605
  setPixel(cel, x, y2, clr);
606
+ }
527
607
  }
528
608
  for (let y = y1 + 1; y < y2; y++) {
529
- if (inB(x1, y, dw, dh))
609
+ if (inB(x1, y, dw, dh)) {
530
610
  setPixel(cel, x1, y, clr);
531
- if (inB(x2, y, dw, dh))
611
+ }
612
+ if (inB(x2, y, dw, dh)) {
532
613
  setPixel(cel, x2, y, clr);
614
+ }
533
615
  }
534
616
  }
535
617
  preview.current = null;
536
618
  setTick((t) => t + 1);
537
619
  }
538
- else if (tool === "ellipse" && tStart.current) {
620
+ else if (tool === 'ellipse' && tStart.current) {
539
621
  const cel = getCel(afi, aLi);
540
622
  const cx2 = (tStart.current.x + p.x) / 2;
541
623
  const cy2 = (tStart.current.y + p.y) / 2;
@@ -545,7 +627,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
545
627
  preview.current = null;
546
628
  setTick((t) => t + 1);
547
629
  }
548
- else if (tool === "gradient" && tStart.current) {
630
+ else if (tool === 'gradient' && tStart.current) {
549
631
  const cel = getCel(afi, aLi);
550
632
  const c2 = btn.current === 2 ? hex2t(col1) : hex2t(col2);
551
633
  drawGradient(cel, tStart.current.x, tStart.current.y, p.x, p.y, clr, c2, sel);
@@ -556,22 +638,32 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
556
638
  tStart.current = null;
557
639
  }, [tool, scr2art, getCel, afi, aLi, col1, col2, dw, dh, shapeFilled, symmetry, sel]);
558
640
  const onWheel = useCallback((e) => {
559
- e.preventDefault();
560
641
  setZoom((z) => {
561
642
  const n = e.deltaY < 0 ? z * 1.2 : z / 1.2;
562
643
  return Math.max(0.5, Math.min(64, n));
563
644
  });
564
645
  }, []);
646
+ useEffect(() => {
647
+ const el = cvRef.current;
648
+ if (!el) {
649
+ return;
650
+ }
651
+ const handler = (e) => e.preventDefault();
652
+ el.addEventListener('wheel', handler, { passive: false });
653
+ return () => el.removeEventListener('wheel', handler);
654
+ }, []);
565
655
  /* ── clipboard operations ── */
566
656
  const doCopy = useCallback(() => {
567
- if (!sel)
657
+ if (!sel) {
568
658
  return;
659
+ }
569
660
  clipboard.current = copySelection(getCel(afi, aLi), sel);
570
661
  }, [sel, getCel, afi, aLi]);
571
662
  const doCut = useCallback(() => {
572
- if (!sel)
663
+ if (!sel) {
573
664
  return;
574
- snap("Cut");
665
+ }
666
+ snap('Cut');
575
667
  const cel = getCel(afi, aLi);
576
668
  clipboard.current = copySelection(cel, sel);
577
669
  clearSelection(cel, sel);
@@ -579,17 +671,19 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
579
671
  }, [sel, getCel, afi, aLi, snap]);
580
672
  const doPaste = useCallback(() => {
581
673
  var _a, _b;
582
- if (!clipboard.current)
674
+ if (!clipboard.current) {
583
675
  return;
584
- snap("Paste");
676
+ }
677
+ snap('Paste');
585
678
  const cel = getCel(afi, aLi);
586
679
  pasteAt(cel, clipboard.current, (_a = sel === null || sel === void 0 ? void 0 : sel.x) !== null && _a !== void 0 ? _a : 0, (_b = sel === null || sel === void 0 ? void 0 : sel.y) !== null && _b !== void 0 ? _b : 0);
587
680
  setTick((t) => t + 1);
588
681
  }, [getCel, afi, aLi, snap, sel]);
589
682
  const doDeleteSel = useCallback(() => {
590
- if (!sel)
683
+ if (!sel) {
591
684
  return;
592
- snap("Delete Selection");
685
+ }
686
+ snap('Delete Selection');
593
687
  clearSelection(getCel(afi, aLi), sel);
594
688
  setTick((t) => t + 1);
595
689
  }, [sel, getCel, afi, aLi, snap]);
@@ -610,11 +704,20 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
610
704
  visible: l.visible,
611
705
  opacity: l.opacity,
612
706
  locked: false,
613
- blendMode: "normal",
707
+ blendMode: 'normal',
614
708
  }));
615
709
  setLayers(lrs.length
616
710
  ? lrs
617
- : [{ id: lid(), name: "Layer 1", visible: true, opacity: 255, locked: false, blendMode: "normal" }]);
711
+ : [
712
+ {
713
+ id: lid(),
714
+ name: 'Layer 1',
715
+ visible: true,
716
+ opacity: 255,
717
+ locked: false,
718
+ blendMode: 'normal',
719
+ },
720
+ ]);
618
721
  setALi(0);
619
722
  setFc(doc.frames.length || 1);
620
723
  setAfi(0);
@@ -623,22 +726,27 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
623
726
  frame.cels.forEach((cel) => {
624
727
  const data = createBlankImageData(doc.width, doc.height);
625
728
  if (cel.pixels && cel.width > 0 && cel.height > 0) {
626
- for (let y = 0; y < cel.height; y++)
729
+ for (let y = 0; y < cel.height; y++) {
627
730
  for (let x = 0; x < cel.width; x++) {
628
731
  const dx = cel.x + x, dy = cel.y + y;
629
732
  if (dx >= 0 && dy >= 0 && dx < doc.width && dy < doc.height) {
630
733
  const si = (y * cel.width + x) * 4;
631
734
  setPixel(data, dx, dy, [
632
- cel.pixels[si], cel.pixels[si + 1], cel.pixels[si + 2], cel.pixels[si + 3],
735
+ cel.pixels[si],
736
+ cel.pixels[si + 1],
737
+ cel.pixels[si + 2],
738
+ cel.pixels[si + 3],
633
739
  ]);
634
740
  }
635
741
  }
742
+ }
636
743
  }
637
744
  cels.current.set(celKey(fi, cel.layerIndex), data);
638
745
  });
639
746
  });
640
- if (doc.palette.length)
747
+ if (doc.palette.length) {
641
748
  setPal(doc.palette.map(aseColorToHex));
749
+ }
642
750
  setZoom(Math.max(1, Math.floor(Math.min(512 / doc.width, 512 / doc.height))));
643
751
  setPx(0);
644
752
  setPy(0);
@@ -653,8 +761,8 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
653
761
  loadAseDoc(doc);
654
762
  }
655
763
  catch (err) {
656
- log.error("ASE parse error", err);
657
- alert("Failed to parse Aseprite file.");
764
+ log.error('ASE parse error', err);
765
+ console.warn('[PixelEditor] Failed to parse Aseprite file.');
658
766
  }
659
767
  }
660
768
  else {
@@ -662,12 +770,21 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
662
770
  img.onload = () => {
663
771
  const w2 = img.naturalWidth, h2 = img.naturalHeight;
664
772
  const cv = new OffscreenCanvas(w2, h2);
665
- cv.getContext("2d").drawImage(img, 0, 0);
666
- const data = cv.getContext("2d").getImageData(0, 0, w2, h2);
773
+ cv.getContext('2d').drawImage(img, 0, 0);
774
+ const data = cv.getContext('2d').getImageData(0, 0, w2, h2);
667
775
  setDw(w2);
668
776
  setDh(h2);
669
777
  cels.current = new Map([[celKey(0, 0), data]]);
670
- setLayers([{ id: lid(), name: "Layer 1", visible: true, opacity: 255, locked: false, blendMode: "normal" }]);
778
+ setLayers([
779
+ {
780
+ id: lid(),
781
+ name: 'Layer 1',
782
+ visible: true,
783
+ opacity: 255,
784
+ locked: false,
785
+ blendMode: 'normal',
786
+ },
787
+ ]);
671
788
  setALi(0);
672
789
  setFc(1);
673
790
  setAfi(0);
@@ -705,34 +822,44 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
705
822
  }, [dw, dh, fc, compFrame]);
706
823
  /* ── save to library ── */
707
824
  const saveToLibrary = useCallback(() => {
708
- if (!onSaveToLibrary)
825
+ if (!onSaveToLibrary) {
709
826
  return;
827
+ }
710
828
  const data = compFrame(afi);
711
- const cv = document.createElement("canvas");
829
+ const cv = document.createElement('canvas');
712
830
  cv.width = dw;
713
831
  cv.height = dh;
714
- cv.getContext("2d").putImageData(data, 0, 0);
715
- const dataUrl = cv.toDataURL("image/png");
832
+ cv.getContext('2d').putImageData(data, 0, 0);
833
+ const dataUrl = cv.toDataURL('image/png');
716
834
  const defaultName = `sprite-${dw}x${dh}.png`;
717
- const name = window.prompt("Save to library as:", defaultName);
718
- if (!name || !name.trim())
835
+ const name = window.prompt('Save to library as:', defaultName);
836
+ if (!name || !name.trim()) {
719
837
  return;
720
- onSaveToLibrary(dataUrl, name.trim(), "image/png");
838
+ }
839
+ onSaveToLibrary(dataUrl, name.trim(), 'image/png');
721
840
  }, [onSaveToLibrary, afi, dw, dh, compFrame]);
722
841
  /* ── layer management ── */
723
842
  const addLayer = useCallback(() => {
724
- snap("Add Layer");
843
+ snap('Add Layer');
725
844
  setLayers((ls) => [
726
845
  ...ls,
727
- { id: lid(), name: `Layer ${ls.length + 1}`, visible: true, opacity: 255, locked: false, blendMode: "normal" },
846
+ {
847
+ id: lid(),
848
+ name: `Layer ${ls.length + 1}`,
849
+ visible: true,
850
+ opacity: 255,
851
+ locked: false,
852
+ blendMode: 'normal',
853
+ },
728
854
  ]);
729
855
  setALi(layers.length);
730
856
  setTick((t) => t + 1);
731
857
  }, [layers, snap]);
732
858
  const rmLayer = useCallback(() => {
733
- if (layers.length <= 1)
859
+ if (layers.length <= 1) {
734
860
  return;
735
- snap("Remove Layer");
861
+ }
862
+ snap('Remove Layer');
736
863
  const idx = aLi;
737
864
  for (let fi = 0; fi < fc; fi++) {
738
865
  cels.current.delete(celKey(fi, idx));
@@ -767,9 +894,10 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
767
894
  setLayers((ls) => ls.map((l, j) => (j === i ? { ...l, name } : l)));
768
895
  }, []);
769
896
  const moveLayerUp = useCallback(() => {
770
- if (aLi >= layers.length - 1)
897
+ if (aLi >= layers.length - 1) {
771
898
  return;
772
- snap("Move Layer Up");
899
+ }
900
+ snap('Move Layer Up');
773
901
  setLayers((ls) => {
774
902
  const n = [...ls];
775
903
  [n[aLi], n[aLi + 1]] = [n[aLi + 1], n[aLi]];
@@ -778,22 +906,27 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
778
906
  for (let fi = 0; fi < fc; fi++) {
779
907
  const a = cels.current.get(celKey(fi, aLi));
780
908
  const b = cels.current.get(celKey(fi, aLi + 1));
781
- if (a)
909
+ if (a) {
782
910
  cels.current.set(celKey(fi, aLi + 1), a);
783
- else
911
+ }
912
+ else {
784
913
  cels.current.delete(celKey(fi, aLi + 1));
785
- if (b)
914
+ }
915
+ if (b) {
786
916
  cels.current.set(celKey(fi, aLi), b);
787
- else
917
+ }
918
+ else {
788
919
  cels.current.delete(celKey(fi, aLi));
920
+ }
789
921
  }
790
922
  setALi(aLi + 1);
791
923
  setTick((t) => t + 1);
792
924
  }, [aLi, layers, fc, snap]);
793
925
  const moveLayerDown = useCallback(() => {
794
- if (aLi <= 0)
926
+ if (aLi <= 0) {
795
927
  return;
796
- snap("Move Layer Down");
928
+ }
929
+ snap('Move Layer Down');
797
930
  setLayers((ls) => {
798
931
  const n = [...ls];
799
932
  [n[aLi], n[aLi - 1]] = [n[aLi - 1], n[aLi]];
@@ -802,31 +935,36 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
802
935
  for (let fi = 0; fi < fc; fi++) {
803
936
  const a = cels.current.get(celKey(fi, aLi));
804
937
  const b = cels.current.get(celKey(fi, aLi - 1));
805
- if (a)
938
+ if (a) {
806
939
  cels.current.set(celKey(fi, aLi - 1), a);
807
- else
940
+ }
941
+ else {
808
942
  cels.current.delete(celKey(fi, aLi - 1));
809
- if (b)
943
+ }
944
+ if (b) {
810
945
  cels.current.set(celKey(fi, aLi), b);
811
- else
946
+ }
947
+ else {
812
948
  cels.current.delete(celKey(fi, aLi));
949
+ }
813
950
  }
814
951
  setALi(aLi - 1);
815
952
  setTick((t) => t + 1);
816
953
  }, [aLi, fc, snap]);
817
954
  const mergeDown = useCallback(() => {
818
- if (aLi <= 0)
955
+ if (aLi <= 0) {
819
956
  return;
820
- snap("Merge Down");
957
+ }
958
+ snap('Merge Down');
821
959
  for (let fi = 0; fi < fc; fi++) {
822
960
  const top = cels.current.get(celKey(fi, aLi));
823
961
  const bot = getCel(fi, aLi - 1);
824
962
  if (top) {
825
963
  const cv = new OffscreenCanvas(dw, dh);
826
- const ctx = cv.getContext("2d");
964
+ const ctx = cv.getContext('2d');
827
965
  ctx.putImageData(bot, 0, 0);
828
966
  const t = new OffscreenCanvas(dw, dh);
829
- t.getContext("2d").putImageData(top, 0, 0);
967
+ t.getContext('2d').putImageData(top, 0, 0);
830
968
  ctx.globalAlpha = layers[aLi].opacity / 255;
831
969
  ctx.drawImage(t, 0, 0);
832
970
  cels.current.set(celKey(fi, aLi - 1), ctx.getImageData(0, 0, dw, dh));
@@ -847,8 +985,8 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
847
985
  setTick((t) => t + 1);
848
986
  }, [aLi, fc, layers, getCel, dw, dh, snap]);
849
987
  const dupLayer = useCallback(() => {
850
- snap("Duplicate Layer");
851
- const newL = { ...layers[aLi], id: lid(), name: layers[aLi].name + " copy" };
988
+ snap('Duplicate Layer');
989
+ const newL = { ...layers[aLi], id: lid(), name: layers[aLi].name + ' copy' };
852
990
  setLayers((ls) => [...ls.slice(0, aLi + 1), newL, ...ls.slice(aLi + 1)]);
853
991
  for (let fi = 0; fi < fc; fi++) {
854
992
  for (let li = layers.length; li > aLi; li--) {
@@ -859,27 +997,29 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
859
997
  }
860
998
  }
861
999
  const src = cels.current.get(celKey(fi, aLi));
862
- if (src)
1000
+ if (src) {
863
1001
  cels.current.set(celKey(fi, aLi + 1), cloneImageData(src));
1002
+ }
864
1003
  }
865
1004
  setALi(aLi + 1);
866
1005
  setTick((t) => t + 1);
867
1006
  }, [aLi, layers, fc, snap]);
868
1007
  /* ── frame management ── */
869
1008
  const addFrame = useCallback(() => {
870
- snap("Add Frame");
1009
+ snap('Add Frame');
871
1010
  setFc((n) => n + 1);
872
1011
  setFDur((d) => [...d, 100]);
873
1012
  setAfi(fc);
874
1013
  setTick((t) => t + 1);
875
1014
  }, [fc, snap]);
876
1015
  const dupFrame = useCallback(() => {
877
- snap("Dup Frame");
1016
+ snap('Dup Frame');
878
1017
  const ni = fc;
879
1018
  for (let li = 0; li < layers.length; li++) {
880
1019
  const c = cels.current.get(celKey(afi, li));
881
- if (c)
1020
+ if (c) {
882
1021
  cels.current.set(celKey(ni, li), cloneImageData(c));
1022
+ }
883
1023
  }
884
1024
  setFc((n) => n + 1);
885
1025
  setFDur((d) => [...d, fDur[afi] || 100]);
@@ -887,9 +1027,10 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
887
1027
  setTick((t) => t + 1);
888
1028
  }, [fc, afi, layers, fDur, snap]);
889
1029
  const rmFrame = useCallback(() => {
890
- if (fc <= 1)
1030
+ if (fc <= 1) {
891
1031
  return;
892
- snap("Remove Frame");
1032
+ }
1033
+ snap('Remove Frame');
893
1034
  for (let li = 0; li < layers.length; li++) {
894
1035
  cels.current.delete(celKey(afi, li));
895
1036
  for (let f = afi + 1; f < fc; f++) {
@@ -907,12 +1048,12 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
907
1048
  }, [fc, afi, layers, snap]);
908
1049
  /* ── canvas ops ── */
909
1050
  const flipCv = useCallback((dir) => {
910
- snap(`Flip ${dir === "h" ? "H" : "V"}`);
911
- cels.current.forEach((c, k) => cels.current.set(k, dir === "h" ? flipH(c) : flipV(c)));
1051
+ snap(`Flip ${dir === 'h' ? 'H' : 'V'}`);
1052
+ cels.current.forEach((c, k) => cels.current.set(k, dir === 'h' ? flipH(c) : flipV(c)));
912
1053
  setTick((t) => t + 1);
913
1054
  }, [snap]);
914
1055
  const rotateCv = useCallback(() => {
915
- snap("Rotate 90°");
1056
+ snap('Rotate 90°');
916
1057
  const n = new Map();
917
1058
  cels.current.forEach((c, k) => n.set(k, rotateCW(c)));
918
1059
  cels.current = n;
@@ -921,7 +1062,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
921
1062
  setTick((t) => t + 1);
922
1063
  }, [dw, dh, snap]);
923
1064
  const clearCv = useCallback(() => {
924
- snap("Clear");
1065
+ snap('Clear');
925
1066
  cels.current.set(celKey(afi, aLi), createBlankImageData(dw, dh));
926
1067
  setTick((t) => t + 1);
927
1068
  }, [afi, aLi, dw, dh, snap]);
@@ -929,7 +1070,16 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
929
1070
  setDw(w);
930
1071
  setDh(h);
931
1072
  cels.current = new Map();
932
- setLayers([{ id: lid(), name: "Background", visible: true, opacity: 255, locked: false, blendMode: "normal" }]);
1073
+ setLayers([
1074
+ {
1075
+ id: lid(),
1076
+ name: 'Background',
1077
+ visible: true,
1078
+ opacity: 255,
1079
+ locked: false,
1080
+ blendMode: 'normal',
1081
+ },
1082
+ ]);
933
1083
  setALi(0);
934
1084
  setFc(1);
935
1085
  setAfi(0);
@@ -951,49 +1101,60 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
951
1101
  // keyboard shortcuts
952
1102
  useEffect(() => {
953
1103
  const h = (e) => {
954
- if (dlgNew)
1104
+ if (dlgNew) {
955
1105
  return;
1106
+ }
956
1107
  const tgt = e.target;
957
- if (tgt.tagName === "INPUT" || tgt.tagName === "TEXTAREA" || tgt.tagName === "SELECT")
1108
+ if (tgt.tagName === 'INPUT' || tgt.tagName === 'TEXTAREA' || tgt.tagName === 'SELECT') {
958
1109
  return;
959
- if (e.ctrlKey && e.key === "z") {
1110
+ }
1111
+ if (e.ctrlKey && e.key === 'z') {
960
1112
  e.preventDefault();
961
1113
  undo();
962
1114
  return;
963
1115
  }
964
- if (e.ctrlKey && (e.key === "y" || (e.shiftKey && e.key === "Z"))) {
1116
+ if (e.ctrlKey && (e.key === 'y' || (e.shiftKey && e.key === 'Z'))) {
965
1117
  e.preventDefault();
966
1118
  redo();
967
1119
  return;
968
1120
  }
969
- if (e.ctrlKey && e.key === "c") {
1121
+ if (e.ctrlKey && e.key === 'c') {
970
1122
  e.preventDefault();
971
1123
  doCopy();
972
1124
  return;
973
1125
  }
974
- if (e.ctrlKey && e.key === "x") {
1126
+ if (e.ctrlKey && e.key === 'x') {
975
1127
  e.preventDefault();
976
1128
  doCut();
977
1129
  return;
978
1130
  }
979
- if (e.ctrlKey && e.key === "v") {
1131
+ if (e.ctrlKey && e.key === 'v') {
980
1132
  e.preventDefault();
981
1133
  doPaste();
982
1134
  return;
983
1135
  }
984
- if (e.ctrlKey && e.key === "a") {
1136
+ if (e.ctrlKey && e.key === 'a') {
985
1137
  e.preventDefault();
986
1138
  doSelectAll();
987
1139
  return;
988
1140
  }
989
- if (e.ctrlKey && e.key === "d") {
1141
+ if (e.ctrlKey && e.key === 'd') {
990
1142
  e.preventDefault();
991
1143
  doDeselectAll();
992
1144
  return;
993
1145
  }
994
1146
  const km = {
995
- b: "pencil", e: "eraser", g: "fill", l: "line", u: "rect",
996
- o: "ellipse", i: "eyedropper", m: "select", v: "move", h: "gradient", d: "dither",
1147
+ b: 'pencil',
1148
+ e: 'eraser',
1149
+ g: 'fill',
1150
+ l: 'line',
1151
+ u: 'rect',
1152
+ o: 'ellipse',
1153
+ i: 'eyedropper',
1154
+ m: 'select',
1155
+ v: 'move',
1156
+ h: 'gradient',
1157
+ d: 'dither',
997
1158
  };
998
1159
  const k = e.key.toLowerCase();
999
1160
  if (km[k]) {
@@ -1001,59 +1162,82 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
1001
1162
  return;
1002
1163
  }
1003
1164
  switch (k) {
1004
- case "+":
1005
- case "=":
1165
+ case '+':
1166
+ case '=':
1006
1167
  setZoom((z) => Math.min(64, z * 1.5));
1007
1168
  break;
1008
- case "-":
1169
+ case '-':
1009
1170
  setZoom((z) => Math.max(0.5, z / 1.5));
1010
1171
  break;
1011
- case "arrowleft":
1172
+ case 'arrowleft':
1012
1173
  setAfi((f) => Math.max(0, f - 1));
1013
1174
  break;
1014
- case "arrowright":
1175
+ case 'arrowright':
1015
1176
  setAfi((f) => Math.min(fc - 1, f + 1));
1016
1177
  break;
1017
- case "n":
1018
- if (!e.ctrlKey)
1178
+ case 'n':
1179
+ if (!e.ctrlKey) {
1019
1180
  addFrame();
1181
+ }
1020
1182
  break;
1021
- case "delete":
1022
- if (sel)
1183
+ case 'delete':
1184
+ if (sel) {
1023
1185
  doDeleteSel();
1024
- else
1186
+ }
1187
+ else {
1025
1188
  clearCv();
1189
+ }
1026
1190
  break;
1027
- case "x": {
1028
- setCol1((c) => { setCol2(c); return col2; });
1191
+ case 'x': {
1192
+ setCol1((c) => {
1193
+ setCol2(c);
1194
+ return col2;
1195
+ });
1029
1196
  break;
1030
1197
  }
1031
- case "[":
1198
+ case '[':
1032
1199
  setBrush((b) => ({ ...b, size: Math.max(1, b.size - 1) }));
1033
1200
  break;
1034
- case "]":
1201
+ case ']':
1035
1202
  setBrush((b) => ({ ...b, size: Math.min(64, b.size + 1) }));
1036
1203
  break;
1037
- case "f":
1204
+ case 'f':
1038
1205
  setShapeFilled((f) => !f);
1039
1206
  break;
1040
1207
  }
1041
1208
  };
1042
- window.addEventListener("keydown", h);
1043
- return () => window.removeEventListener("keydown", h);
1044
- }, [dlgNew, undo, redo, fc, addFrame, clearCv, col2, doCopy, doCut, doPaste, doSelectAll, doDeselectAll, doDeleteSel, sel]);
1209
+ window.addEventListener('keydown', h);
1210
+ return () => window.removeEventListener('keydown', h);
1211
+ }, [
1212
+ dlgNew,
1213
+ undo,
1214
+ redo,
1215
+ fc,
1216
+ addFrame,
1217
+ clearCv,
1218
+ col2,
1219
+ doCopy,
1220
+ doCut,
1221
+ doPaste,
1222
+ doSelectAll,
1223
+ doDeselectAll,
1224
+ doDeleteSel,
1225
+ sel,
1226
+ ]);
1045
1227
  // animation playback
1046
1228
  useEffect(() => {
1047
- if (!playing)
1229
+ if (!playing) {
1048
1230
  return;
1231
+ }
1049
1232
  const iv = setInterval(() => setAfi((f) => (f + 1) % fc), 1000 / fps);
1050
1233
  return () => clearInterval(iv);
1051
1234
  }, [playing, fc, fps]);
1052
1235
  // resize observer
1053
1236
  useEffect(() => {
1054
1237
  const el = boxRef.current;
1055
- if (!el)
1238
+ if (!el) {
1056
1239
  return;
1240
+ }
1057
1241
  const obs = new ResizeObserver(() => setTick((t) => t + 1));
1058
1242
  obs.observe(el);
1059
1243
  return () => obs.disconnect();
@@ -1062,20 +1246,22 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
1062
1246
  const thumbs = useMemo(() => {
1063
1247
  const out = [];
1064
1248
  for (let fi = 0; fi < fc; fi++) {
1065
- const cv = document.createElement("canvas");
1249
+ const cv = document.createElement('canvas');
1066
1250
  cv.width = dw;
1067
1251
  cv.height = dh;
1068
- const ctx = cv.getContext("2d");
1252
+ const ctx = cv.getContext('2d');
1069
1253
  for (let li = 0; li < layers.length; li++) {
1070
- if (!layers[li].visible)
1254
+ if (!layers[li].visible) {
1071
1255
  continue;
1256
+ }
1072
1257
  const c = cels.current.get(celKey(fi, li));
1073
- if (!c)
1258
+ if (!c) {
1074
1259
  continue;
1075
- const t = document.createElement("canvas");
1260
+ }
1261
+ const t = document.createElement('canvas');
1076
1262
  t.width = dw;
1077
1263
  t.height = dh;
1078
- t.getContext("2d").putImageData(c, 0, 0);
1264
+ t.getContext('2d').putImageData(c, 0, 0);
1079
1265
  ctx.globalAlpha = layers[li].opacity / 255;
1080
1266
  ctx.drawImage(t, 0, 0);
1081
1267
  }
@@ -1085,23 +1271,99 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
1085
1271
  }, [fc, dw, dh, layers, tick]);
1086
1272
  /* ── return API ── */
1087
1273
  return {
1088
- dw, dh, layers, aLi, setALi, fc, afi, setAfi, fDur,
1089
- tool, setTool, col1, setCol1, col2, setCol2,
1090
- brush, setBrush, zoom, setZoom, grid, setGrid, onion, setOnion,
1091
- fps, setFps, playing, setPlaying, pal, setPal,
1092
- cursor, setCursor, dlgNew, setDlgNew, nw, setNw, nh, setNh,
1093
- sel, setSel, symmetry, setSymmetry, shapeFilled, setShapeFilled,
1094
- pressure, showHSV, setShowHSV, editingLayerName, setEditingLayerName,
1095
- cvRef, boxRef, fInp, clipboard, drawing, panning,
1096
- undo, redo, openFile,
1097
- exportAse: exportAse$1, exportPNG: exportPNG$1, exportJPG: exportJPG$1, exportWebP: exportWebP$1, exportBMP: exportBMP$1, exportSVG: exportSVG$1, exportSheet: exportSheet$1,
1274
+ dw,
1275
+ dh,
1276
+ layers,
1277
+ aLi,
1278
+ setALi,
1279
+ fc,
1280
+ afi,
1281
+ setAfi,
1282
+ fDur,
1283
+ tool,
1284
+ setTool,
1285
+ col1,
1286
+ setCol1,
1287
+ col2,
1288
+ setCol2,
1289
+ brush,
1290
+ setBrush,
1291
+ zoom,
1292
+ setZoom,
1293
+ grid,
1294
+ setGrid,
1295
+ onion,
1296
+ setOnion,
1297
+ fps,
1298
+ setFps,
1299
+ playing,
1300
+ setPlaying,
1301
+ pal,
1302
+ setPal,
1303
+ cursor,
1304
+ setCursor,
1305
+ dlgNew,
1306
+ setDlgNew,
1307
+ nw,
1308
+ setNw,
1309
+ nh,
1310
+ setNh,
1311
+ sel,
1312
+ setSel,
1313
+ symmetry,
1314
+ setSymmetry,
1315
+ shapeFilled,
1316
+ setShapeFilled,
1317
+ pressure,
1318
+ showHSV,
1319
+ setShowHSV,
1320
+ editingLayerName,
1321
+ setEditingLayerName,
1322
+ cvRef,
1323
+ boxRef,
1324
+ fInp,
1325
+ clipboard,
1326
+ drawing,
1327
+ panning,
1328
+ undo,
1329
+ redo,
1330
+ openFile,
1331
+ exportAse: exportAse$1,
1332
+ exportPNG: exportPNG$1,
1333
+ exportJPG: exportJPG$1,
1334
+ exportWebP: exportWebP$1,
1335
+ exportBMP: exportBMP$1,
1336
+ exportSVG: exportSVG$1,
1337
+ exportSheet: exportSheet$1,
1098
1338
  saveToLibrary,
1099
- addLayer, rmLayer, toggleVis, toggleLock, setLayerOpacity, setLayerBlendMode,
1100
- renameLayer, moveLayerUp, moveLayerDown, mergeDown, dupLayer,
1101
- addFrame, dupFrame, rmFrame,
1102
- flipCv, rotateCv, clearCv, newDoc,
1103
- doCopy, doCut, doPaste, doDeleteSel, doSelectAll, doDeselectAll,
1104
- onDown, onMove, onUp, onWheel,
1339
+ addLayer,
1340
+ rmLayer,
1341
+ toggleVis,
1342
+ toggleLock,
1343
+ setLayerOpacity,
1344
+ setLayerBlendMode,
1345
+ renameLayer,
1346
+ moveLayerUp,
1347
+ moveLayerDown,
1348
+ mergeDown,
1349
+ dupLayer,
1350
+ addFrame,
1351
+ dupFrame,
1352
+ rmFrame,
1353
+ flipCv,
1354
+ rotateCv,
1355
+ clearCv,
1356
+ newDoc,
1357
+ doCopy,
1358
+ doCut,
1359
+ doPaste,
1360
+ doDeleteSel,
1361
+ doSelectAll,
1362
+ doDeselectAll,
1363
+ onDown,
1364
+ onMove,
1365
+ onUp,
1366
+ onWheel,
1105
1367
  thumbs,
1106
1368
  importImageData: useCallback((img) => {
1107
1369
  snap('import generator');
@@ -1117,7 +1379,7 @@ function usePixelEditor({ initialWidth = 64, initialHeight = 64, onSaveToLibrary
1117
1379
  ctx.drawImage(src, 0, 0);
1118
1380
  const merged = ctx.getImageData(0, 0, dw, dh);
1119
1381
  cel.data.set(merged.data);
1120
- setTick(t => t + 1);
1382
+ setTick((t) => t + 1);
1121
1383
  }, [snap, getCel, afi, aLi, dw, dh]),
1122
1384
  };
1123
1385
  }