From 46f046ca4e916c9c1dcb90c36a9cd53ec8092d3b Mon Sep 17 00:00:00 2001 From: David Mann Date: Sun, 11 Oct 2026 16:26:20 +0200 Subject: [PATCH 1/7] scorecard: five rows catch up with work already on main AGENTS.md sends contributors to the scorecard's missing and partial rows when picking work; these five described code that has since landed. - TYPE-218-7 missing -> done: Warp Text opens with the layer's warp (filter_dialog.rs warp_defaults) and previews live; covered by warp_text_dialog_tests.rs and warp_text_preview_matches_the_full_size_result_on_a_reduced_proxy. - TOOL-214-13 partial -> done: Properties shows Density and Feather for both pixel and vector masks (mask_props_ui.rs, mask_props_ui_tests.rs). - BUG-207-5 missing -> done: all twelve retouch tools are tested against mask, alpha channel, Channels-panel and Quick Mask targets; Sample All Layers and the smudge fringe have their own tests (retouch_cmds/tests.rs). Pencil and Mixer Brush targets are still untested, noted in the row. - UI-217-18 missing -> partial: Alt+wheel zooms around the pointer at x1.1 a notch, measured on Photoshop in #1718, not the ~5 % the row asks for; the status bar zoom controls fit (#2823); Navigator not checked. - BUG-208-4 stays partial with a corrected note: marquee add/subtract, Lasso add/subtract/intersect and Polygonal Lasso are tested from modifiers held at the press; a marquee Shift+Alt intersect test is still missing. docs/gaps.md (G8), docs/target-app-parity.md (Type row) and docs/ui-parity.md updated to match, with revision-history rows. docs/scorecard.md regenerated: Tools 26/15/2, Workspace and UI 8/9/6, Type 2/4/3, Open bugs 30/2/0. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/gaps.md | 12 +++++++----- docs/scorecard.md | 18 +++++++++--------- docs/target-app-parity.md | 5 +++-- docs/ui-parity.md | 7 ++++--- scorecard/bugs.toml | 6 +++--- scorecard/tools.toml | 4 ++-- scorecard/type.toml | 4 ++-- scorecard/ui.toml | 4 ++-- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/docs/gaps.md b/docs/gaps.md index a2ec3dddc4..bc99f05298 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Where PhotoCraft falls short of Photoshop -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (first version: every known shortfall ranked, from the 2026-10-10 re-measure) · **Target:** Adobe Photoshop 2026 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (G8: kerning and the Warp Text preview are done) · **Target:** Adobe Photoshop 2026 Every known shortfall against Photoshop 2026 (27.11.0), one entry each, ranked by user impact on the way to beta. This is the work list agents pick from: take the highest-ranked entry that @@ -78,10 +78,11 @@ what an agent can't finish alone. ### G8. Type depth - **Missing:** type on a path (TYPE-218-1), paragraph direction UI (TYPE-218-2), complex-script fallback fonts and golden tests (TYPE-218-3), variable-font axes (TYPE-218-4), OpenType panel - UI (TYPE-218-5), manual and optical kerning with PSD round trip (TYPE-218-6, #206), live Warp - Text preview (TYPE-218-7, #2689), triple/quadruple click (TYPE-218-8), "rasterize and continue" - for distort/perspective on type (TYPE-218-9), text free transform (#2630). -- **Evidence:** scorecard Type: 0 done, 3 partial, 6 missing. The Type tool froze the app for + UI (TYPE-218-5), triple/quadruple click (TYPE-218-8), "rasterize and continue" for + distort/perspective on type (TYPE-218-9), text free transform (#2630). Done since the + re-measure: manual and optical kerning with PSD round trip (TYPE-218-6, #206) and the live Warp + Text preview that opens with the layer's warp (TYPE-218-7, #2689). +- **Evidence:** scorecard Type: 2 done, 4 partial, 3 missing (2026-10-11). The Type tool froze the app for 60 s on one macOS machine (#2518). - **Estimate:** 120–200 h. @@ -212,5 +213,6 @@ what an agent can't finish alone. | Date | Change | Summary | |---|---|---| +| 2026-10-11 | minor | G8 Type depth: manual/optical kerning (TYPE-218-6) and the live Warp Text preview (TYPE-218-7) moved to done; scorecard Type evidence updated to 2/4/3 | | 2026-10-10 | minor | Checked against the alpha gate (no alpha blockers); #2374 marked closed | | 2026-10-10 | major | First version, from the full re-measure against Photoshop 2026 27.11.0 and the open issues | diff --git a/docs/scorecard.md b/docs/scorecard.md index c0c15c3187..b1d729a68f 100644 --- a/docs/scorecard.md +++ b/docs/scorecard.md @@ -8,13 +8,13 @@ Generated by `cargo xtask scorecard` from `perf/budgets.toml`, `perf/baseline.js |---|---:|---:|---:|---| | [Performance](#performance) | 3 | 22 | 22 | 56 scenarios: 3 within budget, 22 over budget or failing, 9 tracked only, 17 not run, 5 not measurable yet (baseline 2026-10-05) | | [File compatibility](#file-compatibility) | 6 | 12 | 9 | io corpus: oracle ≥ 146/170, round trip ≥ 169/170; psd-tools corpus: oracle ≥ 236/309, round trip ≥ 308/309; photoshop oracles: oracle ≥ 133/256, round trip ≥ 258/256 | -| [Tools](#tools) | 25 | 16 | 2 | | -| [Workspace and UI](#workspace-and-ui) | 9 | 8 | 6 | settings that do nothing: 32 of 154 (target 0) | -| [Type](#type) | 1 | 4 | 4 | | +| [Tools](#tools) | 26 | 15 | 2 | | +| [Workspace and UI](#workspace-and-ui) | 9 | 9 | 5 | settings that do nothing: 32 of 154 (target 0) | +| [Type](#type) | 2 | 4 | 3 | | | [Automation](#automation) | 3 | 2 | 6 | 630 of 630 menu items live (100.0%) | | [Reliability](#reliability) | 5 | 2 | 0 | never-crash lints on 28 of 28 crates; panic_hunt present | | [Distribution](#distribution) | 5 | 4 | 2 | | -| [Open bugs](#open-bugs) | 29 | 2 | 1 | | +| [Open bugs](#open-bugs) | 30 | 2 | 0 | | ## Performance @@ -157,7 +157,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t | TOOL-214-10 | Pen: Alt breaks a handle, Shift 45 deg, Ctrl direct-selects, Backspace, close-drag handle | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Ctrl/Cmd = Direct Selection and Alt = Convert Point on existing paths (direct_select.rs, #790); no Shift 45 deg, Backspace or Alt while drawing | | TOOL-214-11 | Stroke Path dialog: pick any brush-based tool, Simulate Pressure | partial | [#214](https://github.com/storytold/photocraft/issues/214) | path.stroke brush, pencil, eraser (vector_cmds.rs:1170); brush-only button, no dialog | | TOOL-214-12 | Shapes: on-canvas corner radius handles, shape feather, selection to shape with tolerance | partial | [#214](https://github.com/storytold/photocraft/issues/214) | select.convertToShape with tolerance (vector_cmds.rs:1256); radius as a field only | -| TOOL-214-13 | Mask Properties: Density and Feather controls | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Vector-mask density/feather in the engine (vector_cmds.rs:948); no UI controls | +| TOOL-214-13 | Mask Properties: Density and Feather controls | done | [#214](https://github.com/storytold/photocraft/issues/214) | Properties panel shows Density (%) and Feather (px) sliders for a targeted pixel mask (layer.layerMask.edit) and a targeted vector mask (layer.vectorMask.edit), non-destructive and one undo step per drag, with Photoshop's Refine row (mask_props_ui.rs; mask_props_ui_tests.rs pixel_mask_properties_follow_target_for_raster_and_adjustment_in_both_themes, mask_slider_drags_preview_live_and_undo_as_separate_gestures, vector_mask_properties_edit_density_and_feather) | | TOOL-214-14 | Vanishing Point window: draw and edit planes, paste, clone in perspective | partial | [#214](https://github.com/storytold/photocraft/issues/214) | filter.vanishingPoint (vp_cmds.rs:15) behind a parameter dialog | | TOOL-214-15 | Content-Aware Fill workspace: paint the sampling area, preview, rotate/scale/mirror, new layer | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Engine sampling auto, rect, custom (edit_menu_cmds.rs:324); generic dialog | | TOOL-214-16 | Liquify: redo (Cmd+Shift+Z) | done | [#214](https://github.com/storytold/photocraft/issues/214) | liquify_ui.rs supports bounded redo through Cmd+Shift+Z and the control channel; new strokes clear redo | @@ -199,7 +199,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | UI-217-15 | Curves: smoothing / pencil mode, black/grey/white eyedroppers, tooltips | partial | [#217](https://github.com/storytold/photocraft/issues/217) | adjust_dialog.rs adds black/gray/white eyedroppers; smoothing and pencil modes remain missing | | UI-217-16 | Hue/Saturation: Saturation and Lightness sliders get hue-following colour tracks | done | [#217](https://github.com/storytold/photocraft/issues/217) | saturation_track/lightness_track (adjust_editors.rs): grey -> the hue and black -> the hue -> white, recolouring as the Hue slider moves; saturation_and_lightness_tracks_follow_the_hue | | UI-217-17 | Color panel: wheel plus RGB/HSB/CMYK/Lab/Gray/Web slider modes; resizes with its group | missing | [#217](https://github.com/storytold/photocraft/issues/217) | panels.rs:1837 single field + hex/RGB readout | -| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | missing | [#217](https://github.com/storytold/photocraft/issues/217) | canvas.rs:1107-1125 no Alt handling | +| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | partial | [#217](https://github.com/storytold/photocraft/issues/217) | Alt+wheel zooms around the pointer, one step per notch applied the frame it arrives (wheel_nav.rs; input_tests.rs alt_scroll_zooms_in_steps_around_the_pointer, wheel_nav.rs alt_scroll_zooms_ten_percent_per_notch), but the step is x1.1 (10 %), not the ~5 % this row asks for: #1718 changed it from x1.05 after measuring Photoshop, so the row's target is in question. Status bar zoom field and Fit button fit inside the bar in every theme (status_bar_tests.rs status_bar_controls_sit_inside_the_bar_with_even_margins, #2823); the Navigator zoom controls are not checked | | UI-217-19 | Shortcut hints rendered per platform; Reveal label per OS | done | [#217](https://github.com/storytold/photocraft/issues/217) | hints and tooltips go through shortcuts::pretty (6266b7a9, #262; pretty_uses_the_platform_notation); menus::reveal_label names Reveal in Finder per OS (Show in Explorer / Show in Folder) in the Smart Objects menu and the tab menu; reveal_label_names_the_platform_file_manager + smart_objects_reveal_item_names_the_platform_file_manager | | UI-217-20 | 'Show rulers in new documents' preference; guides stored as f64 | done | [#217](https://github.com/storytold/photocraft/issues/217) | View › Rulers is remembered in unitsAndRulers.showRulers and applied at launch and on change (#2918; rulers_open_as_last_set_after_a_restart); doc Guides are Vec through New Guide, .pcraft and PSD 1032 (guides_keep_sub_pixel_positions_through_pcraft_and_psd) | | UI-217-21 | One Preset Manager for every preset kind with folders, search, reorder, load/save sets | partial | [#217](https://github.com/storytold/photocraft/issues/217) | edit_menu_cmds.rs:714 covers brushes, custom shapes, patterns with reorder | @@ -216,7 +216,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | TYPE-218-4 | Variable font axis sliders from the font's axes; opsz follows the point size | partial | [#218](https://github.com/storytold/photocraft/issues/218) | type_cmds.rs:184 accepts variations; FaceInfo.axes unused in the UI | | TYPE-218-5 | OpenType UI: Character panel buttons, Numerals and Stylistic Sets submenus | partial | [#218](https://github.com/storytold/photocraft/issues/218) | Type > OpenType toggles (type_extra_cmds.rs:512); no panel buttons or submenus | | TYPE-218-6 | Manual pair kerning (Alt+arrows), optical kerning rendered, both round-trip PSD (#206) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Alt+Left/Right at a collapsed caret kerns the pair (type_tool.rs kern_pair, 20 per step and 100 with Cmd; type_tool_alt_arrows_kern_the_pair). Optical kerning is computed from the glyph outlines in text/src/optical.rs and applied by layout.rs when the run's mode is Optical (optical_matches_photoshop, optical_kerning_tightens_open_pairs). Both modes and manual values round-trip through PSD (io/tests/psd_kerning.rs; the optical mode travels in Txt2, txt2_carries_optical_kerning) | -| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | missing | [#218](https://github.com/storytold/photocraft/issues/218) | view_cmds.rs:834 always seeds arc, bend 50 | +| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | done | [#218](https://github.com/storytold/photocraft/issues/218) | Type > Warp Text opens with the shown layer's warp, or None, never remembered values (filter_dialog.rs warp_defaults; warp_text_dialog_tests.rs warp_text_opens_with_the_type_layers_current_warp, warp_text_opens_at_none_for_a_layer_without_warp, remembered_warp_values_never_override_the_layers_warp). The dialog previews live without editing the document, Cancel leaves no step and OK is one undoable step (warp_text_dialog_previews_the_warp_without_editing_the_document, cancelling_warp_text_leaves_the_document_and_history_untouched, confirming_warp_text_is_one_undoable_step); the reduced-proxy preview matches the full-size result (filter_dialog.rs warp_text_preview_matches_the_full_size_result_on_a_reduced_proxy) | | TYPE-218-8 | Text editing: select all, double/triple/quadruple-click selection, paste, with tests | partial | [#218](https://github.com/storytold/photocraft/issues/218) | Cmd+A, paste and double-click exist; no triple/quadruple click, no tests | | TYPE-218-9 | Offer 'Rasterize and continue?' for Distort/Perspective/Warp on live type | missing | [#218](https://github.com/storytold/photocraft/issues/218) | No such prompt | @@ -298,9 +298,9 @@ Never-crash attribute on 28 of 28 crate roots. | BUG-207-2 | Sample All Layers applies to Blur, Sharpen and Smudge | done | [#207](https://github.com/storytold/photocraft/issues/207) | retouch_ui.rs passes sampleAllLayers to paint.blur/sharpen/smudge; sample_all_layers_reaches_the_command (e2444ce, #234) | | BUG-207-3 | Smudge mixes premultiplied RGBA (no dark fringe at transparent edges) | done | [#207](https://github.com/storytold/photocraft/issues/207) | paint/src/retouch.rs premultiplies; smudge_into_transparency_leaves_no_dark_fringe (e2444ce, #234) | | BUG-207-4 | edit.transform transforms a targeted alpha channel | done | [#207](https://github.com/storytold/photocraft/issues/207) | edit.transform follows a targeted alpha channel or Quick Mask (explicit target since #242, Channels panel target with no target/layer param since #2835); Edit > Transform > Rotate/Flip are routed to the target too; transforms_follow_the_targeted_alpha_channel | -| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | missing | [#207](https://github.com/storytold/photocraft/issues/207) | Only smudge_drags_colour_along_the_stroke (retouch.rs:407) | +| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | done | [#207](https://github.com/storytold/photocraft/issues/207) | Every retouch tool (Clone Stamp, Pattern Stamp, Healing, Spot Healing, Dodge, Burn, Sponge, Blur, Sharpen, Smudge, History Brush, Remove) is tested to paint only a targeted mask, only a targeted alpha channel, and to follow the Channels panel target (engine retouch_cmds/tests.rs retouch_tools_paint_only_the_targeted_mask, retouch_tools_paint_only_the_targeted_alpha_channel, retouch_tools_follow_the_channels_panel_target, retouch_tools_paint_the_quick_mask, retouch_targets_fail_gracefully). Sample All Layers changes the result over two layers (sample_all_layers_blur_and_sharpen_work_on_an_empty_layer, sample_all_layers_smudge_drags_colour_from_below, sample_all_layers_spot_healing_heals_onto_an_empty_layer, clone_stamp_sample_all_layers_onto_empty_layer_and_opacity; ui retouch_ui.rs sample_all_layers_reaches_the_command); no smudge fringe (smudge_across_a_transparent_edge_has_no_dark_fringe). Brush/Eraser/Gradient/Bucket targets: tests.rs painting_can_target_the_layer_mask, channel_cmds/tests.rs painting_filtering_and_adjusting_into_an_alpha_channel. Not covered: Pencil and Mixer Brush into a mask or channel | | BUG-208-1 | Shift while dragging a Rect/Elliptical Marquee constrains to a square/circle | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners applies Shift via Drag::marquee_mods; marquee_tests.rs::shift_during_the_drag_draws_a_square_and_the_readout_follows covers the drag | | BUG-208-2 | Alt while dragging a marquee draws from the centre | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners centres Alt drags; marquee_tests.rs::alt_draws_from_the_centre_and_shift_alt_a_centred_circle verifies rectangles and ellipses | | BUG-208-3 | W x H px readout beside the cursor while dragging a marquee | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_readout draws the readout; marquee_tests.rs asserts dimensions while dragging and its removal after release | -| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press (canvas.rs:1679, used :1779); only a badge test (tool_feedback.rs:195) | +| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press. Marquee: Shift at the press adds and Alt subtracts, with no square or centring (marquee_tests.rs modifiers_held_before_the_drag_pick_the_mode_not_the_shape). Lasso: Alt, Shift and Shift+Alt at the start subtract, add and intersect (lasso_ui/tests.rs initial_alt_still_subtracts_and_initial_shift_still_adds). Polygonal Lasso: Shift/Alt at the first click keep the selection and combine (polygon_lasso_tests.rs modifiers_at_the_first_click_keep_and_combine_the_selection). Missing: a test that Shift+Alt held before a marquee drag intersects | | BUG-208-5 | Kittest: Shift drag gives a square, Alt drag is centred, readout matches the size | done | [#208](https://github.com/storytold/photocraft/issues/208) | crates/ui-egui/src/marquee_tests.rs covers Shift, Alt, selection bounds, W/H readout and drag completion | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 7a4f238cc8..7bac928a5e 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1,6 +1,6 @@ # PhotoCraft vs Adobe Photoshop: target-app parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (full re-measure against Photoshop 2026 27.11.0; merged `parity-estimate.md` and the roadmap's honest assessment into this file) · **Target:** Adobe Photoshop 2026 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (Type evidence: kerning and the Warp Text preview are done; percentages unchanged) · **Target:** Adobe Photoshop 2026 The authoritative answer to "how close is PhotoCraft to Photoshop, and how much work is left". The one-page summary is [`ROADMAP.md`](../ROADMAP.md); the ranked work list is [`gaps.md`](gaps.md); @@ -173,7 +173,7 @@ parity for the area and are already contained in the dimension rows above. | Retouching (healing, clone, patch, remove, content-aware) | 50% | 100–180 | Remove tool non-generative; Content-Aware Fill has no workspace (TOOL-214-15); live stroke preview only for Brush/Eraser (TOOL-213-7) | | Transform, warp, puppet, perspective, liquify | 55% | 100–180 | Free Transform modifiers right; no transform context menu (TOOL-214-5), no skew fields, puppet mesh is a block grid (TOOL-214-6), Liquify called "useless" by a user (#2606) | | Adjustments and filters | 70% | 120–200 | All present; smart-filter re-render matches Photoshop on 5 of 30 files; Filter Gallery looks approximate; no Neural Filters | -| Type | 40% | 120–200 | Engine works; no type on a path, manual kerning, RTL paragraphs, OpenType panel UI, live Warp Text preview; Type tool freeze on macOS (#2518) | +| Type | 40% | 120–200 | Engine works; manual/optical kerning and a live Warp Text preview (2026-10-11); no type on a path, RTL paragraphs, OpenType panel UI; Type tool freeze on macOS (#2518) | | Vector shapes and paths | 55% | 80–140 | Pen, Direct/Path Selection, shapes, shape strokes. Freeform and Curvature Pen (#1054). Missing anchor tools, on-canvas corner radius, path-point nudge; shape parity tracking issue #2496 | | Colour management and modes | 70% | 60–100 | Own ICC engine, soft proof, CMYK/Lab/Indexed/Duotone/Multichannel; no Adobe CMYK profiles, no spot plates (FILE-215-17), monitor profile only at launch | | Camera Raw and computational photo (Photomerge, HDR, lens) | 45% | 120–200 | Raw for DNG/CR2/NEF/ARW/RW2/ORF/RAF(uncompressed)/PEF; no CR3; ACR dialog partial (no masking, calibration); generic lens profiles only | @@ -537,6 +537,7 @@ See [method and results](octagonal-mask-performance.md). | Date | Change | Summary | |---|---|---| +| 2026-10-11 | minor | Type row evidence: manual/optical kerning and the live Warp Text preview are done (TYPE-218-6/7); the 40% estimate is not re-measured | | 2026-10-10 | minor | Readiness-by-audience table: percent and hours for full, mainstream and essentials; full number confirmed as the additive weighted sum over dimensions (46%, reported ~45%) | | 2026-10-10 | minor | Added mainstream-practitioner (~43%) and essentials-user (~61%) numbers with written weights and discounts; full ready-for-real-work rechecked against its written weights (46%, reported ~45%), unchanged | | 2026-10-10 | minor | Stage checked against the core-workflow alpha gate in `roadmap.md`: passes | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 91afa00dcc..b4a9080482 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI parity: tools, handles, modifiers and feel -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (Hand-tool flick panning) · **Target:** Adobe Photoshop 2026 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (selection-modifier and ⌥-wheel rows match their tests) · **Target:** Adobe Photoshop 2026 How PhotoCraft's direct manipulation compares with Photoshop 2026 (27.11.0): the toolbox, the handles and modifier keys of each gesture, nudging, snapping, numeric precision, navigation, @@ -103,7 +103,7 @@ Triangle and Curvature Pen (minus legacy Rounded Rectangle and Targeted Adjustme | Behaviour | Status | Evidence | |---|---|---| | ⇧ square/circle, ⌥ from centre, live W × H readout (marquee) | done | `marquee_tests.rs` | -| ⇧ add, ⌥ subtract, ⇧⌥ intersect from modifiers at press | partial | works; only a badge test (BUG-208-4) | +| ⇧ add, ⌥ subtract, ⇧⌥ intersect from modifiers at press | partial | works; tested for the marquee (add, subtract), Lasso (all three) and Polygonal Lasso; no marquee ⇧⌥ intersect test (BUG-208-4) | | Space repositions the marquee while dragging | done | `hold_keys.rs` | | Polygonal Lasso ⇧ snaps to 45° | missing | #2352 | | Autoscroll at the window edge while selecting | missing | #2231 | @@ -164,7 +164,7 @@ Triangle and Curvature Pen (minus legacy Rounded Rectangle and Targeted Adjustme | Flick panning | done | `flick_pan.rs` (Preferences › Tools › Enable Flick Panning) | | Animated zoom | missing | unread pref; #566 | | Double-click Zoom tool = 100%, double-click Hand = fit | partial | Zoom missing (#2508) | -| ⌥-wheel zoom in gentle steps | missing | UI-217-18 | +| ⌥-wheel zoom around the pointer | partial | ×1.1 per notch, measured on Photoshop (#1718; `wheel_nav.rs`, `input_tests.rs`); #217 asked for ~5 % steps (UI-217-18) | | Wheel, smooth scrolling and pinch as in Photoshop | partial | #2485, #2463, #1989 | | Trackpad rotate drives Rotate View | done | `rotate_view.rs:136` | | Zoom levels to 3200% and beyond | partial | #1813 | @@ -209,3 +209,4 @@ Paragraph; the rest open as in-app floating windows. | 2026-10-10 | major | First version, from a source audit against Photoshop 2026 27.11.0's shortcuts file and the open issues | | 2026-10-10 | minor | Fixed Crop live resize snapping feedback and outdated-camera rendering, applied ratios immediately to centred inscribed previews, and removed two-point options-bar overflow; added pointer, rendering, dropdown/Enter, Swap/X and scrolling regressions | | 2026-10-11 | minor | Flick panning done: releasing a moving Hand drag (tool, Space or middle button) glides and decays, gated by Enable Flick Panning | +| 2026-10-11 | minor | Selection modifiers at press: evidence now names the marquee, Lasso and Polygonal Lasso tests (still partial: no marquee ⇧⌥ intersect test). ⌥-wheel zoom: missing → partial (works at ×1.1 a notch; #217 asked for ~5 %) | diff --git a/scorecard/bugs.toml b/scorecard/bugs.toml index a4620bf7d6..2d701c9b9a 100644 --- a/scorecard/bugs.toml +++ b/scorecard/bugs.toml @@ -191,9 +191,9 @@ note = "edit.transform follows a targeted alpha channel or Quick Mask (explicit [[item]] id = "BUG-207-5" target = "Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe" -status = "missing" +status = "done" issue = 207 -note = "Only smudge_drags_colour_along_the_stroke (retouch.rs:407)" +note = "Every retouch tool (Clone Stamp, Pattern Stamp, Healing, Spot Healing, Dodge, Burn, Sponge, Blur, Sharpen, Smudge, History Brush, Remove) is tested to paint only a targeted mask, only a targeted alpha channel, and to follow the Channels panel target (engine retouch_cmds/tests.rs retouch_tools_paint_only_the_targeted_mask, retouch_tools_paint_only_the_targeted_alpha_channel, retouch_tools_follow_the_channels_panel_target, retouch_tools_paint_the_quick_mask, retouch_targets_fail_gracefully). Sample All Layers changes the result over two layers (sample_all_layers_blur_and_sharpen_work_on_an_empty_layer, sample_all_layers_smudge_drags_colour_from_below, sample_all_layers_spot_healing_heals_onto_an_empty_layer, clone_stamp_sample_all_layers_onto_empty_layer_and_opacity; ui retouch_ui.rs sample_all_layers_reaches_the_command); no smudge fringe (smudge_across_a_transparent_edge_has_no_dark_fringe). Brush/Eraser/Gradient/Bucket targets: tests.rs painting_can_target_the_layer_mask, channel_cmds/tests.rs painting_filtering_and_adjusting_into_an_alpha_channel. Not covered: Pencil and Mixer Brush into a mask or channel" [[item]] id = "BUG-208-1" @@ -221,7 +221,7 @@ id = "BUG-208-4" target = "Add/subtract/intersect from modifiers pressed before the drag, kept by a test" status = "partial" issue = 208 -note = "Mods captured at press (canvas.rs:1679, used :1779); only a badge test (tool_feedback.rs:195)" +note = "Mods captured at press. Marquee: Shift at the press adds and Alt subtracts, with no square or centring (marquee_tests.rs modifiers_held_before_the_drag_pick_the_mode_not_the_shape). Lasso: Alt, Shift and Shift+Alt at the start subtract, add and intersect (lasso_ui/tests.rs initial_alt_still_subtracts_and_initial_shift_still_adds). Polygonal Lasso: Shift/Alt at the first click keep the selection and combine (polygon_lasso_tests.rs modifiers_at_the_first_click_keep_and_combine_the_selection). Missing: a test that Shift+Alt held before a marquee drag intersects" [[item]] id = "BUG-208-5" diff --git a/scorecard/tools.toml b/scorecard/tools.toml index 6c9f5f8d55..540293a6d4 100644 --- a/scorecard/tools.toml +++ b/scorecard/tools.toml @@ -197,9 +197,9 @@ note = "select.convertToShape with tolerance (vector_cmds.rs:1256); radius as a [[item]] id = "TOOL-214-13" target = "Mask Properties: Density and Feather controls" -status = "partial" +status = "done" issue = 214 -note = "Vector-mask density/feather in the engine (vector_cmds.rs:948); no UI controls" +note = "Properties panel shows Density (%) and Feather (px) sliders for a targeted pixel mask (layer.layerMask.edit) and a targeted vector mask (layer.vectorMask.edit), non-destructive and one undo step per drag, with Photoshop's Refine row (mask_props_ui.rs; mask_props_ui_tests.rs pixel_mask_properties_follow_target_for_raster_and_adjustment_in_both_themes, mask_slider_drags_preview_live_and_undo_as_separate_gestures, vector_mask_properties_edit_density_and_feather)" [[item]] id = "TOOL-214-14" diff --git a/scorecard/type.toml b/scorecard/type.toml index faf1f88dc5..ece895b305 100644 --- a/scorecard/type.toml +++ b/scorecard/type.toml @@ -49,9 +49,9 @@ note = "Alt+Left/Right at a collapsed caret kerns the pair (type_tool.rs kern_pa [[item]] id = "TYPE-218-7" target = "Warp Text dialog previews live and opens with the layer's current warp" -status = "missing" +status = "done" issue = 218 -note = "view_cmds.rs:834 always seeds arc, bend 50" +note = "Type > Warp Text opens with the shown layer's warp, or None, never remembered values (filter_dialog.rs warp_defaults; warp_text_dialog_tests.rs warp_text_opens_with_the_type_layers_current_warp, warp_text_opens_at_none_for_a_layer_without_warp, remembered_warp_values_never_override_the_layers_warp). The dialog previews live without editing the document, Cancel leaves no step and OK is one undoable step (warp_text_dialog_previews_the_warp_without_editing_the_document, cancelling_warp_text_leaves_the_document_and_history_untouched, confirming_warp_text_is_one_undoable_step); the reduced-proxy preview matches the full-size result (filter_dialog.rs warp_text_preview_matches_the_full_size_result_on_a_reduced_proxy)" [[item]] id = "TYPE-218-8" diff --git a/scorecard/ui.toml b/scorecard/ui.toml index 8ffa8ca4be..1f784b832a 100644 --- a/scorecard/ui.toml +++ b/scorecard/ui.toml @@ -127,9 +127,9 @@ note = "panels.rs:1837 single field + hex/RGB readout" [[item]] id = "UI-217-18" target = "Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped" -status = "missing" +status = "partial" issue = 217 -note = "canvas.rs:1107-1125 no Alt handling" +note = "Alt+wheel zooms around the pointer, one step per notch applied the frame it arrives (wheel_nav.rs; input_tests.rs alt_scroll_zooms_in_steps_around_the_pointer, wheel_nav.rs alt_scroll_zooms_ten_percent_per_notch), but the step is x1.1 (10 %), not the ~5 % this row asks for: #1718 changed it from x1.05 after measuring Photoshop, so the row's target is in question. Status bar zoom field and Fit button fit inside the bar in every theme (status_bar_tests.rs status_bar_controls_sit_inside_the_bar_with_even_margins, #2823); the Navigator zoom controls are not checked" [[item]] id = "UI-217-19" From d553a1b29fbfda42a66f58d18542766927f4d2dc Mon Sep 17 00:00:00 2001 From: David Mann Date: Tue, 13 Oct 2026 01:45:06 +0200 Subject: [PATCH 2/7] Regenerate docs/scorecard.md after merging main Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/scorecard.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/scorecard.md b/docs/scorecard.md index d2ee641b1e..a7accede67 100644 --- a/docs/scorecard.md +++ b/docs/scorecard.md @@ -8,13 +8,13 @@ Generated by `cargo xtask scorecard` from `perf/budgets.toml`, `perf/baseline.js |---|---:|---:|---:|---| | [Performance](#performance) | 3 | 22 | 22 | 56 scenarios: 3 within budget, 22 over budget or failing, 9 tracked only, 17 not run, 5 not measurable yet (baseline 2026-10-05) | | [File compatibility](#file-compatibility) | 6 | 13 | 8 | io corpus: oracle ≥ 146/170, round trip ≥ 169/170; psd-tools corpus: oracle ≥ 236/309, round trip ≥ 308/309; photoshop oracles: oracle ≥ 133/256, round trip ≥ 258/256 | -| [Tools](#tools) | 28 | 14 | 1 | | -| [Workspace and UI](#workspace-and-ui) | 13 | 5 | 5 | settings that do nothing: 26 of 156 (target 0) | -| [Type](#type) | 4 | 2 | 3 | | +| [Tools](#tools) | 29 | 13 | 1 | | +| [Workspace and UI](#workspace-and-ui) | 13 | 6 | 4 | settings that do nothing: 26 of 156 (target 0) | +| [Type](#type) | 5 | 2 | 2 | | | [Automation](#automation) | 5 | 2 | 4 | 631 of 631 menu items live (100.0%) | | [Reliability](#reliability) | 5 | 2 | 0 | never-crash lints on 28 of 28 crates; panic_hunt present | | [Distribution](#distribution) | 5 | 4 | 2 | | -| [Open bugs](#open-bugs) | 29 | 2 | 1 | | +| [Open bugs](#open-bugs) | 30 | 2 | 0 | | ## Performance @@ -157,7 +157,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t | TOOL-214-10 | Pen: Alt breaks a handle, Shift 45 deg, Ctrl direct-selects, Backspace, close-drag handle | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Ctrl/Cmd = Direct Selection and Alt = Convert Point on existing paths (direct_select.rs, #790); Backspace/Delete retracts the last point while drawing (#1466); Alt during a drag breaks the handle pair, Alt-drag turns the last anchor's outgoing handle alone, and dragging on the first anchor closes with that anchor's handles (vector_ui.rs, #3306); no Shift 45 deg | | TOOL-214-11 | Stroke Path dialog: pick any brush-based tool, Simulate Pressure | done | [#214](https://github.com/storytold/photocraft/issues/214) | path.stroke tool: Brush, Pencil, Eraser and every other brush-based tool (Background Eraser, Clone/Pattern Stamp, Healing/Spot Healing Brush, History Brush, Blur, Sharpen, Smudge, Dodge, Burn, Sponge, Color Replacement, Mixer Brush: their paint.* command along the path, one step) plus simulatePressure (taper both ends); Stroke Path dialog from the Pen menu, the Paths panel menu and Alt-click on its Stroke button (#2978) | | TOOL-214-12 | Shapes: on-canvas corner radius handles, shape feather, selection to shape with tolerance | partial | [#214](https://github.com/storytold/photocraft/issues/214) | select.convertToShape with tolerance (vector_cmds.rs:1256); radius as a field only | -| TOOL-214-13 | Mask Properties: Density and Feather controls | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Vector-mask density/feather in the engine (vector_cmds.rs:948); no UI controls | +| TOOL-214-13 | Mask Properties: Density and Feather controls | done | [#214](https://github.com/storytold/photocraft/issues/214) | Properties panel shows Density (%) and Feather (px) sliders for a targeted pixel mask (layer.layerMask.edit) and a targeted vector mask (layer.vectorMask.edit), non-destructive and one undo step per drag, with Photoshop's Refine row (mask_props_ui.rs; mask_props_ui_tests.rs pixel_mask_properties_follow_target_for_raster_and_adjustment_in_both_themes, mask_slider_drags_preview_live_and_undo_as_separate_gestures, vector_mask_properties_edit_density_and_feather) | | TOOL-214-14 | Vanishing Point window: draw and edit planes, paste, clone in perspective | partial | [#214](https://github.com/storytold/photocraft/issues/214) | filter.vanishingPoint (vp_cmds.rs:15); on-canvas plane editor (vp_ui.rs: Create/Edit Plane, edge nodes, valid/doubtful/invalid grid colours, Grid Size, clipboard pasted onto the plane on OK); clone stamp, marquee and tear-off planes in the window still missing | | TOOL-214-15 | Content-Aware Fill workspace: paint the sampling area, preview, rotate/scale/mirror, new layer | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Engine sampling auto, rect, custom (edit_menu_cmds.rs:324); generic dialog | | TOOL-214-16 | Liquify: redo (Cmd+Shift+Z) | done | [#214](https://github.com/storytold/photocraft/issues/214) | liquify_ui.rs supports bounded redo through Cmd+Shift+Z and the control channel; new strokes clear redo | @@ -199,7 +199,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | UI-217-15 | Curves: smoothing / pencil mode, black/grey/white eyedroppers, tooltips | done | [#217](https://github.com/storytold/photocraft/issues/217) | Curves editor (adjust_editors.rs, dialog and Properties): Edit points / Draw (pencil) buttons and Smooth, all with tooltips; pencil curves are 256-level maps (Adjustment::Curves pencil, params pencil/smooth, PSD curv map form and smart-filter Mpng; #3088). Set Black/Neutral Gray/White Point eyedroppers in the Image > Adjustments > Curves dialog (adjust_dialog.rs, #873) and in a Curves adjustment layer's Properties panel (layer_picker.rs: a click on the image is one layer.setAdjustment with the eyedropper param, sampling below the layer; Esc or another tool disarms; #3110) | | UI-217-16 | Hue/Saturation: Saturation and Lightness sliders get hue-following colour tracks | done | [#217](https://github.com/storytold/photocraft/issues/217) | saturation_track/lightness_track (adjust_editors.rs): grey -> the hue and black -> the hue -> white, recolouring as the Hue slider moves; saturation_and_lightness_tracks_follow_the_hue | | UI-217-17 | Color panel: wheel plus RGB/HSB/CMYK/Lab/Gray/Web slider modes; resizes with its group | missing | [#217](https://github.com/storytold/photocraft/issues/217) | panels.rs:1837 single field + hex/RGB readout | -| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | missing | [#217](https://github.com/storytold/photocraft/issues/217) | canvas.rs:1107-1125 no Alt handling | +| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | partial | [#217](https://github.com/storytold/photocraft/issues/217) | Alt+wheel zooms around the pointer, one step per notch applied the frame it arrives (wheel_nav.rs; input_tests.rs alt_scroll_zooms_in_steps_around_the_pointer, wheel_nav.rs alt_scroll_zooms_ten_percent_per_notch), but the step is x1.1 (10 %), not the ~5 % this row asks for: #1718 changed it from x1.05 after measuring Photoshop, so the row's target is in question. Status bar zoom field and Fit button fit inside the bar in every theme (status_bar_tests.rs status_bar_controls_sit_inside_the_bar_with_even_margins, #2823); the Navigator zoom controls are not checked | | UI-217-19 | Shortcut hints rendered per platform; Reveal label per OS | done | [#217](https://github.com/storytold/photocraft/issues/217) | hints and tooltips go through shortcuts::pretty (6266b7a9, #262; pretty_uses_the_platform_notation); menus::reveal_label names Reveal in Finder per OS (Show in Explorer / Show in Folder) in the Smart Objects menu and the tab menu; reveal_label_names_the_platform_file_manager + smart_objects_reveal_item_names_the_platform_file_manager | | UI-217-20 | 'Show rulers in new documents' preference; guides stored as f64 | done | [#217](https://github.com/storytold/photocraft/issues/217) | View › Rulers is remembered in unitsAndRulers.showRulers and applied at launch and on change (#2918; rulers_open_as_last_set_after_a_restart); doc Guides are Vec through New Guide, .pcraft and PSD 1032 (guides_keep_sub_pixel_positions_through_pcraft_and_psd) | | UI-217-21 | One Preset Manager for every preset kind with folders, search, reorder, load/save sets | partial | [#217](https://github.com/storytold/photocraft/issues/217) | edit_menu_cmds.rs:714 covers brushes, custom shapes, patterns with reorder | @@ -216,7 +216,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | TYPE-218-4 | Variable font axis sliders from the font's axes; opsz follows the point size | done | [#218](https://github.com/storytold/photocraft/issues/218) | One slider per axis of the style's font in the Character section (Properties and Window > Character), setting type.setStyle variations; opsz follows the type size unless set (layout.rs variation_list); a style or weight resets the wght axis (#2985). PSD does not round-trip axis values yet | | TYPE-218-5 | OpenType UI: Character panel buttons, Numerals and Stylistic Sets submenus | partial | [#218](https://github.com/storytold/photocraft/issues/218) | Type > OpenType toggles (type_extra_cmds.rs:512). Character panel (and the Properties Character section) has Photoshop's eight OpenType buttons: Standard Ligatures, Contextual Alternates, Discretionary Ligatures, Swash, Stylistic Alternates, Titling Alternates, Ordinals, Fractions, pressed while the feature is on at the selection and dispatching the type.openType.* commands (type_tool.rs opentype_row; character_panel_opentype_buttons_toggle_and_show_the_feature, #3752). Still missing: the Numerals and Stylistic Sets submenus, and greying out features the font lacks | | TYPE-218-6 | Manual pair kerning (Alt+arrows), optical kerning rendered, both round-trip PSD (#206) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Alt+Left/Right at a collapsed caret kerns the pair (type_tool.rs kern_pair, 20 per step and 100 with Cmd; type_tool_alt_arrows_kern_the_pair). Optical kerning is computed from the glyph outlines in text/src/optical.rs and applied by layout.rs when the run's mode is Optical (optical_matches_photoshop, optical_kerning_tightens_open_pairs). Both modes and manual values round-trip through PSD (io/tests/psd_kerning.rs; the optical mode travels in Txt2, txt2_carries_optical_kerning) | -| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | missing | [#218](https://github.com/storytold/photocraft/issues/218) | view_cmds.rs:834 always seeds arc, bend 50 | +| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | done | [#218](https://github.com/storytold/photocraft/issues/218) | Type > Warp Text opens with the shown layer's warp, or None, never remembered values (filter_dialog.rs warp_defaults; warp_text_dialog_tests.rs warp_text_opens_with_the_type_layers_current_warp, warp_text_opens_at_none_for_a_layer_without_warp, remembered_warp_values_never_override_the_layers_warp). The dialog previews live without editing the document, Cancel leaves no step and OK is one undoable step (warp_text_dialog_previews_the_warp_without_editing_the_document, cancelling_warp_text_leaves_the_document_and_history_untouched, confirming_warp_text_is_one_undoable_step); the reduced-proxy preview matches the full-size result (filter_dialog.rs warp_text_preview_matches_the_full_size_result_on_a_reduced_proxy) | | TYPE-218-8 | Text editing: select all, double/triple/quadruple-click selection, paste, with tests | done | [#218](https://github.com/storytold/photocraft/issues/218) | Like Photoshop, 2 clicks select the word, 3 the laid-out line (a column in vertical type), 4 the paragraph up to the hard return, 5 all text, and the next quick click starts over (#3493; type_tool.rs next_click_count, click_selection, multi_click). Tested through real canvas clicks in point, paragraph and vertical type, with paste replacing the selection and Cmd+A selecting all (type_tool_tests.rs multi_click_selects_word_line_paragraph_and_all_in_point_text, multi_click_separates_wrapped_lines_from_paragraphs, click_counts_cycle_and_restart, click_selection_without_layout_and_on_hostile_input, multi_click_without_a_session_does_nothing) | | TYPE-218-9 | Distort/Perspective/Warp on live type as in Photoshop (was: offer 'Rasterize and continue?'; Photoshop doesn't prompt) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Photoshop 2026 prompts for none of these: Edit › Transform › Warp on live type stays enabled with no rasterize prompt and offers only the warp styles (the mesh can't be dragged), so the type stays editable; Distort, Perspective and the split warps are greyed. PhotoCraft does the same: Warp on type commits the layer's Warp Text in one step (transform_tool.rs enter_type_warp, warp_cmds.rs warp_type_layer, #3004; warp_on_type_takes_a_style_and_keeps_the_type_editable), Distort/Perspective greyed (enable_rules.rs, #2701) | @@ -298,9 +298,9 @@ Never-crash attribute on 28 of 28 crate roots. | BUG-207-2 | Sample All Layers applies to Blur, Sharpen and Smudge | done | [#207](https://github.com/storytold/photocraft/issues/207) | retouch_ui.rs passes sampleAllLayers to paint.blur/sharpen/smudge; sample_all_layers_reaches_the_command (e2444ce, #234) | | BUG-207-3 | Smudge mixes premultiplied RGBA (no dark fringe at transparent edges) | done | [#207](https://github.com/storytold/photocraft/issues/207) | paint/src/retouch.rs premultiplies; smudge_into_transparency_leaves_no_dark_fringe (e2444ce, #234) | | BUG-207-4 | edit.transform transforms a targeted alpha channel | done | [#207](https://github.com/storytold/photocraft/issues/207) | edit.transform follows a targeted alpha channel or Quick Mask (explicit target since #242, Channels panel target with no target/layer param since #2835); Edit > Transform > Rotate/Flip are routed to the target too; transforms_follow_the_targeted_alpha_channel | -| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | missing | [#207](https://github.com/storytold/photocraft/issues/207) | Only smudge_drags_colour_along_the_stroke (retouch.rs:407) | +| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | done | [#207](https://github.com/storytold/photocraft/issues/207) | Every retouch tool (Clone Stamp, Pattern Stamp, Healing, Spot Healing, Dodge, Burn, Sponge, Blur, Sharpen, Smudge, History Brush, Remove) is tested to paint only a targeted mask, only a targeted alpha channel, and to follow the Channels panel target (engine retouch_cmds/tests.rs retouch_tools_paint_only_the_targeted_mask, retouch_tools_paint_only_the_targeted_alpha_channel, retouch_tools_follow_the_channels_panel_target, retouch_tools_paint_the_quick_mask, retouch_targets_fail_gracefully). Sample All Layers changes the result over two layers (sample_all_layers_blur_and_sharpen_work_on_an_empty_layer, sample_all_layers_smudge_drags_colour_from_below, sample_all_layers_spot_healing_heals_onto_an_empty_layer, clone_stamp_sample_all_layers_onto_empty_layer_and_opacity; ui retouch_ui.rs sample_all_layers_reaches_the_command); no smudge fringe (smudge_across_a_transparent_edge_has_no_dark_fringe). Brush/Eraser/Gradient/Bucket targets: tests.rs painting_can_target_the_layer_mask, channel_cmds/tests.rs painting_filtering_and_adjusting_into_an_alpha_channel. Not covered: Pencil and Mixer Brush into a mask or channel | | BUG-208-1 | Shift while dragging a Rect/Elliptical Marquee constrains to a square/circle | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners applies Shift via Drag::marquee_mods; marquee_tests.rs::shift_during_the_drag_draws_a_square_and_the_readout_follows covers the drag | | BUG-208-2 | Alt while dragging a marquee draws from the centre | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners centres Alt drags; marquee_tests.rs::alt_draws_from_the_centre_and_shift_alt_a_centred_circle verifies rectangles and ellipses | | BUG-208-3 | W x H px readout beside the cursor while dragging a marquee | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_readout draws the readout; marquee_tests.rs asserts dimensions while dragging and its removal after release | -| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press (canvas.rs:1679, used :1779); only a badge test (tool_feedback.rs:195) | +| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press. Marquee: Shift at the press adds and Alt subtracts, with no square or centring (marquee_tests.rs modifiers_held_before_the_drag_pick_the_mode_not_the_shape). Lasso: Alt, Shift and Shift+Alt at the start subtract, add and intersect (lasso_ui/tests.rs initial_alt_still_subtracts_and_initial_shift_still_adds). Polygonal Lasso: Shift/Alt at the first click keep the selection and combine (polygon_lasso_tests.rs modifiers_at_the_first_click_keep_and_combine_the_selection). Missing: a test that Shift+Alt held before a marquee drag intersects | | BUG-208-5 | Kittest: Shift drag gives a square, Alt drag is centred, readout matches the size | done | [#208](https://github.com/storytold/photocraft/issues/208) | crates/ui-egui/src/marquee_tests.rs covers Shift, Alt, selection bounds, W/H readout and drag completion | From 32d965cf503f8093df6e92c6dd3c1fd099bd9936 Mon Sep 17 00:00:00 2001 From: David Mann Date: Wed, 14 Oct 2026 15:29:17 +0200 Subject: [PATCH 3/7] Regenerate docs/scorecard.md after merging main Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/scorecard.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/scorecard.md b/docs/scorecard.md index 56a16654bd..d30519331a 100644 --- a/docs/scorecard.md +++ b/docs/scorecard.md @@ -8,13 +8,13 @@ Generated by `cargo xtask scorecard` from `perf/budgets.toml`, `perf/baseline.js |---|---:|---:|---:|---| | [Performance](#performance) | 3 | 22 | 22 | 56 scenarios: 3 within budget, 22 over budget or failing, 9 tracked only, 17 not run, 5 not measurable yet (baseline 2026-10-05) | | [File compatibility](#file-compatibility) | 7 | 13 | 7 | io corpus: oracle ≥ 146/170, round trip ≥ 169/170; psd-tools corpus: oracle ≥ 236/309, round trip ≥ 308/309; photoshop oracles: oracle ≥ 145/256, round trip ≥ 258/256 | -| [Tools](#tools) | 29 | 13 | 1 | | -| [Workspace and UI](#workspace-and-ui) | 13 | 6 | 4 | settings that do nothing: 26 of 157 (target 0) | -| [Type](#type) | 4 | 3 | 2 | | +| [Tools](#tools) | 30 | 12 | 1 | | +| [Workspace and UI](#workspace-and-ui) | 13 | 7 | 3 | settings that do nothing: 26 of 157 (target 0) | +| [Type](#type) | 5 | 3 | 1 | | | [Automation](#automation) | 5 | 2 | 4 | 631 of 631 menu items live (100.0%) | | [Reliability](#reliability) | 5 | 2 | 0 | never-crash lints on 28 of 28 crates; panic_hunt present | | [Distribution](#distribution) | 5 | 4 | 2 | | -| [Open bugs](#open-bugs) | 29 | 2 | 1 | | +| [Open bugs](#open-bugs) | 30 | 2 | 0 | | ## Performance @@ -157,7 +157,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t | TOOL-214-10 | Pen: Alt breaks a handle, Shift 45 deg, Ctrl direct-selects, Backspace, close-drag handle | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Ctrl/Cmd = Direct Selection and Alt = Convert Point on existing paths (direct_select.rs, #790); Backspace/Delete retracts the last point while drawing (#1466); Alt during a drag breaks the handle pair, Alt-drag turns the last anchor's outgoing handle alone, and dragging on the first anchor closes with that anchor's handles (vector_ui.rs, #3306); no Shift 45 deg | | TOOL-214-11 | Stroke Path dialog: pick any brush-based tool, Simulate Pressure | done | [#214](https://github.com/storytold/photocraft/issues/214) | path.stroke tool: Brush, Pencil, Eraser and every other brush-based tool (Background Eraser, Clone/Pattern Stamp, Healing/Spot Healing Brush, History Brush, Blur, Sharpen, Smudge, Dodge, Burn, Sponge, Color Replacement, Mixer Brush: their paint.* command along the path, one step) plus simulatePressure (taper both ends); Stroke Path dialog from the Pen menu, the Paths panel menu and Alt-click on its Stroke button (#2978) | | TOOL-214-12 | Shapes: on-canvas corner radius handles, shape feather, selection to shape with tolerance | partial | [#214](https://github.com/storytold/photocraft/issues/214) | select.convertToShape with tolerance (vector_cmds.rs:1256); radius as a field only | -| TOOL-214-13 | Mask Properties: Density and Feather controls | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Vector-mask density/feather in the engine (vector_cmds.rs:948); no UI controls | +| TOOL-214-13 | Mask Properties: Density and Feather controls | done | [#214](https://github.com/storytold/photocraft/issues/214) | Properties panel shows Density (%) and Feather (px) sliders for a targeted pixel mask (layer.layerMask.edit) and a targeted vector mask (layer.vectorMask.edit), non-destructive and one undo step per drag, with Photoshop's Refine row (mask_props_ui.rs; mask_props_ui_tests.rs pixel_mask_properties_follow_target_for_raster_and_adjustment_in_both_themes, mask_slider_drags_preview_live_and_undo_as_separate_gestures, vector_mask_properties_edit_density_and_feather) | | TOOL-214-14 | Vanishing Point window: draw and edit planes, paste, clone in perspective | partial | [#214](https://github.com/storytold/photocraft/issues/214) | filter.vanishingPoint (vp_cmds.rs:15); on-canvas plane editor (vp_ui.rs: Create/Edit Plane, edge nodes, valid/doubtful/invalid grid colours, Grid Size, clipboard pasted onto the plane on OK); clone stamp, marquee and tear-off planes in the window still missing | | TOOL-214-15 | Content-Aware Fill workspace: paint the sampling area, preview, rotate/scale/mirror, new layer | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Engine sampling auto, rect, custom (edit_menu_cmds.rs:324); generic dialog | | TOOL-214-16 | Liquify: redo (Cmd+Shift+Z) | done | [#214](https://github.com/storytold/photocraft/issues/214) | liquify_ui.rs supports bounded redo through Cmd+Shift+Z and the control channel; new strokes clear redo | @@ -199,7 +199,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | UI-217-15 | Curves: smoothing / pencil mode, black/grey/white eyedroppers, tooltips | done | [#217](https://github.com/storytold/photocraft/issues/217) | Curves editor (adjust_editors.rs, dialog and Properties): Edit points / Draw (pencil) buttons and Smooth, all with tooltips; pencil curves are 256-level maps (Adjustment::Curves pencil, params pencil/smooth, PSD curv map form and smart-filter Mpng; #3088). Set Black/Neutral Gray/White Point eyedroppers in the Image > Adjustments > Curves dialog (adjust_dialog.rs, #873) and in a Curves adjustment layer's Properties panel (layer_picker.rs: a click on the image is one layer.setAdjustment with the eyedropper param, sampling below the layer; Esc or another tool disarms; #3110) | | UI-217-16 | Hue/Saturation: Saturation and Lightness sliders get hue-following colour tracks | done | [#217](https://github.com/storytold/photocraft/issues/217) | saturation_track/lightness_track (adjust_editors.rs): grey -> the hue and black -> the hue -> white, recolouring as the Hue slider moves; saturation_and_lightness_tracks_follow_the_hue | | UI-217-17 | Color panel: wheel plus RGB/HSB/CMYK/Lab/Gray/Web slider modes; resizes with its group | missing | [#217](https://github.com/storytold/photocraft/issues/217) | panels.rs:1837 single field + hex/RGB readout | -| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | missing | [#217](https://github.com/storytold/photocraft/issues/217) | canvas.rs:1107-1125 no Alt handling | +| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | partial | [#217](https://github.com/storytold/photocraft/issues/217) | Alt+wheel zooms around the pointer, one step per notch applied the frame it arrives (wheel_nav.rs; input_tests.rs alt_scroll_zooms_in_steps_around_the_pointer, wheel_nav.rs alt_scroll_zooms_ten_percent_per_notch), but the step is x1.1 (10 %), not the ~5 % this row asks for: #1718 changed it from x1.05 after measuring Photoshop, so the row's target is in question. Status bar zoom field and Fit button fit inside the bar in every theme (status_bar_tests.rs status_bar_controls_sit_inside_the_bar_with_even_margins, #2823); the Navigator zoom controls are not checked | | UI-217-19 | Shortcut hints rendered per platform; Reveal label per OS | done | [#217](https://github.com/storytold/photocraft/issues/217) | hints and tooltips go through shortcuts::pretty (6266b7a9, #262; pretty_uses_the_platform_notation); menus::reveal_label names Reveal in Finder per OS (Show in Explorer / Show in Folder) in the Smart Objects menu and the tab menu; reveal_label_names_the_platform_file_manager + smart_objects_reveal_item_names_the_platform_file_manager | | UI-217-20 | 'Show rulers in new documents' preference; guides stored as f64 | done | [#217](https://github.com/storytold/photocraft/issues/217) | View › Rulers is remembered in unitsAndRulers.showRulers and applied at launch and on change (#2918; rulers_open_as_last_set_after_a_restart); doc Guides are Vec through New Guide, .pcraft and PSD 1032 (guides_keep_sub_pixel_positions_through_pcraft_and_psd) | | UI-217-21 | One Preset Manager for every preset kind with folders, search, reorder, load/save sets | partial | [#217](https://github.com/storytold/photocraft/issues/217) | edit_menu_cmds.rs:714 covers brushes, custom shapes, patterns with reorder | @@ -216,7 +216,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | TYPE-218-4 | Variable font axis sliders from the font's axes; opsz follows the point size | done | [#218](https://github.com/storytold/photocraft/issues/218) | One slider per axis of the style's font in the Character section (Properties and Window > Character), setting type.setStyle variations; opsz follows the type size unless set (layout.rs variation_list); a style or weight resets the wght axis (#2985). PSD does not round-trip axis values yet | | TYPE-218-5 | OpenType UI: Character panel buttons, Numerals and Stylistic Sets submenus | partial | [#218](https://github.com/storytold/photocraft/issues/218) | Type > OpenType toggles (type_extra_cmds.rs:512). Character panel (and the Properties Character section) has Photoshop's eight OpenType buttons: Standard Ligatures, Contextual Alternates, Discretionary Ligatures, Swash, Stylistic Alternates, Titling Alternates, Ordinals, Fractions, pressed while the feature is on at the selection and dispatching the type.openType.* commands (type_tool.rs opentype_row; character_panel_opentype_buttons_toggle_and_show_the_feature, #3752). Still missing: the Numerals and Stylistic Sets submenus, and greying out features the font lacks | | TYPE-218-6 | Manual pair kerning (Alt+arrows), optical kerning rendered, both round-trip PSD (#206) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Alt+Left/Right at a collapsed caret kerns the pair (type_tool.rs kern_pair, 20 per step and 100 with Cmd; type_tool_alt_arrows_kern_the_pair). Optical kerning is computed from the glyph outlines in text/src/optical.rs and applied by layout.rs when the run's mode is Optical (optical_matches_photoshop, optical_kerning_tightens_open_pairs). Both modes and manual values round-trip through PSD (io/tests/psd_kerning.rs; the optical mode travels in Txt2, txt2_carries_optical_kerning) | -| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | missing | [#218](https://github.com/storytold/photocraft/issues/218) | view_cmds.rs:834 always seeds arc, bend 50 | +| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | done | [#218](https://github.com/storytold/photocraft/issues/218) | Type > Warp Text opens with the shown layer's warp, or None, never remembered values (filter_dialog.rs warp_defaults; warp_text_dialog_tests.rs warp_text_opens_with_the_type_layers_current_warp, warp_text_opens_at_none_for_a_layer_without_warp, remembered_warp_values_never_override_the_layers_warp). The dialog previews live without editing the document, Cancel leaves no step and OK is one undoable step (warp_text_dialog_previews_the_warp_without_editing_the_document, cancelling_warp_text_leaves_the_document_and_history_untouched, confirming_warp_text_is_one_undoable_step); the reduced-proxy preview matches the full-size result (filter_dialog.rs warp_text_preview_matches_the_full_size_result_on_a_reduced_proxy) | | TYPE-218-8 | Text editing: select all, double/triple/quadruple-click selection, paste, with tests | done | [#218](https://github.com/storytold/photocraft/issues/218) | Like Photoshop, 2 clicks select the word, 3 the laid-out line (a column in vertical type), 4 the paragraph up to the hard return, 5 all text, and the next quick click starts over (#3493; type_tool.rs next_click_count, click_selection, multi_click). Tested through real canvas clicks in point, paragraph and vertical type, with paste replacing the selection and Cmd+A selecting all (type_tool_tests.rs multi_click_selects_word_line_paragraph_and_all_in_point_text, multi_click_separates_wrapped_lines_from_paragraphs, click_counts_cycle_and_restart, click_selection_without_layout_and_on_hostile_input, multi_click_without_a_session_does_nothing) | | TYPE-218-9 | Distort/Perspective/Warp on live type as in Photoshop (was: offer 'Rasterize and continue?'; Photoshop doesn't prompt) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Photoshop 2026 prompts for none of these: Edit › Transform › Warp on live type stays enabled with no rasterize prompt and offers only the warp styles (the mesh can't be dragged), so the type stays editable; Distort, Perspective and the split warps are greyed. PhotoCraft does the same: Warp on type commits the layer's Warp Text in one step (transform_tool.rs enter_type_warp, warp_cmds.rs warp_type_layer, #3004; warp_on_type_takes_a_style_and_keeps_the_type_editable), Distort/Perspective greyed (enable_rules.rs, #2701) | @@ -298,9 +298,9 @@ Never-crash attribute on 28 of 28 crate roots. | BUG-207-2 | Sample All Layers applies to Blur, Sharpen and Smudge | done | [#207](https://github.com/storytold/photocraft/issues/207) | retouch_ui.rs passes sampleAllLayers to paint.blur/sharpen/smudge; sample_all_layers_reaches_the_command (e2444ce, #234) | | BUG-207-3 | Smudge mixes premultiplied RGBA (no dark fringe at transparent edges) | done | [#207](https://github.com/storytold/photocraft/issues/207) | paint/src/retouch.rs premultiplies; smudge_into_transparency_leaves_no_dark_fringe (e2444ce, #234) | | BUG-207-4 | edit.transform transforms a targeted alpha channel | done | [#207](https://github.com/storytold/photocraft/issues/207) | edit.transform follows a targeted alpha channel or Quick Mask (explicit target since #242, Channels panel target with no target/layer param since #2835); Edit > Transform > Rotate/Flip are routed to the target too; transforms_follow_the_targeted_alpha_channel | -| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | missing | [#207](https://github.com/storytold/photocraft/issues/207) | Only smudge_drags_colour_along_the_stroke (retouch.rs:407) | +| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | done | [#207](https://github.com/storytold/photocraft/issues/207) | Every retouch tool (Clone Stamp, Pattern Stamp, Healing, Spot Healing, Dodge, Burn, Sponge, Blur, Sharpen, Smudge, History Brush, Remove) is tested to paint only a targeted mask, only a targeted alpha channel, and to follow the Channels panel target (engine retouch_cmds/tests.rs retouch_tools_paint_only_the_targeted_mask, retouch_tools_paint_only_the_targeted_alpha_channel, retouch_tools_follow_the_channels_panel_target, retouch_tools_paint_the_quick_mask, retouch_targets_fail_gracefully). Sample All Layers changes the result over two layers (sample_all_layers_blur_and_sharpen_work_on_an_empty_layer, sample_all_layers_smudge_drags_colour_from_below, sample_all_layers_spot_healing_heals_onto_an_empty_layer, clone_stamp_sample_all_layers_onto_empty_layer_and_opacity; ui retouch_ui.rs sample_all_layers_reaches_the_command); no smudge fringe (smudge_across_a_transparent_edge_has_no_dark_fringe). Brush/Eraser/Gradient/Bucket targets: tests.rs painting_can_target_the_layer_mask, channel_cmds/tests.rs painting_filtering_and_adjusting_into_an_alpha_channel. Not covered: Pencil and Mixer Brush into a mask or channel | | BUG-208-1 | Shift while dragging a Rect/Elliptical Marquee constrains to a square/circle | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners applies Shift via Drag::marquee_mods; marquee_tests.rs::shift_during_the_drag_draws_a_square_and_the_readout_follows covers the drag | | BUG-208-2 | Alt while dragging a marquee draws from the centre | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners centres Alt drags; marquee_tests.rs::alt_draws_from_the_centre_and_shift_alt_a_centred_circle verifies rectangles and ellipses | | BUG-208-3 | W x H px readout beside the cursor while dragging a marquee | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_readout draws the readout; marquee_tests.rs asserts dimensions while dragging and its removal after release | -| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press (canvas.rs:1679, used :1779); only a badge test (tool_feedback.rs:195) | +| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press. Marquee: Shift at the press adds and Alt subtracts, with no square or centring (marquee_tests.rs modifiers_held_before_the_drag_pick_the_mode_not_the_shape). Lasso: Alt, Shift and Shift+Alt at the start subtract, add and intersect (lasso_ui/tests.rs initial_alt_still_subtracts_and_initial_shift_still_adds). Polygonal Lasso: Shift/Alt at the first click keep the selection and combine (polygon_lasso_tests.rs modifiers_at_the_first_click_keep_and_combine_the_selection). Missing: a test that Shift+Alt held before a marquee drag intersects | | BUG-208-5 | Kittest: Shift drag gives a square, Alt drag is centred, readout matches the size | done | [#208](https://github.com/storytold/photocraft/issues/208) | crates/ui-egui/src/marquee_tests.rs covers Shift, Alt, selection bounds, W/H readout and drag completion | From 8601a7b17057f11210206c7a83dab9d7ba8b8fb4 Mon Sep 17 00:00:00 2001 From: David Mann Date: Thu, 15 Oct 2026 02:05:26 +0200 Subject: [PATCH 4/7] docs: resolve the conflict markers left in the main merge The merge of main (5a4df1a3) committed unresolved conflict markers in the status lines of gaps.md, target-app-parity.md and ui-parity.md and in the Type/Vector rows of target-app-parity.md. Keep main's text and add this PR's own items back: G8 Warp Text preview done (TYPE-218-7), the Type row's evidence, and the selection-modifier and Alt-wheel rows. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/gaps.md | 6 +----- docs/target-app-parity.md | 11 +---------- docs/ui-parity.md | 6 +----- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/docs/gaps.md b/docs/gaps.md index 146892effe..f231dab29a 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,10 +1,6 @@ # Where PhotoCraft falls short of Photoshop -<<<<<<< ours -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (G7: Field Blur's on-canvas pins, #3373; G4: Hue Jitter amount track, #3825 partial; G4: minimum field interaction, #3825 partial; G1: CMYK Invert, Posterize and Threshold on the inks, 16-bit Lab Invert; Photoshop-oracle floor 145/258; G11: `.atn` import maps 112 events: Select and Mask, Filter Gallery Spatter, Ripple, Crystallize, Pattern Fill layers, mask targeting, Step Backward, nudges in points, Bitmap mode; G5: Free Transform H/V skew fields; G9: toolbar tool shortcut editing; refreshed against main: G2, G5, G7, G9, G10, G13, G14, G17 items that landed; G10: DPX read and write, #1049; G4: checkbox-only Brush Settings rows; G11: Load/Save Actions `.atn` landed, AUTO-219-2 partial; G5: hold-a-key spring-loaded tools landed, #2672; G1: #2465 fixed; stale missing-tool rows corrected: Color Replacement, Red Eye and Add/Delete Anchor Point are live tools, so only Art History Brush is missing; no estimate changed; 2026-10-11: G8: the live Warp Text preview is done, TYPE-218-7) · **Target:** Adobe Photoshop 2026 -======= -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (G1: CMYK Hue/Saturation and Color Balance keep the black ink; G1: CMYK Posterize on the stored values, psd-tools oracle floor 242/309; G1: CMYK adjustment layers composite on the document's inks, Photoshop-oracle floor 165/258; G1: CMYK Brightness/Contrast on the inks, CMYK Threshold's luma; G1: modern Brightness/Contrast's brightness curve matches Photoshop, Photoshop-oracle floor 151/258; G1: Lab documents composite on their stored L, a, b, Photoshop-oracle floor 152/258; G1: Levels on whole levels at every step, Photoshop-oracle floor 146/258, psd-tools 238/309; G1: 32-bit Brightness/Contrast legacy, Channel Mixer, Photo Filter and Black & White tint unclipped as in Photoshop, Photoshop-oracle floor 149/258; G1: mask feathers blur with their exact variance, psd-tools oracle floor 240/309; G1: Threshold splits on Photoshop's luminosity, psd-tools oracle floor 241/309; G1: pass-through clipping base with an adjustment renders isolated, psd-tools oracle floor 240/309; G1: 16-bit Posterize as Photoshop bins it, psd-tools oracle floor 241/309; G1: Gradient Map driven by the W3C luminosity, Photoshop-oracle floor 147/258; G7: Field Blur's on-canvas pins, #3373; G4: Hue Jitter amount track, #3825 partial; G4: minimum field interaction, #3825 partial; G1: CMYK Invert, Posterize and Threshold on the inks, 16-bit Lab Invert; Photoshop-oracle floor 145/258; G11: `.atn` import maps 112 events: Select and Mask, Filter Gallery Spatter, Ripple, Crystallize, Pattern Fill layers, mask targeting, Step Backward, nudges in points, Bitmap mode; G5: Free Transform H/V skew fields; G9: toolbar tool shortcut editing; refreshed against main: G2, G5, G7, G9, G10, G13, G14, G17 items that landed; G10: DPX read and write, #1049; G4: checkbox-only Brush Settings rows; G11: Load/Save Actions `.atn` landed, AUTO-219-2 partial; G5: hold-a-key spring-loaded tools landed, #2672; G1: #2465 fixed; stale missing-tool rows corrected: Color Replacement, Red Eye and Add/Delete Anchor Point are live tools, so only Art History Brush is missing; no estimate changed) · **Target:** Adobe Photoshop 2026 ->>>>>>> theirs +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (G1: CMYK Hue/Saturation and Color Balance keep the black ink; G1: CMYK Posterize on the stored values, psd-tools oracle floor 242/309; G1: CMYK adjustment layers composite on the document's inks, Photoshop-oracle floor 165/258; G1: CMYK Brightness/Contrast on the inks, CMYK Threshold's luma; G1: modern Brightness/Contrast's brightness curve matches Photoshop, Photoshop-oracle floor 151/258; G1: Lab documents composite on their stored L, a, b, Photoshop-oracle floor 152/258; G1: Levels on whole levels at every step, Photoshop-oracle floor 146/258, psd-tools 238/309; G1: 32-bit Brightness/Contrast legacy, Channel Mixer, Photo Filter and Black & White tint unclipped as in Photoshop, Photoshop-oracle floor 149/258; G1: mask feathers blur with their exact variance, psd-tools oracle floor 240/309; G1: Threshold splits on Photoshop's luminosity, psd-tools oracle floor 241/309; G1: pass-through clipping base with an adjustment renders isolated, psd-tools oracle floor 240/309; G1: 16-bit Posterize as Photoshop bins it, psd-tools oracle floor 241/309; G1: Gradient Map driven by the W3C luminosity, Photoshop-oracle floor 147/258; G7: Field Blur's on-canvas pins, #3373; G4: Hue Jitter amount track, #3825 partial; G4: minimum field interaction, #3825 partial; G1: CMYK Invert, Posterize and Threshold on the inks, 16-bit Lab Invert; Photoshop-oracle floor 145/258; G11: `.atn` import maps 112 events: Select and Mask, Filter Gallery Spatter, Ripple, Crystallize, Pattern Fill layers, mask targeting, Step Backward, nudges in points, Bitmap mode; G5: Free Transform H/V skew fields; G9: toolbar tool shortcut editing; refreshed against main: G2, G5, G7, G9, G10, G13, G14, G17 items that landed; G10: DPX read and write, #1049; G4: checkbox-only Brush Settings rows; G11: Load/Save Actions `.atn` landed, AUTO-219-2 partial; G5: hold-a-key spring-loaded tools landed, #2672; G1: #2465 fixed; stale missing-tool rows corrected: Color Replacement, Red Eye and Add/Delete Anchor Point are live tools, so only Art History Brush is missing; no estimate changed; 2026-10-11: G8: the live Warp Text preview is done, TYPE-218-7) · **Target:** Adobe Photoshop 2026 Every known shortfall against Photoshop 2026 (27.11.0), one entry each, ranked by user impact on the way to beta. This is the work list agents pick from: take the highest-ranked entry that diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 9fb2679db3..9033163d68 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1,10 +1,6 @@ # PhotoCraft vs Adobe Photoshop: target-app parity -<<<<<<< ours -> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-13 · **Change:** minor (`.atn` import maps 112 events; Free Transform H/V skew fields; 2026-10-11: Type evidence: kerning, the Warp Text preview and variable-font axes are done, percentages unchanged; stale rows corrected against `main` and the scorecard, estimates unchanged; Photoshop Actions `.atn` load and save; 2026-10-10: Tilt-Shift measurements added; earlier the same day: major, full re-measure against Photoshop 2026 27.11.0; merged `parity-estimate.md` and the roadmap's honest assessment; stale missing-tool rows corrected: Color Replacement and Red Eye are live toolbar tools, Frame landed; percentages unchanged) · **Target:** Adobe Photoshop 2026 -======= -> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-13 · **Change:** minor (on-canvas corner radius widgets, TOOL-214-12; `.atn` import maps 112 events; Free Transform H/V skew fields; stale rows corrected against `main` and the scorecard, estimates unchanged; Photoshop Actions `.atn` load and save; 2026-10-10: Tilt-Shift measurements added; earlier the same day: major, full re-measure against Photoshop 2026 27.11.0; merged `parity-estimate.md` and the roadmap's honest assessment; stale missing-tool rows corrected: Color Replacement and Red Eye are live toolbar tools, Frame landed; percentages unchanged) · **Target:** Adobe Photoshop 2026 ->>>>>>> theirs +> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-13 · **Change:** minor (on-canvas corner radius widgets, TOOL-214-12; `.atn` import maps 112 events; Free Transform H/V skew fields; 2026-10-11: Type evidence: kerning, the Warp Text preview and variable-font axes are done, percentages unchanged; stale rows corrected against `main` and the scorecard, estimates unchanged; Photoshop Actions `.atn` load and save; 2026-10-10: Tilt-Shift measurements added; earlier the same day: major, full re-measure against Photoshop 2026 27.11.0; merged `parity-estimate.md` and the roadmap's honest assessment; stale missing-tool rows corrected: Color Replacement and Red Eye are live toolbar tools, Frame landed; percentages unchanged) · **Target:** Adobe Photoshop 2026 The authoritative answer to "how close is PhotoCraft to Photoshop, and how much work is left". The one-page summary is [`ROADMAP.md`](../ROADMAP.md); the ranked work list is [`gaps.md`](gaps.md); @@ -177,13 +173,8 @@ parity for the area and are already contained in the dimension rows above. | Retouching (healing, clone, patch, remove, content-aware) | 50% | 100–180 | Remove tool non-generative; Content-Aware Fill has no workspace (TOOL-214-15); live stroke preview only for Brush/Eraser (TOOL-213-7) | | Transform, warp, puppet, perspective, liquify | 55% | 100–180 | Free Transform modifiers right, with a right-click transform menu (TOOL-214-5) and H/V skew fields; Puppet Warp mesh follows the object outline (TOOL-214-6); Liquify called "useless" by a user (#2606) | | Adjustments and filters | 70% | 120–200 | All present; smart-filter re-render matches Photoshop on 5 of 30 files; Filter Gallery looks approximate; no Neural Filters | -<<<<<<< ours | Type | 40% | 120–200 | Engine works; manual/optical kerning, a live Warp Text preview and variable-font axis sliders (2026-10-11); type on a path only places glyphs rigidly (TYPE-218-1 partial); no RTL paragraphs, OpenType panel UI; Type tool freeze on macOS (#2518) | -| Vector shapes and paths | 55% | 80–140 | Pen, Direct/Path Selection, shapes, shape strokes. Freeform and Curvature Pen (#1054). Add/Delete Anchor Point and Convert Point tools exist (`Tool` enum); missing on-canvas corner radius (TOOL-214-12), path-point nudge; shape parity tracking issue #2496 | -======= -| Type | 40% | 120–200 | Engine works; no type on a path, manual kerning, RTL paragraphs, OpenType panel UI, live Warp Text preview; Type tool freeze on macOS (#2518) | | Vector shapes and paths | 55% | 80–140 | Pen, Direct/Path Selection, shapes, shape strokes. Freeform and Curvature Pen (#1054). Add/Delete Anchor Point and Convert Point tools exist (`Tool` enum); on-canvas corner radius widgets on live rectangles (TOOL-214-12, 2026-10-13); missing path-point nudge; shape parity tracking issue #2496 | ->>>>>>> theirs | Colour management and modes | 70% | 60–100 | Own ICC engine, soft proof, CMYK/Lab/Indexed/Duotone/Multichannel; no Adobe CMYK profiles, no spot plates (FILE-215-17), monitor profile only at launch | | Camera Raw and computational photo (Photomerge, HDR, lens) | 45% | 120–200 | Raw for DNG/CR2/NEF/ARW/RW2/ORF/RAF(uncompressed)/PEF; no CR3; ACR dialog partial (no masking, calibration); generic lens profiles only | | Automation, actions, batch, scripting | 45% | 120–200 | CLI/MCP/control channel ahead of Photoshop; Actions panel and recording not document-independent (AUTO-219-1/2); `.atn` load/save since 2026-10-12 (112 events mapped, the rest kept verbatim); no ExtendScript/UXP | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index ae1734b9a5..252207fd07 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,10 +1,6 @@ # UI parity: tools, handles, modifiers and feel -<<<<<<< ours -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (smart filter reordering by drag; smart object perspective row corrected to done, #426; Free Transform H/V skew fields; toolbar tool shortcuts can be reassigned; ⇧-dragged guides land on ruler ticks; layer and selection keys; tool keys; spring-loaded tool letters; type formatting keys; Pen Auto Add/Delete, #4144; smart filter rows; stale missing-tool rows corrected: Color Replacement, Red Eye and the Add/Delete Anchor Point pair are live toolbar tools, Frame landed; no percentage changed; selection-modifier and ⌥-wheel rows match their tests) · **Target:** Adobe Photoshop 2026 -======= -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (guide keys and clicks; menu bar from the keyboard, #4988; Crop tool Content-Aware Fill; on-canvas corner radius widgets, TOOL-214-12; Curvature Pen edits the active path; Clip Thumbnails to Layer Bounds; Pen ⇧ 45°; last selected tool restored at launch; Layers panel filter-type dropdown with Kind, Name and Mode, #5048; Free Transform box and marching ants follow the selection, #5297; History: the trash deletes the selected snapshot, rows drag onto the trash, #5324; smart filter reordering by drag; smart object perspective row corrected to done, #426; Free Transform H/V skew fields; toolbar tool shortcuts can be reassigned; ⇧-dragged guides land on ruler ticks; layer and selection keys; tool keys; spring-loaded tool letters; type formatting keys; Pen Auto Add/Delete, #4144; smart filter rows; stale missing-tool rows corrected: Color Replacement, Red Eye and the Add/Delete Anchor Point pair are live toolbar tools, Frame landed; no percentage changed) · **Target:** Adobe Photoshop 2026 ->>>>>>> theirs +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (guide keys and clicks; menu bar from the keyboard, #4988; Crop tool Content-Aware Fill; on-canvas corner radius widgets, TOOL-214-12; Curvature Pen edits the active path; Clip Thumbnails to Layer Bounds; Pen ⇧ 45°; last selected tool restored at launch; Layers panel filter-type dropdown with Kind, Name and Mode, #5048; Free Transform box and marching ants follow the selection, #5297; History: the trash deletes the selected snapshot, rows drag onto the trash, #5324; smart filter reordering by drag; smart object perspective row corrected to done, #426; Free Transform H/V skew fields; toolbar tool shortcuts can be reassigned; ⇧-dragged guides land on ruler ticks; layer and selection keys; tool keys; spring-loaded tool letters; type formatting keys; Pen Auto Add/Delete, #4144; smart filter rows; stale missing-tool rows corrected: Color Replacement, Red Eye and the Add/Delete Anchor Point pair are live toolbar tools, Frame landed; no percentage changed; selection-modifier and ⌥-wheel rows match their tests) · **Target:** Adobe Photoshop 2026 How PhotoCraft's direct manipulation compares with Photoshop 2026 (27.11.0): the toolbox, the handles and modifier keys of each gesture, nudging, snapping, numeric precision, navigation, From a0c2c1992f0e09e143728c8fb89c9dc48e89f3b1 Mon Sep 17 00:00:00 2001 From: David Mann Date: Thu, 15 Oct 2026 02:36:30 +0200 Subject: [PATCH 5/7] docs: ui-parity marks the modifiers-at-press row done, as BUG-208-4 is Main has the marquee Shift+Alt intersect test (#3624), so the row no longer says it is missing. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/ui-parity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 252207fd07..01c94cc7c4 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -106,7 +106,7 @@ Triangle and Curvature Pen (minus legacy Rounded Rectangle and Targeted Adjustme | Behaviour | Status | Evidence | |---|---|---| | ⇧ square/circle, ⌥ from centre, live W × H readout (marquee) | done | `marquee_tests.rs` | -| ⇧ add, ⌥ subtract, ⇧⌥ intersect from modifiers at press | partial | works; tested for the marquee (add, subtract), Lasso (all three) and Polygonal Lasso; no marquee ⇧⌥ intersect test (BUG-208-4) | +| ⇧ add, ⌥ subtract, ⇧⌥ intersect from modifiers at press | done | tested for the marquee (add, subtract, ⇧⌥ intersect: `marquee_tests.rs`), Lasso (all three: `lasso_ui/tests.rs`) and Polygonal Lasso (`polygon_lasso_tests.rs`) (BUG-208-4) | | Space repositions the marquee while dragging | done | `hold_keys.rs` | | Polygonal Lasso ⇧ snaps to 45° | missing | #2352 | | Autoscroll at the window edge while selecting | missing | #2231 | From e8f50f69c3d1d0e9c96b4b0f31349fa156f990f5 Mon Sep 17 00:00:00 2001 From: David Mann Date: Thu, 15 Oct 2026 21:17:33 +0200 Subject: [PATCH 6/7] scorecard: TOOL-214-4 note and the pasteboard menu row catch up with main Dragging layers onto another document's tab landed in #851 (#589), and the pasteboard colour menu in #2633 (#2462); the TOOL-214-4 note and the context-menu parity row still listed both as open. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/context-menu-parity.md | 5 +++-- docs/scorecard.md | 2 +- scorecard/tools.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/context-menu-parity.md b/docs/context-menu-parity.md index 76d6724b7e..23c34ebaa6 100644 --- a/docs/context-menu-parity.md +++ b/docs/context-menu-parity.md @@ -1,6 +1,6 @@ # Context-menu parity contract -> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-13 · **Change:** minor (layer-mask thumbnail menu, #4575) · **Target:** Adobe Photoshop 2026 +> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-15 · **Change:** trivial (pasteboard row: the menu exists, #2462; layer-mask thumbnail menu, #4575) · **Target:** Adobe Photoshop 2026 Status: implementation contract, updated 2026-10-09. Scope: canvas, document tabs, and panels. “Right-click” means a secondary pointer click; macOS Control-click should also open the same menu where the platform sends a context-menu gesture. Photoshop changes a context menu with the active tool, selection, and panel item. Adobe documents that principle but does not publish a complete current menu catalog. **Documented** means an Adobe source explicitly names the gesture or action. **Inferred** means a PhotoCraft design target or an item known from a main menu whose presence in a Photoshop context menu still needs a current-product capture. Do not present inferred rows as exact Photoshop menus. [Adobe: panels and menus](https://helpx.adobe.com/photoshop/using/panels-menus.html), [Adobe: shortcuts and context menus](https://helpx.adobe.com/sa_en/photoshop/using/customizing-keyboard-shortcuts.html). @@ -82,7 +82,7 @@ Photoshop's Generative Fill and Delete and Fill Selection rows are left out: Pho | Brushes and preset panels | Rename/Delete brush or group, export selected brushes, view/reset preset choices | Rename/Delete, and preset group/item menus exist | Adobe explicitly documents Export Selected Brushes from brush/group right-click ([brushes](https://helpx.adobe.com/photoshop/desktop/apply-painting-techniques/brushes-presets/create-brush-set-painting-options.html)); Photoshop pop-up-panel rename/delete/reset/view options are [documented](https://helpx.adobe.com/photoshop/using/panels-menus.html), though some are panel-button menus | | Paths, History, Actions, Swatches, Gradients, Patterns, Styles, Libraries, Properties | Target-specific duplicate/delete/rename and panel operations where a panel exists | Paths row menu added in this PR; other panels need audit | **Inferred** catalog; record a Photoshop capture before claiming parity | | Document tab | Close, Close Others, Close All, Reveal in file manager, duplicate/move to window where supported | Close, Close Others, Close All, Reveal in Finder, and drag to reorder implemented; duplicate/move to window where supported remains open | **Inferred** exact list; P1 | -| Empty pasteboard / workspace | Gray, Black, Custom canvas color choices; verify any additional entries in a current Photoshop capture | No menu | Adobe [documents right-clicking outside the image for canvas color](https://helpx.adobe.com/ph_en/photoshop/using/filling-stroking-selections-layers-paths.html); exact current layout still needs a capture | +| Empty pasteboard / workspace | Gray, Black, Custom canvas color choices; verify any additional entries in a current Photoshop capture | Implemented (canvas_tool_menu.rs `PASTEBOARD_MENU`, #2462): Default, Black, Dark Gray, Medium Gray, Light Gray, Custom, Select Custom Color… | Adobe [documents right-clicking outside the image for canvas color](https://helpx.adobe.com/ph_en/photoshop/using/filling-stroking-selections-layers-paths.html); exact current layout still needs a capture | | Text field / selected text | Native edit menu and spelling suggestions without routing to active image tool | Edit menu implemented in text_field_menu.rs for every text field (Undo, Cut, Copy, Paste, Delete, Select All; a right-click inside the selection keeps it; never reaches the canvas or tool menu). Spelling suggestions live in the Type tool's edit menu (canvas_tool_menu.rs), not in generic fields, which hold no type layer text (UI-217-8) | P1; **inferred** exact spelling list | | Tool icon in Options bar | Reset Tool, Reset All Tools | Audit | Explicitly documented in [Adobe Photoshop reference](https://helpx.adobe.com/archive/en/photoshop/cc/2015/photoshop_reference.pdf); historical source, verify modern label | | Adaptive Wide Angle constraint line | Auto, Horizontal, Vertical orientation | Current right-click deletes constraint | P1 behavior mismatch: [Adobe documents orientation choice](https://helpx.adobe.com/photoshop/using/adaptive-wide-angle-filter.html) | @@ -100,6 +100,7 @@ Each slice needs pure model tests (including every item dispatching a known comm | Date | Change | Summary | |---|---|---| +| 2026-10-15 | trivial | Pasteboard row: the colour menu exists since #2462 | | 2026-10-13 | minor | Layer-mask thumbnail menu (#4575) | | 2026-10-10 | trivial | Status line, revision history | | 2026-10-09 | minor | Selection canvas reference and tool matrix updates | diff --git a/docs/scorecard.md b/docs/scorecard.md index a84661205a..729e4fd11b 100644 --- a/docs/scorecard.md +++ b/docs/scorecard.md @@ -148,7 +148,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t | TOOL-214-1 | Select and Mask workspace: view modes, Refine Edge brush, 6 outputs | partial | [#214](https://github.com/storytold/photocraft/issues/214) | select.refineEdge dialog with a live preview in Photoshop's view modes: Onion Skin, Marching Ants, Overlay, On Black, On White, Black & White, On Layers, per-view Opacity, Show Edge (J), Show Original (P), F cycles, X shows the image (select_mask_view.rs, #1754); Refine Edge Brush (R, size, Expand Detection Area / Restore Original Edge, Alt swaps) paints select.refineEdge refineStrokes, estimated by colour-line matting (matting/brush.rs, #2972); outputs Selection, Layer Mask, New Layer, New Layer with Mask, New Document, New Document with Mask (#2998); no workspace layout | | TOOL-214-2 | Marquee: Shift square, Alt from centre, live W x H readout | done | [#214](https://github.com/storytold/photocraft/issues/214) | canvas.rs marquee_corners: Shift square or circle, Alt from the centre, live W x H readout beside the cursor (marquee_readout); marquee_tests.rs | | TOOL-214-3 | Color Range test: Sampled Colors at Fuzziness 0 selects the exact match only | done | [#214](https://github.com/storytold/photocraft/issues/214) | color_range_fuzziness_zero_selects_exact_match_only in selection_cmds.rs asserts exact match is selected and 1-level-off pixels are rejected at fuzziness 0; tonal presets covered in color_range_presets | -| TOOL-214-4 | Move tool: box-select layers, Auto-Select hover outline, double-click fit, drag to a tab | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Auto-Select hover outline (Preferences › Tools › Show Highlight on Rollover, #2834) and box-select layers from an empty spot (move_box.rs, layer.selectInRect, #2844) done; double-click fit and drag to a tab open | +| TOOL-214-4 | Move tool: box-select layers, Auto-Select hover outline, double-click fit, drag to a tab | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Auto-Select hover outline (Preferences › Tools › Show Highlight on Rollover, #2834) and box-select layers from an empty spot (move_box.rs, layer.selectInRect, #2844) done; dragging layers with the Move tool (or from the Layers panel) onto another document's tab copies them there (layer_transfer.rs, layer.copyToDocument, #589/#851); double-click fit and dragging a selection's pixels to another document open | | TOOL-214-5 | Right-click menu during Free Transform (scale, rotate, skew, warp, flip, rotate 90/180) | done | [#214](https://github.com/storytold/photocraft/issues/214) | canvas_tool_menu.rs TRANSFORM_MENU: modes, Content-Aware Scale / Puppet Warp greyed, Rotate 180 / 90 CW / 90 CCW and Flip turn the open box (transform_tool::intercept, #2832) | | TOOL-214-6 | Puppet Warp mesh follows the object outline (constrained triangulation) | done | [#214](https://github.com/storytold/photocraft/issues/214) | algo/puppet.rs build_mesh: traced outline of the opaque region grown by Expansion, triangulated with a Density-spaced lattice (conforming Delaunay); separate shapes get separate meshes (#3105) | | TOOL-214-7 | Content-Aware Scale through the Free Transform box with a live proxy preview | done | [#214](https://github.com/storytold/photocraft/issues/214) | Edit > Content-Aware Scale opens a scale-only Free Transform box (cas_transform.rs) with Amount, Protect and Protect Skin Tones in the options bar; edit.contentAwareScale carves a 384 px copy in the background for the live preview, and Enter runs it with the box's size and x/y as one step (#3096) | diff --git a/scorecard/tools.toml b/scorecard/tools.toml index 3232cdec18..65db639711 100644 --- a/scorecard/tools.toml +++ b/scorecard/tools.toml @@ -136,7 +136,7 @@ id = "TOOL-214-4" target = "Move tool: box-select layers, Auto-Select hover outline, double-click fit, drag to a tab" status = "partial" issue = 214 -note = "Auto-Select hover outline (Preferences › Tools › Show Highlight on Rollover, #2834) and box-select layers from an empty spot (move_box.rs, layer.selectInRect, #2844) done; double-click fit and drag to a tab open" +note = "Auto-Select hover outline (Preferences › Tools › Show Highlight on Rollover, #2834) and box-select layers from an empty spot (move_box.rs, layer.selectInRect, #2844) done; dragging layers with the Move tool (or from the Layers panel) onto another document's tab copies them there (layer_transfer.rs, layer.copyToDocument, #589/#851); double-click fit and dragging a selection's pixels to another document open" [[item]] id = "TOOL-214-5" From b3dfd1bf6ac90b0e3771d60fac35a7461414da8b Mon Sep 17 00:00:00 2001 From: David Mann Date: Tue, 20 Oct 2026 19:51:52 +0200 Subject: [PATCH 7/7] Regenerate docs/scorecard.md Co-Authored-By: Claude Opus 5.5 --- docs/scorecard.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/scorecard.md b/docs/scorecard.md index c4b53a20f8..615619775e 100644 --- a/docs/scorecard.md +++ b/docs/scorecard.md @@ -8,13 +8,13 @@ Generated by `cargo xtask scorecard` from `perf/budgets.toml`, `perf/baseline.js |---|---:|---:|---:|---| | [Performance](#performance) | 3 | 22 | 24 | 58 scenarios: 3 within budget, 22 over budget or failing, 9 tracked only, 19 not run, 5 not measurable yet (baseline 2026-10-05) | | [File compatibility](#file-compatibility) | 7 | 14 | 6 | io corpus: oracle ≥ 148/170, round trip ≥ 169/170; psd-tools corpus: oracle ≥ 249/309, round trip ≥ 308/309; photoshop oracles: oracle ≥ 188/256, round trip ≥ 258/256 | -| [Tools](#tools) | 33 | 11 | 0 | | -| [Workspace and UI](#workspace-and-ui) | 13 | 6 | 4 | settings that do nothing: 25 of 169 (target 0) | -| [Type](#type) | 4 | 3 | 2 | | +| [Tools](#tools) | 34 | 10 | 0 | | +| [Workspace and UI](#workspace-and-ui) | 13 | 7 | 3 | settings that do nothing: 25 of 169 (target 0) | +| [Type](#type) | 5 | 3 | 1 | | | [Automation](#automation) | 5 | 2 | 4 | 631 of 631 menu items live (100.0%) | | [Reliability](#reliability) | 5 | 2 | 0 | never-crash lints on 30 of 30 crates; panic_hunt present | | [Distribution](#distribution) | 5 | 4 | 2 | | -| [Open bugs](#open-bugs) | 29 | 2 | 1 | | +| [Open bugs](#open-bugs) | 31 | 1 | 0 | | ## Performance @@ -150,7 +150,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t | TOOL-214-1 | Select and Mask workspace: view modes, Refine Edge brush, 6 outputs | partial | [#214](https://github.com/storytold/photocraft/issues/214) | select.refineEdge dialog with a live preview in Photoshop's view modes: Onion Skin, Marching Ants, Overlay, On Black, On White, Black & White, On Layers, per-view Opacity, Show Edge (J), Show Original (P), F cycles, X shows the image (select_mask_view.rs, #1754); Refine Edge Brush (R, size, Expand Detection Area / Restore Original Edge, Alt swaps) paints select.refineEdge refineStrokes, estimated by colour-line matting (matting/brush.rs, #2972); outputs Selection, Layer Mask, New Layer, New Layer with Mask, New Document, New Document with Mask (#2998); no workspace layout | | TOOL-214-2 | Marquee: Shift square, Alt from centre, live W x H readout | done | [#214](https://github.com/storytold/photocraft/issues/214) | canvas.rs marquee_corners: Shift square or circle, Alt from the centre, live W x H readout beside the cursor (marquee_readout); marquee_tests.rs | | TOOL-214-3 | Color Range test: Sampled Colors at Fuzziness 0 selects the exact match only | done | [#214](https://github.com/storytold/photocraft/issues/214) | color_range_fuzziness_zero_selects_exact_match_only in selection_cmds.rs asserts exact match is selected and 1-level-off pixels are rejected at fuzziness 0; tonal presets covered in color_range_presets | -| TOOL-214-4 | Move tool: box-select layers, Auto-Select hover outline, double-click fit, drag to a tab | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Auto-Select hover outline (Preferences › Tools › Show Highlight on Rollover, #2834) and box-select layers from an empty spot (move_box.rs, layer.selectInRect, #2844) done; double-click fit and drag to a tab open | +| TOOL-214-4 | Move tool: box-select layers, Auto-Select hover outline, double-click fit, drag to a tab | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Auto-Select hover outline (Preferences › Tools › Show Highlight on Rollover, #2834) and box-select layers from an empty spot (move_box.rs, layer.selectInRect, #2844) done; dragging layers with the Move tool (or from the Layers panel) onto another document's tab copies them there (layer_transfer.rs, layer.copyToDocument, #589/#851); double-click fit and dragging a selection's pixels to another document open | | TOOL-214-5 | Right-click menu during Free Transform (scale, rotate, skew, warp, flip, rotate 90/180) | done | [#214](https://github.com/storytold/photocraft/issues/214) | canvas_tool_menu.rs TRANSFORM_MENU: modes, Content-Aware Scale / Puppet Warp greyed, Rotate 180 / 90 CW / 90 CCW and Flip turn the open box (transform_tool::intercept, #2832) | | TOOL-214-6 | Puppet Warp mesh follows the object outline (constrained triangulation) | done | [#214](https://github.com/storytold/photocraft/issues/214) | algo/puppet.rs build_mesh: traced outline of the opaque region grown by Expansion, triangulated with a Density-spaced lattice (conforming Delaunay); separate shapes get separate meshes (#3105) | | TOOL-214-7 | Content-Aware Scale through the Free Transform box with a live proxy preview | done | [#214](https://github.com/storytold/photocraft/issues/214) | Edit > Content-Aware Scale opens a scale-only Free Transform box (cas_transform.rs) with Amount, Protect and Protect Skin Tones in the options bar; edit.contentAwareScale carves a 384 px copy in the background for the live preview, and Enter runs it with the box's size and x/y as one step (#3096) | @@ -159,7 +159,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t | TOOL-214-10 | Pen: Alt breaks a handle, Shift 45 deg, Ctrl direct-selects, Backspace, close-drag handle | done | [#214](https://github.com/storytold/photocraft/issues/214) | Ctrl/Cmd = Direct Selection and Alt = Convert Point on existing paths (direct_select.rs, #790); Backspace/Delete retracts the last point while drawing (#1466); Alt during a drag breaks the handle pair, Alt-drag turns the last anchor's outgoing handle alone, and dragging on the first anchor closes with that anchor's handles (vector_ui.rs, #3306); Shift-click puts the next anchor on the nearest 45 deg ray from the previous one and Shift-drag turns the handles to 45 deg steps, live (vector_ui.rs pen_shift_click_puts_the_next_anchor_on_a_45_degree_ray, pen_shift_drag_turns_handles_to_45_degrees_live, #3751) | | TOOL-214-11 | Stroke Path dialog: pick any brush-based tool, Simulate Pressure | done | [#214](https://github.com/storytold/photocraft/issues/214) | path.stroke tool: Brush, Pencil, Eraser and every other brush-based tool (Background Eraser, Clone/Pattern Stamp, Healing/Spot Healing Brush, History Brush, Blur, Sharpen, Smudge, Dodge, Burn, Sponge, Color Replacement, Mixer Brush: their paint.* command along the path, one step) plus simulatePressure (taper both ends); Stroke Path dialog from the Pen menu, the Paths panel menu and Alt-click on its Stroke button (#2978) | | TOOL-214-12 | Shapes: on-canvas corner radius handles, shape feather, selection to shape with tolerance | partial | [#214](https://github.com/storytold/photocraft/issues/214) | On-canvas corner radius widgets on every selected live rectangle with Path Selection, the Rectangle tool and Move + Show Transform Controls: drag rounds every corner of every selected rectangle alike, Alt that corner on each, corner radius cursor and R: readout, one history step (corner_radius.rs, 2026-10-13); select.convertToShape with tolerance (vector_cmds.rs:1256). Missing: shape feather | -| TOOL-214-13 | Mask Properties: Density and Feather controls | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Vector-mask density/feather in the engine (vector_cmds.rs:948); no UI controls | +| TOOL-214-13 | Mask Properties: Density and Feather controls | done | [#214](https://github.com/storytold/photocraft/issues/214) | Properties panel shows Density (%) and Feather (px) sliders for a targeted pixel mask (layer.layerMask.edit) and a targeted vector mask (layer.vectorMask.edit), non-destructive and one undo step per drag, with Photoshop's Refine row (mask_props_ui.rs; mask_props_ui_tests.rs pixel_mask_properties_follow_target_for_raster_and_adjustment_in_both_themes, mask_slider_drags_preview_live_and_undo_as_separate_gestures, vector_mask_properties_edit_density_and_feather) | | TOOL-214-14 | Vanishing Point window: draw and edit planes, paste, clone in perspective | partial | [#214](https://github.com/storytold/photocraft/issues/214) | filter.vanishingPoint (vp_cmds.rs:15); on-canvas plane editor (vp_ui.rs: Create/Edit Plane, edge nodes, valid/doubtful/invalid grid colours, Grid Size, clipboard pasted onto the plane on OK); clone stamp, marquee and tear-off planes in the window still missing | | TOOL-214-15 | Content-Aware Fill workspace: paint the sampling area, preview, rotate/scale/mirror, new layer | partial | [#214](https://github.com/storytold/photocraft/issues/214) | Engine sampling auto, rect, custom (edit_menu_cmds.rs:324); generic dialog | | TOOL-214-16 | Liquify: redo (Cmd+Shift+Z) | done | [#214](https://github.com/storytold/photocraft/issues/214) | liquify_ui.rs supports bounded redo through Cmd+Shift+Z and the control channel; new strokes clear redo | @@ -202,7 +202,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | UI-217-15 | Curves: smoothing / pencil mode, black/grey/white eyedroppers, tooltips | done | [#217](https://github.com/storytold/photocraft/issues/217) | Curves editor (adjust_editors.rs, dialog and Properties): Edit points / Draw (pencil) buttons and Smooth, all with tooltips; pencil curves are 256-level maps (Adjustment::Curves pencil, params pencil/smooth, PSD curv map form and smart-filter Mpng; #3088). Set Black/Neutral Gray/White Point eyedroppers in the Image > Adjustments > Curves dialog (adjust_dialog.rs, #873) and in a Curves adjustment layer's Properties panel (layer_picker.rs: a click on the image is one layer.setAdjustment with the eyedropper param, sampling below the layer; Esc or another tool disarms; #3110) | | UI-217-16 | Hue/Saturation: Saturation and Lightness sliders get hue-following colour tracks | done | [#217](https://github.com/storytold/photocraft/issues/217) | saturation_track/lightness_track (adjust_editors.rs): grey -> the hue and black -> the hue -> white, recolouring as the Hue slider moves; saturation_and_lightness_tracks_follow_the_hue | | UI-217-17 | Color panel: wheel plus RGB/HSB/CMYK/Lab/Gray/Web slider modes; resizes with its group | missing | [#217](https://github.com/storytold/photocraft/issues/217) | panels.rs:1837 single field + hex/RGB readout | -| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | missing | [#217](https://github.com/storytold/photocraft/issues/217) | canvas.rs:1107-1125 no Alt handling | +| UI-217-18 | Alt+wheel zooms in gentle ~5 % steps; zoom controls uncramped | partial | [#217](https://github.com/storytold/photocraft/issues/217) | Alt+wheel zooms around the pointer, one step per notch applied the frame it arrives (wheel_nav.rs; input_tests.rs alt_scroll_zooms_in_steps_around_the_pointer, wheel_nav.rs alt_scroll_zooms_ten_percent_per_notch), but the step is x1.1 (10 %), not the ~5 % this row asks for: #1718 changed it from x1.05 after measuring Photoshop, so the row's target is in question. Status bar zoom field and Fit button fit inside the bar in every theme (status_bar_tests.rs status_bar_controls_sit_inside_the_bar_with_even_margins, #2823); the Navigator zoom controls are not checked | | UI-217-19 | Shortcut hints rendered per platform; Reveal label per OS | done | [#217](https://github.com/storytold/photocraft/issues/217) | hints and tooltips go through shortcuts::pretty (6266b7a9, #262; pretty_uses_the_platform_notation); menus::reveal_label names Reveal in Finder per OS (Show in Explorer / Show in Folder) in the Smart Objects menu and the tab menu; reveal_label_names_the_platform_file_manager + smart_objects_reveal_item_names_the_platform_file_manager | | UI-217-20 | 'Show rulers in new documents' preference; guides stored as f64 | done | [#217](https://github.com/storytold/photocraft/issues/217) | View › Rulers is remembered in unitsAndRulers.showRulers and applied at launch and on change (#2918; rulers_open_as_last_set_after_a_restart); doc Guides are Vec through New Guide, .pcraft and PSD 1032 (guides_keep_sub_pixel_positions_through_pcraft_and_psd) | | UI-217-21 | One Preset Manager for every preset kind with folders, search, reorder, load/save sets | partial | [#217](https://github.com/storytold/photocraft/issues/217) | edit_menu_cmds.rs:714 covers brushes, custom shapes, patterns with reorder | @@ -219,7 +219,7 @@ Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_w | TYPE-218-4 | Variable font axis sliders from the font's axes; opsz follows the point size | done | [#218](https://github.com/storytold/photocraft/issues/218) | One slider per axis of the style's font in the Character section (Properties and Window > Character), setting type.setStyle variations; opsz follows the type size unless set (layout.rs variation_list); a style or weight resets the wght axis (#2985). PSD does not round-trip axis values yet | | TYPE-218-5 | OpenType UI: Character panel buttons, Numerals and Stylistic Sets submenus | partial | [#218](https://github.com/storytold/photocraft/issues/218) | Type > OpenType toggles (type_extra_cmds.rs:512). Character panel (and the Properties Character section) has Photoshop's eight OpenType buttons: Standard Ligatures, Contextual Alternates, Discretionary Ligatures, Swash, Stylistic Alternates, Titling Alternates, Ordinals, Fractions, pressed while the feature is on at the selection and dispatching the type.openType.* commands (type_tool.rs opentype_row; character_panel_opentype_buttons_toggle_and_show_the_feature, #3752). Still missing: the Numerals and Stylistic Sets submenus, and greying out features the font lacks | | TYPE-218-6 | Manual pair kerning (Alt+arrows), optical kerning rendered, both round-trip PSD (#206) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Alt+Left/Right at a collapsed caret kerns the pair (type_tool.rs kern_pair, 20 per step and 100 with Cmd; type_tool_alt_arrows_kern_the_pair). Optical kerning is computed from the glyph outlines in text/src/optical.rs and applied by layout.rs when the run's mode is Optical (optical_matches_photoshop, optical_kerning_tightens_open_pairs). Both modes and manual values round-trip through PSD (io/tests/psd_kerning.rs; the optical mode travels in Txt2, txt2_carries_optical_kerning) | -| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | missing | [#218](https://github.com/storytold/photocraft/issues/218) | view_cmds.rs:834 always seeds arc, bend 50 | +| TYPE-218-7 | Warp Text dialog previews live and opens with the layer's current warp | done | [#218](https://github.com/storytold/photocraft/issues/218) | Type > Warp Text opens with the shown layer's warp, or None, never remembered values (filter_dialog.rs warp_defaults; warp_text_dialog_tests.rs warp_text_opens_with_the_type_layers_current_warp, warp_text_opens_at_none_for_a_layer_without_warp, remembered_warp_values_never_override_the_layers_warp). The dialog previews live without editing the document, Cancel leaves no step and OK is one undoable step (warp_text_dialog_previews_the_warp_without_editing_the_document, cancelling_warp_text_leaves_the_document_and_history_untouched, confirming_warp_text_is_one_undoable_step); the reduced-proxy preview matches the full-size result (filter_dialog.rs warp_text_preview_matches_the_full_size_result_on_a_reduced_proxy) | | TYPE-218-8 | Text editing: select all, double/triple/quadruple-click selection, paste, with tests | done | [#218](https://github.com/storytold/photocraft/issues/218) | Like Photoshop, 2 clicks select the word, 3 the laid-out line (a column in vertical type), 4 the paragraph up to the hard return, 5 all text, and the next quick click starts over (#3493; type_tool.rs next_click_count, click_selection, multi_click). Tested through real canvas clicks in point, paragraph and vertical type, with paste replacing the selection and Cmd+A selecting all (type_tool_tests.rs multi_click_selects_word_line_paragraph_and_all_in_point_text, multi_click_separates_wrapped_lines_from_paragraphs, click_counts_cycle_and_restart, click_selection_without_layout_and_on_hostile_input, multi_click_without_a_session_does_nothing) | | TYPE-218-9 | Distort/Perspective/Warp on live type as in Photoshop (was: offer 'Rasterize and continue?'; Photoshop doesn't prompt) | done | [#218](https://github.com/storytold/photocraft/issues/218) | Photoshop 2026 prompts for none of these: Edit › Transform › Warp on live type stays enabled with no rasterize prompt and offers only the warp styles (the mesh can't be dragged), so the type stays editable; Distort, Perspective and the split warps are greyed. PhotoCraft does the same: Warp on type commits the layer's Warp Text in one step (transform_tool.rs enter_type_warp, warp_cmds.rs warp_type_layer, #3004; warp_on_type_takes_a_style_and_keeps_the_type_editable), Distort/Perspective greyed (enable_rules.rs, #2701) | @@ -301,9 +301,9 @@ Never-crash attribute on 30 of 30 crate roots. | BUG-207-2 | Sample All Layers applies to Blur, Sharpen and Smudge | done | [#207](https://github.com/storytold/photocraft/issues/207) | retouch_ui.rs passes sampleAllLayers to paint.blur/sharpen/smudge; sample_all_layers_reaches_the_command (e2444ce, #234) | | BUG-207-3 | Smudge mixes premultiplied RGBA (no dark fringe at transparent edges) | done | [#207](https://github.com/storytold/photocraft/issues/207) | paint/src/retouch.rs premultiplies; smudge_into_transparency_leaves_no_dark_fringe (e2444ce, #234) | | BUG-207-4 | edit.transform transforms a targeted alpha channel | done | [#207](https://github.com/storytold/photocraft/issues/207) | edit.transform follows a targeted alpha channel or Quick Mask (explicit target since #242, Channels panel target with no target/layer param since #2835); Edit > Transform > Rotate/Flip are routed to the target too; transforms_follow_the_targeted_alpha_channel | -| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | missing | [#207](https://github.com/storytold/photocraft/issues/207) | Only smudge_drags_colour_along_the_stroke (retouch.rs:407) | +| BUG-207-5 | Tests: per-tool mask/channel targeting, Sample All Layers, no smudge fringe | done | [#207](https://github.com/storytold/photocraft/issues/207) | Every retouch tool (Clone Stamp, Pattern Stamp, Healing, Spot Healing, Dodge, Burn, Sponge, Blur, Sharpen, Smudge, History Brush, Remove) is tested to paint only a targeted mask, only a targeted alpha channel, and to follow the Channels panel target (engine retouch_cmds/tests.rs retouch_tools_paint_only_the_targeted_mask, retouch_tools_paint_only_the_targeted_alpha_channel, retouch_tools_follow_the_channels_panel_target, retouch_tools_paint_the_quick_mask, retouch_targets_fail_gracefully). Sample All Layers changes the result over two layers (sample_all_layers_blur_and_sharpen_work_on_an_empty_layer, sample_all_layers_smudge_drags_colour_from_below, sample_all_layers_spot_healing_heals_onto_an_empty_layer, clone_stamp_sample_all_layers_onto_empty_layer_and_opacity; ui retouch_ui.rs sample_all_layers_reaches_the_command); no smudge fringe (smudge_across_a_transparent_edge_has_no_dark_fringe). Brush/Eraser/Gradient/Bucket targets: tests.rs painting_can_target_the_layer_mask, channel_cmds/tests.rs painting_filtering_and_adjusting_into_an_alpha_channel. Not covered: Pencil and Mixer Brush into a mask or channel | | BUG-208-1 | Shift while dragging a Rect/Elliptical Marquee constrains to a square/circle | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners applies Shift via Drag::marquee_mods; marquee_tests.rs::shift_during_the_drag_draws_a_square_and_the_readout_follows covers the drag | | BUG-208-2 | Alt while dragging a marquee draws from the centre | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_corners centres Alt drags; marquee_tests.rs::alt_draws_from_the_centre_and_shift_alt_a_centred_circle verifies rectangles and ellipses | | BUG-208-3 | W x H px readout beside the cursor while dragging a marquee | done | [#208](https://github.com/storytold/photocraft/issues/208) | canvas.rs marquee_readout draws the readout; marquee_tests.rs asserts dimensions while dragging and its removal after release | -| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | partial | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press (canvas.rs:1679, used :1779); only a badge test (tool_feedback.rs:195) | +| BUG-208-4 | Add/subtract/intersect from modifiers pressed before the drag, kept by a test | done | [#208](https://github.com/storytold/photocraft/issues/208) | Mods captured at press. Marquee: Shift at the press adds and Alt subtracts, with no square or centring (marquee_tests.rs modifiers_held_before_the_drag_pick_the_mode_not_the_shape). Lasso: Alt, Shift and Shift+Alt at the start subtract, add and intersect (lasso_ui/tests.rs initial_alt_still_subtracts_and_initial_shift_still_adds). Polygonal Lasso: Shift/Alt at the first click keep the selection and combine (polygon_lasso_tests.rs modifiers_at_the_first_click_keep_and_combine_the_selection). Marquee Shift+Alt held at the press intersects (marquee_tests.rs shift_alt_before_the_drag_intersects_the_selection) | | BUG-208-5 | Kittest: Shift drag gives a square, Alt drag is centred, readout matches the size | done | [#208](https://github.com/storytold/photocraft/issues/208) | crates/ui-egui/src/marquee_tests.rs covers Shift, Alt, selection bounds, W/H readout and drag completion |