Vector Art: Formen und Gruppen drehen, skalieren und spiegeln #291

Closed
opened 2026-10-01 22:57:49 +02:00 by meleki · 2 comments
Owner

Folge-Issue zu #190 („Vector Art: Gruppen und Layers“). Dort steht unter den eigenen Festlegungen: Eine Gruppe hat keine eigene Transformation, Drehen und Skalieren mehrerer Formen gibt es nicht. Der User will das jetzt haben, für einzelne Formen und für Gruppen.

Stand heute

  • Eine Form lässt sich im Vector-Art-Tab nur verschieben (Druck in die Füllung oder auf die Linie) und Punkt für Punkt umformen.
  • Seit #190 zieht ein Druck auf eine Form die ganze äußerste Gruppe mit, und eine Mehrfachauswahl zieht gemeinsam. Auch das ist nur Verschieben.
  • Drehen, Skalieren und Spiegeln gibt es nicht, weder für eine Form noch für mehrere. Wer eine Form größer haben will, zieht heute jeden Punkt einzeln.
  • Das Modell kennt keine Transformation: Eine Form ist ihre Ringe aus Punkten und Griffen (src/core/model/vectorPath.ts), eine Gruppe nur ein Knoten im Baum (src/core/model/vectorTree.ts).

Zu bauen (Vorschlag)

  • Rahmen um die Auswahl: Mit dem Werkzeug Select zeigt die Auswahl (eine Form, mehrere Formen, eine Gruppe) einen Rahmen um ihre gemeinsame Bounding Box, mit acht Griffen zum Skalieren und einem Drehgriff darüber.
  • Skalieren: Ein Eckgriff skaliert um die gegenüberliegende Ecke, ein Seitengriff nur in einer Richtung. Shift hält die Proportionen, Alt skaliert um die Mitte.
  • Drehen: Der Drehgriff dreht um die Mitte des Rahmens. Shift rastet in 15°-Schritten ein.
  • Spiegeln: Zwei Knöpfe im Inspector (Flip horizontal, Flip vertical), um die Mitte des Rahmens.
  • Zahlen im Inspector: Zeilen für Position, Größe und Drehung der Auswahl, zum Eintippen und Scrubben.
  • Die Transformation wird eingebacken: Die Punkte und Griffe aller betroffenen Formen werden umgerechnet, das Modell bekommt keine eigene Matrix. So bleiben Boolean-Operationen (#187), das Bild für Sprites und der Collider-Umriss (#188) unverändert.
  • Füllungen gehen mit: Verläufe und Texturkacheln werden mit transformiert, wie heute beim Verschieben.
  • Eine Geste ist ein Undo-Schritt, auch über mehrere Formen. Die Vorschau läuft wie beim Verschieben einmal pro Frame (#274).
  • Die Regel (Punkte, Griffe und Füllung unter einer affinen Abbildung) als reine Funktion in src/core/model/, ein Command darüber für eine Liste von Formen.

Übernommen aus #217

#217 („mehrere gewählte Formen gemeinsam verschieben“) ist geschlossen: Das gemeinsame Ziehen ist mit #190 gebaut (2ff3a78), samt Verläufen, Texturkacheln, Einrasten des gemeinsamen Versatzes und einem Undo-Schritt. Was davon übrig ist, gehört hierher:

  • e2e für die Mehrfachauswahl ohne Gruppe: zwei Formen wählen, eine ziehen, beide haben sich um denselben Betrag bewegt. Heute prüft Modul 47 das nur für eine Gruppe, den Fall ohne Gruppe nur ein Unit-Test.
  • Tests für das Einrasten des gemeinsamen Versatzes (Magnet, #194) und für Verläufe und Texturkacheln der mitgezogenen Formen. Beides ist gebaut, hat aber keinen eigenen Test.
  • Der Rahmen dieses Issues gilt für dieselbe Auswahl: Was beim Ziehen gemeinsam geht (Mehrfachauswahl, Gruppe, Formen aus mehreren Gruppen), wird auch gemeinsam skaliert, gedreht und gespiegelt.
  • Verschieben per Zahl: Die Positionszeilen im Inspector (oben unter „Zahlen im Inspector“) verschieben die ganze Auswahl. Das ist der Teil, den #217 mit den Pfeiltasten offen gelassen hat, siehe Frage 6.

Offene Fragen

  1. Eingebacken oder eigene Transformation? Vorschlag oben: eingebacken. Die Alternative wäre eine Matrix an Form und Gruppe, die erst beim Zeichnen angewandt wird. Dann bliebe „Drehung 30°“ im Inspector stehen und ließe sich zurücknehmen, aber jede Stelle, die Punkte liest (Boolean, Collider-Umriss, Treffertest, Einrasten), müsste sie kennen.
  2. Was zeigt die Zeile Rotation nach dem Drehen? Bei eingebackener Transformation wieder 0, weil der Rahmen immer achsparallel ist. Reicht das, oder soll die Drehung einer Form gemerkt werden?
  3. Rahmen und Punkte zugleich? Heute zeigt die zuletzt geklickte Form ihre Punkte und Griffe. Vorschlag: Der Rahmen kommt dazu, die Punkte gewinnen beim Treffer. Die Alternative ist ein eigenes Werkzeug Transform neben Select, Pen und Paint.
  4. Linienstärke: Skaliert sie mit oder bleibt sie? Vorschlag: bleibt, mit einem Schalter Scale stroke im Inspector.
  5. Einzelne Form in einer Gruppe: Über ihre Zeile in der Liste gewählt, bekommt sie ihren eigenen Rahmen. Passt das?
  6. Pfeiltasten zum Verschieben der Auswahl: hier mit? In #217 war die Antwort „nicht in diesem Issue, auch kein Folge-Issue notwendig“. Die Frage steht hier nur noch einmal, weil die Auswahl jetzt ohnehin Positionszeilen bekommt. Vorschlag: bleibt draußen, solange du nichts anderes sagst.

Tests (Vorschlag)

  • Unit für die reine Funktion: Skalieren um eine Ecke, Drehen um 90° (Punkte und Griffe exakt), Spiegeln kehrt die Umlaufrichtung nicht sichtbar um (Füllregel bleibt), Verlauf und Texturkachel gehen mit.
  • Unit für den Command: mehrere Formen, eine Gruppe, zwei Ebenen in einer Auswahl, ein Undo-Schritt.
  • e2e in Modul 47 mit echter Maus: Eckgriff ziehen, Drehgriff ziehen, mit Shift. Dazu eine Pixelprobe im Bild eines Sprites, das die Zeichnung trägt, und ein Screenshot des Rahmens, angesehen.
  • Gegenprobe je Regel.
Folge-Issue zu #190 („Vector Art: Gruppen und Layers“). Dort steht unter den eigenen Festlegungen: Eine Gruppe hat keine eigene Transformation, Drehen und Skalieren mehrerer Formen gibt es nicht. Der User will das jetzt haben, für einzelne Formen und für Gruppen. ## Stand heute - Eine Form lässt sich im Vector-Art-Tab nur **verschieben** (Druck in die Füllung oder auf die Linie) und Punkt für Punkt umformen. - Seit #190 zieht ein Druck auf eine Form die ganze äußerste Gruppe mit, und eine Mehrfachauswahl zieht gemeinsam. Auch das ist nur Verschieben. - **Drehen, Skalieren und Spiegeln gibt es nicht**, weder für eine Form noch für mehrere. Wer eine Form größer haben will, zieht heute jeden Punkt einzeln. - Das Modell kennt keine Transformation: Eine Form ist ihre Ringe aus Punkten und Griffen (`src/core/model/vectorPath.ts`), eine Gruppe nur ein Knoten im Baum (`src/core/model/vectorTree.ts`). ## Zu bauen (Vorschlag) - **Rahmen um die Auswahl:** Mit dem Werkzeug *Select* zeigt die Auswahl (eine Form, mehrere Formen, eine Gruppe) einen Rahmen um ihre gemeinsame Bounding Box, mit acht Griffen zum Skalieren und einem Drehgriff darüber. - **Skalieren:** Ein Eckgriff skaliert um die gegenüberliegende Ecke, ein Seitengriff nur in einer Richtung. `Shift` hält die Proportionen, `Alt` skaliert um die Mitte. - **Drehen:** Der Drehgriff dreht um die Mitte des Rahmens. `Shift` rastet in 15°-Schritten ein. - **Spiegeln:** Zwei Knöpfe im Inspector (*Flip horizontal*, *Flip vertical*), um die Mitte des Rahmens. - **Zahlen im Inspector:** Zeilen für Position, Größe und Drehung der Auswahl, zum Eintippen und Scrubben. - **Die Transformation wird eingebacken:** Die Punkte und Griffe aller betroffenen Formen werden umgerechnet, das Modell bekommt keine eigene Matrix. So bleiben Boolean-Operationen (#187), das Bild für Sprites und der Collider-Umriss (#188) unverändert. - **Füllungen gehen mit:** Verläufe und Texturkacheln werden mit transformiert, wie heute beim Verschieben. - **Eine Geste ist ein Undo-Schritt**, auch über mehrere Formen. Die Vorschau läuft wie beim Verschieben einmal pro Frame (#274). - Die Regel (Punkte, Griffe und Füllung unter einer affinen Abbildung) als reine Funktion in `src/core/model/`, ein Command darüber für eine Liste von Formen. ## Übernommen aus #217 #217 („mehrere gewählte Formen gemeinsam verschieben“) ist geschlossen: Das gemeinsame Ziehen ist mit #190 gebaut (`2ff3a78`), samt Verläufen, Texturkacheln, Einrasten des gemeinsamen Versatzes und einem Undo-Schritt. Was davon übrig ist, gehört hierher: - **e2e für die Mehrfachauswahl ohne Gruppe:** zwei Formen wählen, eine ziehen, beide haben sich um denselben Betrag bewegt. Heute prüft Modul 47 das nur für eine Gruppe, den Fall ohne Gruppe nur ein Unit-Test. - **Tests für das Einrasten des gemeinsamen Versatzes** (Magnet, #194) und für **Verläufe und Texturkacheln der mitgezogenen Formen**. Beides ist gebaut, hat aber keinen eigenen Test. - **Der Rahmen dieses Issues gilt für dieselbe Auswahl:** Was beim Ziehen gemeinsam geht (Mehrfachauswahl, Gruppe, Formen aus mehreren Gruppen), wird auch gemeinsam skaliert, gedreht und gespiegelt. - **Verschieben per Zahl:** Die Positionszeilen im Inspector (oben unter „Zahlen im Inspector“) verschieben die ganze Auswahl. Das ist der Teil, den #217 mit den Pfeiltasten offen gelassen hat, siehe Frage 6. ## Offene Fragen 1. **Eingebacken oder eigene Transformation?** Vorschlag oben: eingebacken. Die Alternative wäre eine Matrix an Form und Gruppe, die erst beim Zeichnen angewandt wird. Dann bliebe „Drehung 30°“ im Inspector stehen und ließe sich zurücknehmen, aber jede Stelle, die Punkte liest (Boolean, Collider-Umriss, Treffertest, Einrasten), müsste sie kennen. 2. **Was zeigt die Zeile *Rotation* nach dem Drehen?** Bei eingebackener Transformation wieder 0, weil der Rahmen immer achsparallel ist. Reicht das, oder soll die Drehung einer Form gemerkt werden? 3. **Rahmen und Punkte zugleich?** Heute zeigt die zuletzt geklickte Form ihre Punkte und Griffe. Vorschlag: Der Rahmen kommt dazu, die Punkte gewinnen beim Treffer. Die Alternative ist ein eigenes Werkzeug *Transform* neben *Select*, *Pen* und *Paint*. 4. **Linienstärke:** Skaliert sie mit oder bleibt sie? Vorschlag: bleibt, mit einem Schalter *Scale stroke* im Inspector. 5. **Einzelne Form in einer Gruppe:** Über ihre Zeile in der Liste gewählt, bekommt sie ihren eigenen Rahmen. Passt das? 6. **Pfeiltasten** zum Verschieben der Auswahl: hier mit? In #217 war die Antwort „nicht in diesem Issue, auch kein Folge-Issue notwendig“. Die Frage steht hier nur noch einmal, weil die Auswahl jetzt ohnehin Positionszeilen bekommt. Vorschlag: bleibt draußen, solange du nichts anderes sagst. ## Tests (Vorschlag) - Unit für die reine Funktion: Skalieren um eine Ecke, Drehen um 90° (Punkte und Griffe exakt), Spiegeln kehrt die Umlaufrichtung nicht sichtbar um (Füllregel bleibt), Verlauf und Texturkachel gehen mit. - Unit für den Command: mehrere Formen, eine Gruppe, zwei Ebenen in einer Auswahl, ein Undo-Schritt. - e2e in Modul 47 mit echter Maus: Eckgriff ziehen, Drehgriff ziehen, mit `Shift`. Dazu eine Pixelprobe im Bild eines Sprites, das die Zeichnung trägt, und ein Screenshot des Rahmens, angesehen. - Gegenprobe je Regel.
admin added the question label 2026-10-01 23:00:46 +02:00
admin added this to the Development project 2026-10-01 23:00:50 +02:00
admin moved this to Next in Development on 2026-10-02 10:19:06 +02:00
  1. ja, machen wir eingebacken
  2. die drehung einer form brauch man sich nicht merken, auch generell jegliche transformationen müssen nicht gespeichert werden (position, scale)
  3. ja, rahmen soll dazu kommen, wie bei scene objects
  4. linienstärke bleibt (wird nicht mitskaliert)
  5. vorschlag passt
  6. pfeiltasten bleibt draußen
1. ja, machen wir eingebacken 2. die drehung einer form brauch man sich nicht merken, auch generell jegliche transformationen müssen nicht gespeichert werden (position, scale) 3. ja, rahmen soll dazu kommen, wie bei scene objects 4. linienstärke bleibt (wird nicht mitskaliert) 5. vorschlag passt 6. pfeiltasten bleibt draußen
admin removed the question label 2026-10-02 10:32:45 +02:00
Author
Owner

Done in 3452899, wiki 9657f11 (Vector Art, Keyboard, Development).

What changes
Following the six answers above: baked in, nothing remembered, a frame as on scene objects, the line width stays, a single shape of a group gets its own frame, no arrow keys.

  • A frame round the selection. With Select the selection (one shape, several shapes, a group) stands in a frame of eight squares and a knob, drawn like the one of the scene view.
  • Scaling. A corner square scales from the opposite corner, a square on an edge only in its own direction. Shift keeps the proportions, Alt scales about the middle.
  • Turning. The knob turns round the middle of the frame, with Shift in steps of 15 degrees.
  • Inspector. A new band TRANSFORM with X, Y, Width, Height and Rotate by, below them Flip horizontal and Flip vertical. The numbers can be typed or scrubbed.
  • Baked in. Points, handles, gradients and texture tiles are converted, nothing is remembered. After a turn the frame stands upright again and Rotate by shows 0.
  • The line width stays.
  • One pull, one number, one flip is one undo step, whatever the number of shapes.

Decided here

  • The frame stands 15 pixels off the shapes. The points of a shape lie exactly on its bounds, on the corners for a square. A handle on the bounds would lie on a point. This departs from "as on scene objects".
  • The knob only turns. In the scene view it scales as well, here the squares do that.
  • No mirroring by pulling. A side cannot be pulled through the opposite one, the frame keeps at least 1 pixel.
  • Coordinates are rounded to a thousandth of a pixel. A quarter turn is exact that way, and the file stays readable.
  • A texture fill under a turn: the tile stays upright and grows to the bounds of the turned tile, the picture itself does not turn.
  • A gradient under an uneven scale: both ends go along, the bands stay square to the axis.
  • X and Y are the top left corner of the frame, Width and Height stretch from there.
  • The switch Scale stroke of the proposal is not built, the answer was "stays".

Taken over from #217

  • The e2e check for two selected shapes without a group (block 47k).
  • Unit tests for the snap of the common offset and for the gradients of the shapes dragged along.
  • The frame holds the same selection that is dragged as one, and the rows X and Y move it by number.

Two findings

  • The inspector of a shape is now taller than the window. Two existing checks of module 47 no longer found their row or button on the screen and use a new hook that scrolls there first. In the editor Add shape now needs a scroll or a folded band.
  • Not solved: with a shape at the top edge of the view the knob lies outside the tab. Panning the view or Rotate by helps. The wiki names it under the limits.

Under the hood

  • src/core/model/vectorTransform.ts is the rule as pure functions: ringTransformed, paintTransformed, geometryTransformed, outlineExtent and the matrices of a pull (frameScale, frameMovedTo, frameSizedTo, frameFlipped).
  • transformShapesCommand in vectorArtCommands.ts takes a list of shapes through one matrix as one step.
  • src/editor/vectorart/shapeFrame.ts holds where the handles are (frameBox, frameGripAt) and what a pull means (frameSizing, frameTurning). VectorArtCanvas asks a point or a handle first, then the frame, then a line.
  • src/editor/inspector/shapeTransformRows.ts builds the band and its buttons.
  • __gm.vectorArt.frame() and __gm.inspectorButton(text) are what a check can use of it.

Tests

gate (melektaus-atx)   209 files, 3176 tests, CHECK EXIT 0 (3121 + 55)
e2e 47,48              ALL PASSED - 112 checks
  • No full run and no smokes. The sum of 1664 (1660 + 4) in README and wiki is reckoned. 1660 is what CI counted for 6d79cf5 (run 240, read in the log). A run for 3452899 was started with the push and was not waited for.
  • 55 unit tests: 25 in tests/core/vector-transform.test.ts, 30 in tests/editor/shape-frame.test.ts.
  • Four e2e checks with a real mouse in block 47k: pull a corner square, turn with Shift, type width and rotation in the inspector, drag two shapes without a group.
  • Two screenshots looked at: the frame round one shape and round two, the band TRANSFORM.
  • Not checked in the browser: the squares on the edges, Alt, the cursors, the flip buttons and the rows X, Y and Height. Unit tests only. Nothing was looked at after the build.
Counter-check Result
47 in the unit tests all work. Four did not at first: two showed dead code, which is gone, two got tests
4 in the browser all work, 1 to 2 checks fall each
Done in `3452899`, wiki `9657f11` (*Vector Art*, *Keyboard*, *Development*). **What changes** Following the six answers above: baked in, nothing remembered, a frame as on scene objects, the line width stays, a single shape of a group gets its own frame, no arrow keys. - **A frame round the selection.** With *Select* the selection (one shape, several shapes, a group) stands in a frame of eight squares and a knob, drawn like the one of the scene view. - **Scaling.** A corner square scales from the opposite corner, a square on an edge only in its own direction. `Shift` keeps the proportions, `Alt` scales about the middle. - **Turning.** The knob turns round the middle of the frame, with `Shift` in steps of 15 degrees. - **Inspector.** A new band `TRANSFORM` with *X*, *Y*, *Width*, *Height* and *Rotate by*, below them *Flip horizontal* and *Flip vertical*. The numbers can be typed or scrubbed. - **Baked in.** Points, handles, gradients and texture tiles are converted, nothing is remembered. After a turn the frame stands upright again and *Rotate by* shows 0. - **The line width stays.** - **One pull, one number, one flip is one undo step**, whatever the number of shapes. **Decided here** - **The frame stands 15 pixels off the shapes.** The points of a shape lie exactly on its bounds, on the corners for a square. A handle on the bounds would lie on a point. This departs from "as on scene objects". - **The knob only turns.** In the scene view it scales as well, here the squares do that. - **No mirroring by pulling.** A side cannot be pulled through the opposite one, the frame keeps at least 1 pixel. - **Coordinates are rounded to a thousandth of a pixel.** A quarter turn is exact that way, and the file stays readable. - **A texture fill under a turn:** the tile stays upright and grows to the bounds of the turned tile, the picture itself does not turn. - **A gradient under an uneven scale:** both ends go along, the bands stay square to the axis. - **X and Y** are the top left corner of the frame, *Width* and *Height* stretch from there. - **The switch *Scale stroke*** of the proposal is not built, the answer was "stays". **Taken over from #217** - The e2e check for two selected shapes without a group (block 47k). - Unit tests for the snap of the common offset and for the gradients of the shapes dragged along. - The frame holds the same selection that is dragged as one, and the rows *X* and *Y* move it by number. **Two findings** - **The inspector of a shape is now taller than the window.** Two existing checks of module 47 no longer found their row or button on the screen and use a new hook that scrolls there first. In the editor *Add shape* now needs a scroll or a folded band. - **Not solved:** with a shape at the top edge of the view the knob lies outside the tab. Panning the view or *Rotate by* helps. The wiki names it under the limits. **Under the hood** - `src/core/model/vectorTransform.ts` is the rule as pure functions: `ringTransformed`, `paintTransformed`, `geometryTransformed`, `outlineExtent` and the matrices of a pull (`frameScale`, `frameMovedTo`, `frameSizedTo`, `frameFlipped`). - `transformShapesCommand` in `vectorArtCommands.ts` takes a list of shapes through one matrix as one step. - `src/editor/vectorart/shapeFrame.ts` holds where the handles are (`frameBox`, `frameGripAt`) and what a pull means (`frameSizing`, `frameTurning`). `VectorArtCanvas` asks a point or a handle first, then the frame, then a line. - `src/editor/inspector/shapeTransformRows.ts` builds the band and its buttons. - `__gm.vectorArt.frame()` and `__gm.inspectorButton(text)` are what a check can use of it. **Tests** ``` gate (melektaus-atx) 209 files, 3176 tests, CHECK EXIT 0 (3121 + 55) e2e 47,48 ALL PASSED - 112 checks ``` - No full run and no smokes. The sum of 1664 (1660 + 4) in README and wiki is reckoned. 1660 is what CI counted for `6d79cf5` (run 240, read in the log). A run for `3452899` was started with the push and was not waited for. - 55 unit tests: 25 in `tests/core/vector-transform.test.ts`, 30 in `tests/editor/shape-frame.test.ts`. - Four e2e checks with a real mouse in block 47k: pull a corner square, turn with `Shift`, type width and rotation in the inspector, drag two shapes without a group. - Two screenshots looked at: the frame round one shape and round two, the band `TRANSFORM`. - **Not checked in the browser:** the squares on the edges, `Alt`, the cursors, the flip buttons and the rows *X*, *Y* and *Height*. Unit tests only. Nothing was looked at after the build. | Counter-check | Result | |---|---| | 47 in the unit tests | all work. Four did not at first: two showed dead code, which is gone, two got tests | | 4 in the browser | all work, 1 to 2 checks fall each |
admin moved this to Done in Development on 2026-10-02 11:21:25 +02:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#291