@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
|
@@ -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
|
-
{
|
|
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(
|
|
27
|
-
const [col1, setCol1] = useState(
|
|
28
|
-
const [col2, setCol2] = useState(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 !==
|
|
154
|
+
if (bm !== 'normal') {
|
|
142
155
|
ctx.globalCompositeOperation = bm;
|
|
143
156
|
}
|
|
144
157
|
else {
|
|
145
|
-
ctx.globalCompositeOperation =
|
|
158
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
146
159
|
}
|
|
147
160
|
ctx.drawImage(t, 0, 0);
|
|
148
161
|
}
|
|
149
|
-
ctx.globalCompositeOperation =
|
|
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(
|
|
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 ?
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 !==
|
|
226
|
+
if (bm !== 'normal') {
|
|
208
227
|
cc.globalCompositeOperation = bm;
|
|
209
228
|
}
|
|
210
229
|
else {
|
|
211
|
-
cc.globalCompositeOperation =
|
|
230
|
+
cc.globalCompositeOperation = 'source-over';
|
|
212
231
|
}
|
|
213
232
|
cc.drawImage(t, 0, 0);
|
|
214
233
|
}
|
|
215
|
-
cc.globalCompositeOperation =
|
|
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 ===
|
|
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 ===
|
|
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
|
-
|
|
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
|
-
|
|
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 ===
|
|
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 ===
|
|
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(
|
|
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 !==
|
|
269
|
-
ctx.strokeStyle =
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 &&
|
|
325
|
-
|
|
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 =
|
|
358
|
+
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
|
|
328
359
|
ctx.lineWidth = 1 / zoom;
|
|
329
|
-
if (brush.shape ===
|
|
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
|
-
}, [
|
|
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 ===
|
|
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
|
|
374
|
-
case
|
|
375
|
-
case
|
|
376
|
-
snap(tool ===
|
|
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 ===
|
|
432
|
+
applyBrushAt(p.x, p.y, tool === 'eraser', pr);
|
|
381
433
|
setTick((t) => t + 1);
|
|
382
434
|
break;
|
|
383
|
-
case
|
|
435
|
+
case 'fill':
|
|
384
436
|
if (inB(p.x, p.y, dw, dh)) {
|
|
385
|
-
snap(
|
|
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
|
|
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
|
-
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
404
457
|
setCol1(hex);
|
|
458
|
+
}
|
|
405
459
|
}
|
|
406
460
|
break;
|
|
407
461
|
}
|
|
408
|
-
case
|
|
409
|
-
case
|
|
410
|
-
case
|
|
411
|
-
case
|
|
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
|
|
471
|
+
case 'select':
|
|
418
472
|
drawing.current = true;
|
|
419
473
|
tStart.current = p;
|
|
420
474
|
break;
|
|
421
|
-
case
|
|
475
|
+
case 'move':
|
|
422
476
|
drawing.current = true;
|
|
423
477
|
lastPx.current = p;
|
|
424
478
|
break;
|
|
425
479
|
}
|
|
426
|
-
}, [
|
|
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
|
-
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
562
|
+
if (tool === 'line' && tStart.current) {
|
|
490
563
|
const cel = getCel(afi, aLi);
|
|
491
564
|
getSymmetryPoints(0, 0, dw, dh, symmetry);
|
|
492
|
-
if (symmetry ===
|
|
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 ===
|
|
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
|
-
|
|
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
|
-
|
|
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 ===
|
|
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 ===
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
707
|
+
blendMode: 'normal',
|
|
614
708
|
}));
|
|
615
709
|
setLayers(lrs.length
|
|
616
710
|
? lrs
|
|
617
|
-
: [
|
|
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],
|
|
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(
|
|
657
|
-
|
|
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(
|
|
666
|
-
const data = cv.getContext(
|
|
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([
|
|
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(
|
|
829
|
+
const cv = document.createElement('canvas');
|
|
712
830
|
cv.width = dw;
|
|
713
831
|
cv.height = dh;
|
|
714
|
-
cv.getContext(
|
|
715
|
-
const dataUrl = cv.toDataURL(
|
|
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(
|
|
718
|
-
if (!name || !name.trim())
|
|
835
|
+
const name = window.prompt('Save to library as:', defaultName);
|
|
836
|
+
if (!name || !name.trim()) {
|
|
719
837
|
return;
|
|
720
|
-
|
|
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(
|
|
843
|
+
snap('Add Layer');
|
|
725
844
|
setLayers((ls) => [
|
|
726
845
|
...ls,
|
|
727
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
911
|
+
}
|
|
912
|
+
else {
|
|
784
913
|
cels.current.delete(celKey(fi, aLi + 1));
|
|
785
|
-
|
|
914
|
+
}
|
|
915
|
+
if (b) {
|
|
786
916
|
cels.current.set(celKey(fi, aLi), b);
|
|
787
|
-
|
|
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
|
-
|
|
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
|
-
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
808
942
|
cels.current.delete(celKey(fi, aLi - 1));
|
|
809
|
-
|
|
943
|
+
}
|
|
944
|
+
if (b) {
|
|
810
945
|
cels.current.set(celKey(fi, aLi), b);
|
|
811
|
-
|
|
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
|
-
|
|
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(
|
|
964
|
+
const ctx = cv.getContext('2d');
|
|
827
965
|
ctx.putImageData(bot, 0, 0);
|
|
828
966
|
const t = new OffscreenCanvas(dw, dh);
|
|
829
|
-
t.getContext(
|
|
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(
|
|
851
|
-
const newL = { ...layers[aLi], id: lid(), name: layers[aLi].name +
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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 ===
|
|
911
|
-
cels.current.forEach((c, k) => cels.current.set(k, dir ===
|
|
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(
|
|
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(
|
|
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([
|
|
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 ===
|
|
1108
|
+
if (tgt.tagName === 'INPUT' || tgt.tagName === 'TEXTAREA' || tgt.tagName === 'SELECT') {
|
|
958
1109
|
return;
|
|
959
|
-
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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:
|
|
996
|
-
|
|
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
|
|
1172
|
+
case 'arrowleft':
|
|
1012
1173
|
setAfi((f) => Math.max(0, f - 1));
|
|
1013
1174
|
break;
|
|
1014
|
-
case
|
|
1175
|
+
case 'arrowright':
|
|
1015
1176
|
setAfi((f) => Math.min(fc - 1, f + 1));
|
|
1016
1177
|
break;
|
|
1017
|
-
case
|
|
1018
|
-
if (!e.ctrlKey)
|
|
1178
|
+
case 'n':
|
|
1179
|
+
if (!e.ctrlKey) {
|
|
1019
1180
|
addFrame();
|
|
1181
|
+
}
|
|
1020
1182
|
break;
|
|
1021
|
-
case
|
|
1022
|
-
if (sel)
|
|
1183
|
+
case 'delete':
|
|
1184
|
+
if (sel) {
|
|
1023
1185
|
doDeleteSel();
|
|
1024
|
-
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1025
1188
|
clearCv();
|
|
1189
|
+
}
|
|
1026
1190
|
break;
|
|
1027
|
-
case
|
|
1028
|
-
setCol1((c) => {
|
|
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
|
|
1204
|
+
case 'f':
|
|
1038
1205
|
setShapeFilled((f) => !f);
|
|
1039
1206
|
break;
|
|
1040
1207
|
}
|
|
1041
1208
|
};
|
|
1042
|
-
window.addEventListener(
|
|
1043
|
-
return () => window.removeEventListener(
|
|
1044
|
-
}, [
|
|
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(
|
|
1249
|
+
const cv = document.createElement('canvas');
|
|
1066
1250
|
cv.width = dw;
|
|
1067
1251
|
cv.height = dh;
|
|
1068
|
-
const ctx = cv.getContext(
|
|
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
|
-
|
|
1260
|
+
}
|
|
1261
|
+
const t = document.createElement('canvas');
|
|
1076
1262
|
t.width = dw;
|
|
1077
1263
|
t.height = dh;
|
|
1078
|
-
t.getContext(
|
|
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,
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
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,
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
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
|
}
|