diff --git a/ROADMAP.md b/ROADMAP.md index 61c4bb9b..b9517f82 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,7 +4,7 @@ VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adob This file tracks **how far we are and what's left**. Time estimates are wall-clock hours of continuous Claude Opus 5.5 agent work (including builds and the CI gate), given both for **one agent** and for **4–6 parallel agents** on disjoint crates. They are counted from the remaining work (see [Parity estimate](#parity-estimate)), calibrated against measured throughput, and updated as work lands. -_Last updated: 2026-10-07 (after M4.14–M4.98, M8.1–M8.20, M14.4–M14.7, the MCP prompts, resource templates, completions and logging, and the 2026-10-07 issue fixes; see [Honest assessment](#honest-assessment-2026-10-05))._ +_Last updated: 2026-10-07 (after M4.14–M4.98, M8.1–M8.20, M14.4–M14.7, the MCP prompts, resource templates, completions and logging, the 2026-10-07 issue fixes and the Layers panel rework; see [Honest assessment](#honest-assessment-2026-10-05))._ ## Where we are @@ -115,6 +115,7 @@ grade by behaviour against `plan/illustrator/`, not by whether a menu item exist - **Temporary tools:** Cmd with any other tool drags with the selection tool used last (Selection, Direct Selection or Group Selection). Held Space pans and Cmd+Space zooms (Cmd+Alt+Space out) whatever the tool. - **Panel drag and drop:** art dragged off the canvas onto the Symbols panel becomes a symbol, and a symbol dragged onto the canvas places an instance where it is dropped. - **Tool double-clicks:** double-clicking a tool's button opens its options: Hand fits the artboard in the window, Zoom shows 100 %, Rotate, Scale, Reflect and Shear open their Object › Transform dialogs, Gradient, Eyedropper, Blend and the Liquify tools their panels or options. +- **Layers panel:** every layer, sublayer, group and object is a clickable row at any depth: a click highlights it and makes its layer current (new art goes there), Shift-click a range, Ctrl/Cmd-click toggles. Sublayers are no longer treated as objects: clicks, marquees, Select All and the Select menu take the art inside them, and each sublayer selects in its own colour. Selection squares on rows with selected art (click selects a row's art, Shift adds or removes; dragging the square moves the selection to another row, Alt copies), the eye and lock on every row with drag-down-the-column (one undo step), Ctrl/Cmd-click an eye for per-layer Outline, triangles with Alt to open or close everything inside, drag and drop rows above, below or into layers and groups with a drop line (Alt copies, the trash deletes), inline rename, Delete key on highlighted rows. Buttons and the full panel menu: New Layer/Sublayer (Alt: options, Ctrl: on top), Duplicate, Delete, Options for Selection, clipping mask, isolation, Locate Object, Merge Selected, Flatten Artwork, Collect in New Layer, Release to Layers (Sequence and Build), Reverse Order, Template, Hide/Outline/Lock Others and Show/Preview/Unlock All, Paste Remembers Layers, Panel Options (row size, thumbnails per kind, Show Layers Only). Layer Options: name, colour (presets or custom), Template, Lock, Show, Print, Preview (outline drawing and clicking) and Dim Images to %. Every operation is a command (`layer.move`, `layer.highlight`, `layer.merge`…) with validation against cycles and invalid nesting. - **Drawing aids:** Smart Guides and snapping, guides dragged out of the rulers, and Draw Normal / Behind / Inside modes. - **Views:** the status bar's artboard navigator (first, previous, next, last; `view.goToArtboard`) goes to an artboard and fits it, and Fit Artboard in Window and Actual Size show the navigator's artboard. - **Geometry and effects:** @@ -195,7 +196,7 @@ about 1–1.5 agent-hours each, so the other rows (estimated on the older scale) | Type advanced | 4 | 48% | CJK composition for vertical type (ruby, mojikumi, vertical metrics, manual tate-chu-yoko), variable font axis sliders (named instances are styles), tab leaders, spell check (open dictionary), Touch Type, Retype; vertical point/area/path type and Type Orientation have initial support | 20–28 | | Symbols, blends, envelopes, Repeat, perspective | 5 | 88% | symbol libraries (original), dynamic symbols, envelope Anti-Alias/Preserve Shape output and warp point editing, brush interpolation in blends (M8 fidelity pass done) | 5–8 | | Image Trace, graphs, image tools | 3 | 70% | graph Design/Column/Marker, Create Object Mosaic, Crop Image polish (Vector Halftone is done) | 6–10 | -| Layers, artboards, document setup | 5 | 80% | Layers panel options depth, artboard presets/rearrange polish (Document Setup and New Document are done) | 5–8 | +| Layers, artboards, document setup | 5 | 82% | Layers panel: a confirmation before deleting layers that hold art, Collect for Export, row context menus, the Layer Options dialog for several rows with mixed values, Paste Remembers Layers for sublayers, drag-scrolling a long panel while dragging rows; artboard presets/rearrange polish (Document Setup, New Document and the rest of the Layers panel are done) | 4–7 | | View & navigation | 3 | 70% | New View/Edit Views, multiple windows/arrange, Snap to Pixel/Glyph (print tiling is done) | 9–14 | | Guides, grids, smart guides, snapping, rulers | 3 | 75% | global/video rulers, smart-guide preference depth, ruler-drag modifiers (Shift snaps to ticks, Alt swaps orientation) and dragging existing guides | 4–8 | | File formats | 6 | 85% | DWG (no open spec: DXF instead), PSD placement as layers, Illustrator EPS checked against real files (only reduced repros so far), the remaining fidelity polish; EPS, DXF, EMF/WMF, TIFF, BMP, Targa, PSD export, SVGZ, PDF security, PDF/X, PDF layers and presets are done | 6–10 | diff --git a/docs/control-protocol.md b/docs/control-protocol.md index d8e7a9eb..86c80e1e 100644 --- a/docs/control-protocol.md +++ b/docs/control-protocol.md @@ -288,8 +288,13 @@ Paste placement: through the app, `edit.paste` and `edit.pasteWithoutFormatting` paste at the centre of the view. The Paste menu items are enabled while the system clipboard holds something to paste (SVG, PDF, text or a bitmap on the desktop; SVG on the web), even with nothing copied in the app (looked at up to four times a second; `ui.menu.list` shows it). The Layers panel menu (≡ on -the dock's tab strip while Layers shows) lists the layer commands and Paste Remembers Layers -(`layer.pasteRemembersLayers`, checked when on). +the dock's tab strip while Layers shows) lists the layer commands (New Layer…, Duplicate and Delete Selection, +Options for Selection…, clipping mask, isolation, Locate Object, Merge Selected, Flatten Artwork, Collect in New +Layer, Release to Layers, Reverse Order, Template, Hide/Outline/Lock Others or Show/Preview/Unlock All Layers), Paste +Remembers Layers (`layer.pasteRemembersLayers`, checked when on) and Panel Options…. Layer Options is the +`layerOptions` dialog (`ui.layerOptions {ids?}`, `ui.newLayer {sublayer?}`), Panel Options the `layersPanelOptions` +dialog (`ui.layersPanelOptions`), and `ui.layersExpand {ids?, open?}` opens or closes rows; see the Layers panel +section of `docs/mcp.md` for the row commands (`layer.setCurrent`, `layer.highlight`, `layer.move`…). File Info: File → File Info… (`file.info` from the menu or Cmd+Alt+Shift+I; `ui.fileInfoDialog` for agents) opens the `fileInfo` dialog. Its fields are what `file.info` reports (`title`, `author`, `authorTitle`, `description`, diff --git a/docs/mcp.md b/docs/mcp.md index 0b9a65a0..f1fe2f96 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -512,7 +512,7 @@ paints behind the clipped art and its stroke over it, not clipped, on screen and ``` `layer.clippingMask.toggle {id?}` is the Layers panel's clipping mask button: the top object of the layer `id` (default: -the one selected group, else the current layer) becomes its clipping path (unpainted, moved to the bottom of the layer, +the one highlighted layer or group row, else the one selected group, else the current layer) becomes its clipping path (unpainted, moved to the bottom of the layer, so art added later is clipped too); called again it releases the mask. It returns `{clip}`, and the Layers panel underlines clipping-path names. @@ -719,9 +719,58 @@ branch sets all of it. `paint.sampleColor {color}` puts a sampled colour (in its {"name":"run_command","arguments":{"command":"appearance.copyFrom","params":{"source":12,"ids":[7,8]}}} ``` +## The Layers panel: rows, layers and sublayers + +Every layer, sublayer, group and object is a row of the Layers panel. Sublayers are layers inside layers: they are not +objects, so clicking or marquee-selecting art in a sublayer, Select All and the other Select commands take the art +itself, and each sublayer has its own colour for the selection highlight. `document.inspect` lists the tree (layers +report `color`, `template`, `printable`, `preview`, `dimImages` and `clip`), the `currentLayer` (where new art goes) +and `layerRows`, the rows highlighted in the panel. + +- **Clicking rows** (not undo steps): `layer.setCurrent {id}` is a plain click on any row: it alone is highlighted + and its layer (the row itself when it is a layer or sublayer) becomes current. `layer.highlight {ids, mode?: + set|add|toggle}` is Shift-click (a range) and Ctrl/Cmd-click (toggle). Selecting art makes its layer current. + Without `ids`, the panel commands below act on the highlighted rows, else on the current layer. +- **Selection column**: `layer.selectAll {id, add?}` selects a row's visible, unlocked art (a layer's sublayers' + too); `add` (Shift) adds it, or removes it when it's all selected. +- **Eye and lock**: `layer.setProps {ids?, visible?, locked?, name?}` for any rows, plus Layer Options for layers: + `template` (also locks the layer and dims its images to 50% unless given), `printable`, `preview` (off: the layer + draws and is clicked in outline, Ctrl/Cmd-click its eye), `dimImages` (0–100, or false) and `color` (an index 0–26, + `#rrggbb` or a preset name). Several rows change in one undo step (a drag down the eye or lock column). +- **Dragging rows**: `layer.move {ids, target, place?: above|below|inside, copy?}` moves rows beside a row or into a + layer or group (on top of its contents), keeping their stacking order; `copy` (Alt-drag) moves copies. Layers go + only in layers or at the top level and objects in layers and groups (an object placed beside a top-level layer goes + inside it); a row never goes into itself or a row inside it, and a locked layer or group takes nothing. Dragging the + selected-art square is `layer.move` with the selected objects. `node.move {id, parent?, index}` is the low-level + form with the same rules. +- **Buttons**: `layer.new {name?, top?, …options}` (above the current layer at its level; `top` with Ctrl/Cmd), + `layer.newSublayer {parent?, name?, …options}` (on top of the parent's contents), `layer.delete {ids?}` (rows with + what they hold; the last layer stays), `layer.locate {id?}` (highlights the selected object's row; the panel opens + the rows around it) and `layer.clippingMask.toggle`. +- **Panel menu**: `layer.duplicate {ids?}`, `layer.merge {ids?}` (into the layer highlighted last, keeping the + stacking order), `layer.flatten {id?}` (every other visible layer's art into one layer; hidden layers are deleted, + templates stay), `layer.collectInNew {ids?}`, `layer.releaseToLayers {id?, build?}` and + `layer.releaseToLayersBuild` (each object of a layer or group in a sublayer of its own; Build adds up copies), + `layer.reverse {ids?}`, `layer.template {ids?, on?}`, `layer.hideOthers` / `layer.showAll`, + `layer.outlineOthers` / `layer.previewAll`, `layer.lockOthers` / `layer.unlockAll`, `layer.pasteRemembersLayers`, + `object.isolate {id}` / `object.exitIsolation`. +- **Dialogs and panel state** (control channel and the app's MCP): `ui.layerOptions {ids?}` and `ui.newLayer + {sublayer?}` open Layer Options (dialog `layerOptions`: name, color, template, locked, visible, printable, preview, + dimImages, dimPercent; OK is one undo step), `ui.layersPanelOptions` opens Panel Options (`layersPanelOptions`: + layersOnly, rowSize small|medium|large|other, otherSize, thumbLayers, thumbGroups, thumbObjects), and + `ui.layersExpand {ids?, open?}` opens or closes rows as their triangles do (Alt-click: everything inside). + +```json +{"name":"run_command","arguments":{"command":"layer.newSublayer","params":{"name":"Shadows"}}} +{"name":"run_command","arguments":{"command":"layer.move","params":{"ids":[12,15],"target":7,"place":"inside"}}} +{"name":"run_command","arguments":{"command":"layer.setProps","params":{"ids":[7],"preview":false,"color":"Orange"}}} +{"name":"run_command","arguments":{"command":"layer.highlight","params":{"ids":[3,7]}}} +{"name":"run_command","arguments":{"command":"layer.merge","params":{}}} +``` + ## Targeting layers and moving appearances -`layer.target {id}` is the Layers panel's target circle: a layer gets its visible, unlocked art selected and is itself +`layer.target {id}` is the Layers panel's target circle: a layer gets its visible, unlocked art (its sublayers' too) selected and is itself the target, so `appearance.*`, `effect.*`, `transparency.*` and the opacity-mask commands without `ids` act on the layer (its opacity, its own fills and effects, an opacity mask on the whole layer); a group or object is simply selected. `document.inspect` reports it as `target`, and any other selection change ends it.