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