-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Feat(canvas): Replace Rectangle tool with new Shapes tool #9082
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
lstein
merged 41 commits into
invoke-ai:main
from
DustyShoe:Feat(Canvas)/Replace-Rectangle-tool-with-Shapes-tool
May 14, 2026
Merged
Changes from 35 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
c49fee9
Feat(Canvas): Replace Rectangle tool with multifunctional Shapes tool.
DustyShoe bc68c59
Fix: Tweaked icon size on top bar
DustyShoe 708ba51
Fix: also tweaked SVGs for Gradient tool to align with unified 16px i…
DustyShoe 890d151
Feat: added freehand shape
DustyShoe 58bdb0d
fix(canvas): remove duplicate lasso payload export after rebase
DustyShoe 9ad8225
Merge branch 'invoke-ai:main' into Feat(Canvas)/Replace-Rectangle-too…
DustyShoe dd0dd20
Merge branch 'invoke-ai:main' into Feat(Canvas)/Replace-Rectangle-too…
DustyShoe d282020
Merge branch 'invoke-ai:main' into Feat(Canvas)/Replace-Rectangle-too…
DustyShoe 9a696b1
Merge branch 'invoke-ai:main' into Feat(Canvas)/Replace-Rectangle-too…
DustyShoe 9102fea
Merge branch 'invoke-ai:main' into Feat(Canvas)/Replace-Rectangle-too…
DustyShoe 4c25e9b
`fix(canvas): clear polygon preview stroke on commit`
DustyShoe d787f15
Merge branch 'invoke-ai:main' into Feat(Canvas)/Replace-Rectangle-too…
DustyShoe 4e18f1a
chore: remove temporary codex artifact
DustyShoe 2b6f11e
chore: format with prettier
DustyShoe 15c9252
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 4bd2593
fix(canvas): preserve shapes sessions across view switch
DustyShoe 29ae589
chore: format with prettier
DustyShoe 6d454d6
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe b1bc708
add: constrain rectangles to squares with shift
DustyShoe b877fc5
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 410f7c7
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 6affa7d
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe e157110
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 3b39f54
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 4eb10ba
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
Pfannkuchensack 9c338f2
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 1b0a379
fix(canvas): refine shapes space and alt interactions
DustyShoe 4a1d12c
fix(canvas): preserve polygon sessions across temporary tool switches
DustyShoe 47af75b
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 712000e
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 8f0ac11
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
Pfannkuchensack c0823c5
refactor(i18n): reuse lasso labels for shapes polygon modes
DustyShoe 7f41786
fix(i18n): merge shapes locale additions with modifier hints
DustyShoe a00fb5a
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe ae6f858
feat(canvas): add shape-specific modifier hints and docs
DustyShoe ecd7293
fix(canvas): refine shape modifier hints and toolbar overflow
DustyShoe 9068da7
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe e5a0f85
fix(canvas): keep toolbar overflow clipped to the right
DustyShoe 3a6a160
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe d8a8e0e
Merge branch 'main' into Feat(Canvas)/Replace-Rectangle-tool-with-Sha…
DustyShoe 69ba743
fix: Escape while panning while drawing should exit shape tool
dunkeroni File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| --- | ||
| title: Shapes Tool | ||
| description: Learn how to draw filled shapes on raster and inpaint mask layers with the Shapes tool. | ||
| lastUpdated: 2026-05-11 | ||
| --- | ||
|
|
||
| import { Card, CardGrid } from '@astrojs/starlight/components'; | ||
|
|
||
| The Shapes tool is a general-purpose filled-shape drawing tool for the canvas. It replaces the old Rectangle tool and | ||
| adds four shape modes under a single toolbar button: | ||
|
|
||
| - **Rect** | ||
| - **Oval** | ||
| - **Polygon** | ||
| - **Freehand** | ||
|
|
||
| You can activate the Shapes tool from the canvas toolbar or with the default hotkey <kbd>U</kbd>. | ||
|
|
||
| ## Where Shapes Draws | ||
|
|
||
| Shapes always draws into the **active raster target**: | ||
|
|
||
| - On a regular raster layer, Shapes adds filled pixels to that layer. | ||
| - On an active inpaint mask layer, Shapes draws directly into the mask. | ||
|
|
||
| :::note | ||
| Shapes overlaps with some Lasso workflows on mask layers, but the tools are not identical. Lasso is still the more | ||
| specialized masking tool and can create a new mask layer automatically when one does not already exist. | ||
| ::: | ||
|
|
||
| ## Common Behavior | ||
|
|
||
| - Shapes preview live while you draw. | ||
| - The fill color uses the current active color. | ||
| - The active color's alpha is respected when adding pixels. | ||
| - Hold <kbd>Ctrl</kbd> on Windows/Linux or <kbd>Cmd</kbd> on macOS to switch to **subtractive** mode and cut pixels | ||
| out of the active layer. | ||
| - In subtractive mode, alpha is ignored and the shape fully clears pixels. | ||
| - Press <kbd>Esc</kbd> to cancel the current shape session. | ||
|
|
||
| :::tip | ||
| When subtractive mode is active, the canvas cursor shows a small minus badge so you can tell at a glance that the next | ||
| shape will erase instead of fill. | ||
| ::: | ||
|
|
||
| ## Shape Modes | ||
|
|
||
| <CardGrid> | ||
| <Card title="Rect"> | ||
| Drag to draw a rectangle. Hold <kbd>Shift</kbd> to constrain to a square. Hold <kbd>Alt</kbd> to draw from the | ||
| center instead of from a corner. | ||
| </Card> | ||
| <Card title="Oval"> | ||
| Drag to draw an ellipse. Hold <kbd>Shift</kbd> to constrain to a perfect circle. Hold <kbd>Alt</kbd> to draw from | ||
| the center. | ||
| </Card> | ||
| <Card title="Polygon"> | ||
| Click to place vertices. Click the first point to close and commit the shape. Hold <kbd>Shift</kbd> to snap the | ||
| pending edge to horizontal, vertical, and 45 degree angles. | ||
| </Card> | ||
| <Card title="Freehand"> | ||
| Click and drag to sketch a filled freehand contour. Release the pointer to commit the shape. | ||
| </Card> | ||
| </CardGrid> | ||
|
|
||
| ## Moving and Panning During Drawing | ||
|
|
||
| The Shapes tool supports different <kbd>Space</kbd> behavior depending on the current mode: | ||
|
|
||
| - **Rect / Oval:** While the pointer is still down, hold <kbd>Space</kbd> to move the uncommitted shape instead of | ||
| resizing it. Release <kbd>Space</kbd> to continue resizing. | ||
| - **Polygon / Freehand:** Hold <kbd>Space</kbd> during an active session to pan the viewport without discarding the | ||
| unfinished shape. | ||
|
|
||
| This is especially useful when drawing large shapes that extend beyond the current viewport. | ||
|
|
||
| ## Color Picking While Using Shapes | ||
|
|
||
| The <kbd>Alt</kbd> key behaves differently depending on the active Shapes mode: | ||
|
|
||
| - **Rect / Oval:** Before you start dragging, <kbd>Alt</kbd> can be used for the temporary color-picker quick-switch. | ||
| Once a drag is active, <kbd>Alt</kbd> is reserved for drawing from the center. | ||
| - **Polygon:** <kbd>Alt</kbd> remains available for the temporary color-picker quick-switch between vertex placements. | ||
| - **Freehand:** <kbd>Alt</kbd> is available before the stroke starts, but not during an active stroke. | ||
|
|
||
| ## Practical Examples | ||
|
|
||
| - Use **Rect** or **Oval** to block in clean mask regions quickly. | ||
| - Use **Polygon** when you need straight edges and deliberate corner placement. | ||
| - Use **Freehand** for irregular organic regions. | ||
| - Use **subtractive mode** to cut holes back out of an existing raster or mask layer. | ||
|
|
||
| ## Summary | ||
|
|
||
| The Shapes tool is the fastest way to add filled geometric or freeform regions to canvas layers. Use it for structured | ||
| fills, mask authoring, and precise subtractive edits without switching away from the current raster target. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
invokeai/frontend/web/src/features/controlLayers/components/Tool/ToolShapeTypeToggle.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import { ButtonGroup, IconButton, Tooltip } from '@invoke-ai/ui-library'; | ||
| import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; | ||
| import { selectShapeType, settingsShapeTypeChanged } from 'features/controlLayers/store/canvasSettingsSlice'; | ||
| import { memo, useCallback } from 'react'; | ||
| import { useTranslation } from 'react-i18next'; | ||
| import { PiCircleBold, PiPolygonBold, PiRectangleBold, PiScribbleLoopBold } from 'react-icons/pi'; | ||
|
|
||
| export const ToolShapeTypeToggle = memo(() => { | ||
| const { t } = useTranslation(); | ||
| const shapeType = useAppSelector(selectShapeType); | ||
| const dispatch = useAppDispatch(); | ||
|
|
||
| const onRectClick = useCallback(() => dispatch(settingsShapeTypeChanged('rect')), [dispatch]); | ||
| const onOvalClick = useCallback(() => dispatch(settingsShapeTypeChanged('oval')), [dispatch]); | ||
| const onPolygonClick = useCallback(() => dispatch(settingsShapeTypeChanged('polygon')), [dispatch]); | ||
| const onFreehandClick = useCallback(() => dispatch(settingsShapeTypeChanged('freehand')), [dispatch]); | ||
|
|
||
| const rectLabel = t('controlLayers.shape.rect', { defaultValue: 'Rect' }); | ||
| const ovalLabel = t('controlLayers.shape.oval', { defaultValue: 'Oval' }); | ||
| const polygonLabel = t('controlLayers.lasso.polygon', { defaultValue: 'Polygon' }); | ||
| const freehandLabel = t('controlLayers.lasso.freehand', { defaultValue: 'Freehand' }); | ||
|
|
||
| return ( | ||
| <ButtonGroup isAttached size="sm"> | ||
| <Tooltip label={rectLabel}> | ||
| <IconButton | ||
| aria-label={rectLabel} | ||
| icon={<PiRectangleBold />} | ||
| colorScheme={shapeType === 'rect' ? 'invokeBlue' : 'base'} | ||
| variant="solid" | ||
| onClick={onRectClick} | ||
| /> | ||
| </Tooltip> | ||
| <Tooltip label={ovalLabel}> | ||
| <IconButton | ||
| aria-label={ovalLabel} | ||
| icon={<PiCircleBold />} | ||
| colorScheme={shapeType === 'oval' ? 'invokeBlue' : 'base'} | ||
| variant="solid" | ||
| onClick={onOvalClick} | ||
| /> | ||
| </Tooltip> | ||
| <Tooltip label={polygonLabel}> | ||
| <IconButton | ||
| aria-label={polygonLabel} | ||
| icon={<PiPolygonBold />} | ||
| colorScheme={shapeType === 'polygon' ? 'invokeBlue' : 'base'} | ||
| variant="solid" | ||
| onClick={onPolygonClick} | ||
| /> | ||
| </Tooltip> | ||
| <Tooltip label={freehandLabel}> | ||
| <IconButton | ||
| aria-label={freehandLabel} | ||
| icon={<PiScribbleLoopBold />} | ||
| colorScheme={shapeType === 'freehand' ? 'invokeBlue' : 'base'} | ||
| variant="solid" | ||
| onClick={onFreehandClick} | ||
| /> | ||
| </Tooltip> | ||
| </ButtonGroup> | ||
| ); | ||
| }); | ||
|
|
||
| ToolShapeTypeToggle.displayName = 'ToolShapeTypeToggle'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.