diff --git a/TODO.md b/TODO.md index f238aa8..08ac7cc 100644 --- a/TODO.md +++ b/TODO.md @@ -8,6 +8,29 @@ Running list of deferred work. Detailed specs for the larger items live in _(Empty — see "Shipped (recent)" below for the items that just landed. Drop new items in here as they come up.)_ +## Design-tool follow-ups (Illustrator parity arc) + +The pen / select / pathfinder bundle (`docs/PEN_TOOL_FEATURE.md`) +landed with these intentional gaps: + +- **Smart Guides.** Snap-to-anchor and snap-to-edge alignment with + on-canvas distance hints while dragging. Biggest "feels professional" + upgrade still on the table; deserves its own arc. +- **Gradients + drop shadows.** Linear / radial gradient fills and a + basic drop-shadow / glow effect on the appearance panel. Mostly an + SVG `` + `filter` addition. +- **Scissors (C) + Outline text + Command palette (Cmd+K).** Three + small wins: split a path at a click, convert text to editable pen + paths (font-independent for Nostr export), searchable action list. +- **Flip H / V.** Prototyped during the Align panel arc but pulled + out — needs the renderer to honor per-layer scaleX / scaleY. +- **Pathfinder limitations to lift.** Today: refuses rotated shapes, + flattens curves, only the first polygon's outer ring stays + pen-editable post-op. Rotation support is the most user-facing of + these; curve fidelity would need a Bézier-aware clipper. +- **Pixel-art frame timeline.** Onion skin + frame list + FPS control. + Largest open arc; transformative if pixel art is a focus. + ## QR code layer — remaining phases Phases A and B shipped (the `qr` layer type: data, error-correction level, diff --git a/docs/PEN_TOOL_FEATURE.md b/docs/PEN_TOOL_FEATURE.md index 4b68bc2..2b83e6d 100644 --- a/docs/PEN_TOOL_FEATURE.md +++ b/docs/PEN_TOOL_FEATURE.md @@ -24,12 +24,18 @@ tool-mode system with flanking toolbars to host it. shape-layer commit. - **Phase C** — done. Pen click/drag anchors, rubber-band preview, close / Enter / dbl-click / Esc, closed-fill-on-close, `shape.pen.nodes` stored. -- **Phase D** — partial. Editable anchors + Bézier handles for selected - `tool:'pen'` paths; drag-to-move anchor (carries handles) and drag-to-move - handle, regenerates `d`, one undo per drag. *Deferred:* add/delete anchor, - corner↔smooth toggle, click-segment-to-insert, and bbox-refit when an - anchor is dragged past the original 0–100 viewBox (path clips at the box - edge until refit lands). Rotated paths are not node-editable in v1. +- **Phase D** — done (close-out 2026-06-01). On top of the existing + drag-anchor / drag-handle path: click on a segment between anchors + inserts a new anchor via a de Casteljau cubic split (curve shape + preserved exactly); right-click or Backspace on a selected anchor + deletes it; Alt-click on an anchor toggles between **corner** + (handles move independently, square anchor glyph) and **smooth** + (handles stay mirrored across the anchor, circle anchor glyph); + dragging a node or handle past the original 0–100 viewBox refits + the layer's bounding rect + remaps coordinates so the path stays + visually anchored without clipping. The currently-selected anchor + renders with an amber stroke so Backspace-to-delete is unambiguous. + Rotated paths are still not node-editable in v1. - **Phase E** — done. `layer.hidden` flag, eye toggle in the layer list, all six renderers + Canvas2D export skip hidden layers. - **Unified vector editing** — done. With the Pen tool active, the options @@ -42,16 +48,92 @@ tool-mode system with flanking toolbars to host it. arcs, abs & rel). *Not convertible:* multi-element SVGs and compound (multi-subpath) paths — the panel shows a hint instead. +### Implementation status — 2026-06-02 (Illustrator parity arc) + +A subsequent arc brought the pen / select tools much closer to +Adobe Illustrator's feel. The tool-mode system from Phases A–E is +unchanged; the new work plugs into it: + +- **Direct Selection (A)** as a separate tool from Select (V), + matching Illustrator's V/A split. Cmd / Ctrl held from any + non-pen tool temporarily flips the effective tool to Direct + Selection so a quick anchor tweak doesn't require dropping the + current tool. +- **Hover cursor cues**: − over an anchor in Pen mode (auto-delete), + + over a segment (auto-add), the "continue" pointer over an + endpoint of an open path, grab over a segment in Direct Select + (bow the curve). +- **Pen auto-add / auto-delete**: clicking a segment with no + modifier inserts an anchor at the click point; clicking an + existing anchor deletes it. Drag (instead of click) on an anchor + converts it on the fly — pulls symmetric handles out. Alt-drag + pulls an asymmetric corner. +- **Convert anchor** (Alt-click in Pen or Direct Select): flips + curved ↔ pointed completely. Curved → pointed drops both handles + for a real sharp corner; pointed → curved grows symmetric handles + along the chord through the anchor (1/3 of chord length). +- **Shift constrains** pen segments to 0 / 45 / 90° while drawing + and previewing the next click. +- **Multi-anchor selection**: Shift-click anchors to add / remove + them from a selection Set. Drag a marquee inside the editable + path to box-select anchors. Arrow keys nudge every selected + anchor (1 px, 10 px with Shift) instead of the whole layer. + Backspace deletes the whole anchor selection at once. +- **Drag a segment** to bow the curve (Direct Select). Equal-split + delta across the two inner control points so the cursor tracks + the grabbed point; smooth anchors on either end keep their + handles mirrored. +- **Continue an open path**: with the Pen tool, click the start / + end anchor of an open path to resume drawing from there. The + source layer is hidden during the draft; on commit (Enter / close + / Escape) the new path takes its place, preserving z-order, + target, fill and stroke. +- **Spacebar reposition** during pen create-drag: slides the anchor + itself instead of growing handles; release Space to resume + handle-pulling from the new position. +- **Alt mid-draw** during pen create-drag: only the outgoing handle + is pulled, incoming side stays at the anchor — asymmetric corner + for tangent-then-corner transitions without lifting the pen. +- **Alt-drag handle** in Direct Selection: breaks symmetry, the + opposite handle stays put. +- **Path keyboard ops**: Cmd+J closes an open path when both + endpoints are selected; Cmd+Alt+J averages selected anchors to + their centroid. +- **Path Actions side panel**: when Pen or Direct Selection is + active and a pen path is selected, a sidebar block surfaces the + same ops as buttons — Pointed corner, Curved smooth, Delete + anchor, Average, Join endpoints, Close / Open path, Reverse + direction. Buttons auto-disable when the action would be a no-op. + ### Non-goals (v1) - A raster paint layer (true pixel buffers). Explicitly out of scope — the app's design-as-JSON model and Nostr-friendliness depend on storing instructions, not bitmaps. A `paint` layer type could be a separate future feature; this doc does not pursue it. - Pressure / tilt / velocity-sensitive brushes. -- Boolean path operations (union / subtract / intersect). - Moving the existing shape-primitive menu into the left toolbar. The sidebar "+ Shape" menu stays; pen/pencil are additive. +### Adjacent design-tool features (shipped in the same arc) +- **Eyedropper (I)** — native EyeDropper picker, samples any pixel + on screen to the selected layer's fill (or stroke with Shift). +- **Align & distribute panel** — six align ops + horizontal / + vertical distribute on the layer selection (uses the selection + bbox for 2+, target bounds for a single layer). +- **Free Transform rotation handle** above both the single-layer + selection bbox and the multi-layer selection box; Shift snaps to + 15°. Multi-layer rotates each layer's centre around the bbox + centre AND advances each layer's own rotation. +- **Pathfinder** — Unite / Subtract / Intersect / Exclude on 2+ + selected shape layers, backed by `vendor/polygon-clipping.min.js`. + Curves are flattened to polygon approximations. Rotated layers + are not supported yet. +- **Marquee box-select** on empty canvas with the Select (V) tool — + marching-ants rectangle, Shift adds to the existing selection. +- **Double-click dive-into-edit**: a vector shape under the Select + tool flips to Direct Selection on dbl-click and auto-converts + primitives to editable pen paths so anchors show immediately. + --- ## Why this fits the repo diff --git a/src/index.html b/src/index.html index 6f30222..d308504 100644 --- a/src/index.html +++ b/src/index.html @@ -1720,6 +1720,29 @@ .lh-s { left: 50%; top: 100%; cursor: ns-resize; } .lh-sw { left: 0; top: 100%; cursor: nesw-resize; } .lh-w { left: 0; top: 50%; cursor: ew-resize; } + /* Free Transform rotation handle: sits above the bbox top edge, + connected by a thin line, with a circular pill so it's visually + distinct from the square scale handles. */ + .lh-rot { + left: 50%; top: 0; + margin-top: -36px; + margin-left: -8px; + width: 15px; height: 15px; + border-radius: 50%; + background: var(--accent); + border-color: #fff; + cursor: grab; + } + .lh-rot:active { cursor: grabbing; } + .lh-rot::after { + content: ''; + position: absolute; + left: 50%; top: 100%; + width: 1px; height: 23px; + background: var(--accent); + transform: translateX(-50%); + pointer-events: none; + } .freeLayer img { width: 100%; @@ -2494,7 +2517,29 @@ .toolOptions .buttonRow { margin:6px 0 0; } .toolOptHint { font-size:.7rem; color:var(--muted); margin:4px 0 0; line-height:1.35; } .penOverlay { position:absolute; inset:0; z-index:998; pointer-events:none; } + /* Marching-ants marquee box drawn while drag-selecting on the + canvas. CSS animation shifts four 1px dashed borders so the + outline reads as moving — same effect as Photoshop / Figma. */ + .marqueeSelectBox { + position: absolute; + pointer-events: none; + z-index: 10000; + background: + linear-gradient(90deg, rgba(15,23,42,0.95) 50%, rgba(255,255,255,0.95) 50%) 0 0/8px 1px repeat-x, + linear-gradient(90deg, rgba(15,23,42,0.95) 50%, rgba(255,255,255,0.95) 50%) 0 100%/8px 1px repeat-x, + linear-gradient(0deg, rgba(15,23,42,0.95) 50%, rgba(255,255,255,0.95) 50%) 0 0/1px 8px repeat-y, + linear-gradient(0deg, rgba(15,23,42,0.95) 50%, rgba(255,255,255,0.95) 50%) 100% 0/1px 8px repeat-y; + animation: marqueeAntsMarch 0.6s linear infinite; + } + @keyframes marqueeAntsMarch { + to { + background-position: 8px 0, -8px 100%, 0 -8px, 100% 8px; + } + } body.tool-drawing .penOverlay { pointer-events:auto; cursor:crosshair; } + /* Direct Selection captures segment + marquee drags too, but + individual anchor / handle dots still set their own cursors. */ + body.tool-direct-select .penOverlay { pointer-events:auto; cursor:default; } body.tool-drawing .freeLayer { pointer-events:none !important; } body.tool-hand .penOverlay { cursor:grab; } body.tool-panning .penOverlay { cursor:grabbing; } @@ -3701,6 +3746,38 @@ + +
+ Align & distribute +

Select 2+ layers to align to their bounding box, or 1 layer to align to the page bounds. 3+ layers needed to distribute.

+
+ + + +
+
+ + + +
+
+ + +
+
+ +
+ Pathfinder +

Boolean ops on 2+ selected shape layers. Result is a polygon approximation (curves get flattened). Non-pen primitives are auto-converted; rotated shapes aren’t supported yet.

+
+ + +
+
+ + +
+

Click a layer to select it. Shift/Ctrl/Cmd-click to select multiple layers, then drag any selected layer to move the set together. Text layers are editable in place.

@@ -4031,13 +4108,15 @@
- + + +
@@ -4070,6 +4149,29 @@
+ + +