M8.6: Puppet Warp pins appear at once, warp from the rest shape and follow Undo

- Pins show as soon as the tool has art selected: automatic ones at the
  centre and the middle of each limb's end (at least three), until pins are
  placed. They stay across tool switches while the selection is unchanged and
  a new selection starts afresh.
- The pins live in the document (Document.puppet, never saved) with the rest
  shape they started from: every warp starts from it, so warps don't stack and
  dragging a pin back restores the original; Undo/Redo take the pins back with
  the art. Adding and deleting pins are undo steps too.
- object.puppetWarp gains rest: true (the tool's pins); the new query
  object.puppetWarp.pins reads them. A click off the mesh adds nothing and
  says so (not-allowed cursor, canvas label); the command refuses such pins.
- The mesh grid covers the expanded art, so tiny art with a wide Expand no
  longer allocates millions of cells.
- Tests on groups, compound paths and open strokes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-06 11:16:10 +07:00
co-authored by Claude Opus 5.5
parent 47ef223a02
commit 117aa0b5a3
12 changed files with 1115 additions and 263 deletions
+12
View File
@@ -879,6 +879,18 @@ on the art) lands on its `moved` point. `angles` (degrees, or null for a free pi
the art takes around a pin, as Alt-dragging near a selected pin with the Puppet Warp tool does: one pin with
`angles: [90]` turns the art a quarter turn around it.
The Puppet Warp tool's pins live in the document while the same art stays selected (never saved; Undo and Redo take
them back with the art). `object.puppetWarp.pins {ids?}` reads them: `pins` (where each sits on the shape the pins
started from), `moved` (where it is now), `angles`, and `auto: true` while none was placed (the tool's automatic pins:
the centre and the end of each limb). Edit `moved`, `angles` or the lists and pass the result back to
`object.puppetWarp`: with `rest: true` the warp always starts from that rest shape, so warps don't stack and putting
a pin back restores the original; every pin must be on the art's mesh, and empty lists remove the pins.
```json
{"name":"run_command","arguments":{"command":"object.puppetWarp.pins","params":{}}}
{"name":"run_command","arguments":{"command":"object.puppetWarp","params":{"rest":true,"pins":[[250,150],[110,150],[390,150]],"moved":[[250,150],[110,150],[390,90]],"angles":[null,null,null]}}}
```
```json
{"name":"run_command","arguments":{"command":"stroke.widthPoint.set","params":{"id":9,"t":0.5,"left":4,"right":4}}}
{"name":"run_command","arguments":{"command":"stroke.widthPoint.set","params":{"id":9,"t":0.8,"left":12,"right":12}}}