Commit Graph
773 Commits
Author SHA1 Message Date
Reynold HuandClaude Opus 5.5 d7d5c6069c Test the dispatch panic guard end to end; mark REL-3 done (#1803)
A cfg(test)-only test.panic command drives Session::execute into the catch_unwind
guard in jobs::dispatch; the test asserts an internal-error Err, an untouched document
and history, and a working session afterwards. REL-3 flips to done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:51:51 -04:00
Reynold HuandClaude Opus 5.5 ff1d933cb8 Scorecard: mark the BUG-205 and BUG-207 rows done; the fixes and their tests are on main (#1795)
BUG-205-1/2/3 (5a5facc, #242) and BUG-207-1/2/3 (e2444ce, #234) flip to done;
each row now names the test that covers it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:40:48 -04:00
Reynold HuandClaude Opus 5.5 7544bb1084 Scorecard: mark UI-217-2 done; the geometry round trip is tested (#1808)
UI-217-2 flips to done: b07a2e5b (#587) persists the window and dock width via eframe,
and window_and_panel_geometry_survive_a_restart asserts the round trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:39:33 -04:00
BFlat 9a71884244 Merge pull request #1894 from storytold/community/1745-eyedropper
Eyedropper: Sample Size, Sample layers and Show Sampling Ring (#1745 carry)
2026-10-09 22:08:46 +07:00
2b139ebd5c inspect: report each smart object's source (#1785)
document.inspect (and photocraft-cli info) now gives every smart object a
smartSource: embedded with its file name, or linked with a file path or,
for a PSD placed layer, the Idnt uuid its duplicates share. A script can
then tell duplicates of one placed file from independent contents, e.g.
to check that every location in a mockup template has its own art.

Co-authored-by: Juan Manuel Verges Solanas <jmverges@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 22:08:07 +07:00
BFlatandClaude e39cacd895 Packaging: Windows MSI setup wizard (folder choice, progress, version, launch on finish) (#1864)
Double-clicking the MSI now opens WixUI_InstallDir without the licence page:
Welcome, install folder (remembered for upgrades in
HKLM\Software\PhotoCraft\InstallDir), Ready, progress, and a Finish page with
a ticked "Launch PhotoCraft" box (WixShellExec, unelevated). The pages name
the full version, pre-release tag included (photocraft.en-us.wxl).
package.ps1 draws the banner and side bitmaps from the app icon, so no WiX
stock art ships. msiexec /qn still installs silently. The release and ARM64
workflows install the WiX UI and Util extensions; packaging-lint checks the
.wxl. Ported from VectorCraft (storytold/vectorcraft@aa548d2).


Claude-Session: https://claude.ai/code/session_01AP7ThRN3kpNmjsuJUerJui

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-09 21:33:38 +07:00
Elvis33LEandClaude Opus 5.5 adc1f76df4 Indexed Color: integer counts, palette stops and asynchronous previews (#1741)
Indexed Color accepted fractional colour counts and computed its live preview on the UI thread.
Counts are now whole numbers in 2-256 with a linear slider snapping at 8/16/32/64/128/256, and on
native builds the preview runs on one background worker that coalesces slider drags and rejects
stale results. Nearest-colour lookup uses an exact kd-tree above 64 entries (identical indices,
256 colours at 4.2 MP: 3018 -> 1061 ms). Web and inline sessions stay synchronous.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:33:13 -04:00
Gert Pellin - GPEandClaude Opus 5.5 15737e122b Filter > Other > Color to Alpha (#1683)
A new filter that removes a chosen colour by unmixing it into transparency, as GIMP's and
Krita's Color to Alpha do: per pixel the most transparent opacity that keeps the unmixed colour
in range, shaped by transparency and opacity thresholds. It runs through run_filter (selection,
smart filters, Last Filter, one history step), floats the Background first and refuses a
transparency-locked layer; the filter dialog gains a colour parameter. Fixes #1576.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:13:42 -04:00
Claude ac9c7b057b Merge main into #1745 (catalogs: keep both blocks)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHgFEHEsefoQoBParH47JA
2026-10-09 14:08:06 +00:00
storybored379andClaude Opus 5.5 15e35cf605 MCP: shared conventions and cancellable Render Video (#1668)
The MCP server follows the crafts' shared conventions (FilmCraft #28): core tools
incl. render_preview, titles and annotation hints, strict argument keys (-32602),
live photocraft://document and photocraft://commands resources, and -32700
recovery from malformed JSON lines. Headless Render Video writes through the
granted write root, reports progress, stays ping-responsive and can be cancelled,
removing only the files it created. docs/mcp.md describes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:54:14 -04:00
Nigel Ihza FirdausyandClaude Opus 5.5 75e6bad453 Control: ui.inspect reports the open Brush Preset picker (#1672)
ui.inspect now has brushPicker: null while closed, {pos, list} while the Brush
Preset picker is open (list is its collapsed/filter/view/renaming state), so
agents can see what a right-click with a painting tool opened. Fixes #1558.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:50:01 -04:00
Claude a94dd19d79 Merge main into #1745 (German catalog)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHgFEHEsefoQoBParH47JA
2026-10-09 13:29:18 +00:00
midasdfandClaude Opus 5.5 b5320e590e Preferences: System Title Bar says it applies at next launch (#1677)
On Windows and Linux the System title bar checkbox now carries the existing "Applies at next
launch." note, since saving it does not change the current window. Fixes #1661.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:17:05 -04:00
midasdfandClaude Opus 5.5 40f14d25e8 Plug-ins: keep the originating error across parallel bands (#1654)
When one band failed, its siblings stopped with a generic "another band failed"
error, which could win the collection order and hide the real cause. The abort
flag now carries the first error, so every band reports it; tests cover traps,
error codes and the instruction budget across parallel bands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:11:00 -04:00
初心YearthandClaude Opus 5.5 c63d04a09c docs: explain Windows source build prerequisites and app-control failures (#1692)
Document the MSVC toolchain and C++ build tools workload, and how to diagnose
Smart App Control blocking Cargo or build outputs (os error 4551), with a
pointer to the packaged release. Fixes #1585.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:04:05 -04:00
Nigel Ihza FirdausyandClaude Opus 5.5 351736ef6b docs(mcp): grant scoped file roots in headless registration examples (#1673)
The PHOTOCRAFT_AUTOMATION_*_ROOT variables are read only by the desktop app, so
headless photocraft-cli mcp/serve need the --automation-*-root flags. Say so,
and pass explicit roots in the .mcp.json and claude mcp add examples.
Fixes #1551.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:03:58 -04:00
Nigel Ihza FirdausyandClaude Opus 5.5 6b1075e240 docs(control): align method signatures with accepted parameters (#1674)
ui.set gains rotation, gradientBlendMode and gradientClassic in its signature
and the stale duplicate ui.set line goes; ui.menu.invoke documents params,
ui.pointer tool, app.save an optional path, and serve's doc.save tiffLayers.
Fixes #1550.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:03:30 -04:00
buivanvu94andClaude Opus 5.5 f7d8a328e4 docs(control): Preferences Apply and OK are refused over control (#1678)
The Preferences entry said ui.dialog.apply/confirm save the dialog, but the
automation policy refuses whole-preferences updates (SECURITY.md). Document the
refusal, what happens to the dialog, and prefs.set for single safe preferences.
Fixes #1555.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:03:06 -04:00
BFlat 8e8e9f2c68 Merge pull request #1778 from storytold/community/1607-affinity
AF.3: native Affinity import (layers, artboards, vectors, text, images), carrying #1607 by @callmeBalloch
2026-10-09 18:00:53 +07:00
MarekSpodBiedry 2feaf055cc fix(xtask): the scorecard's performance summary no longer counts not-run scenarios as tracked (#947) (#1705) 2026-10-09 18:00:19 +07:00
MarekSpodBiedry 1fd600d3ad fix(automation): bridge doc_save without path writes back like headless (#946) (#1704) 2026-10-09 18:00:16 +07:00
MarekSpodBiedry 864021994c fix(scorecard): mark the #204 preference rows done; their readers, allowlist and test exist (#1002) (#1694) 2026-10-09 17:59:41 +07:00
Gert Pellin 65f30dd9e3 feat(eyedropper): Sample Size, Sample layers and Show Sampling Ring (#1649)
The Eyedropper options bar now has Photoshop's Sample Size (Point Sample,
3 by 3 ... 101 by 101 Average), Sample (Current Layer, Current & Below,
All Layers, All Layers No Adjustments, Current & Below No Adjustments)
and Show Sampling Ring.

- engine: new `document.sampleColor {x, y, size, sampleLayer}`
  (sample_cmds.rs). Averages the square centred on the pixel, clipped to
  the canvas, alpha-weighted, in the document's colour model (Gray, Lab;
  CMYK documents use their composite RGB, since the profile round trip
  is not exact) and rounded to the document's bit depth.
- ui: eyedropper_ui.rs options bar; state.rs ToolOptions
  eyedropper_size / eyedropper_sample / eyedropper_ring (serde). The
  size is shared with the painting tools' Alt-click eyedropper, the
  Curves / Color Picker eyedroppers and the Info panel readout.
- control: ui.set eyedropperSampleSize / eyedropperSample /
  eyedropperRing; documented in control-protocol.md and the MCP schema.
- i18n: new strings in all 14 catalogs (plus the missing Russian hint
  the tl! scan had not reached).
- scorecard: TOOL-1649-1.
2026-10-09 12:28:14 +02:00
Claude 770f6d49b8 scorecard: regenerate for the display-server preference (141 settings)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHgFEHEsefoQoBParH47JA
2026-10-09 16:06:12 +07:00
Adam Gincel 35c323c9de feat(ui): keep a brush per painting tool, as in Photoshop (#218)
The brush was one global session setting (only its smoothing was per tool), so
switching tools carried the size, hardness, mode, opacity, flow and dynamics
over. sync_tool_smoothing becomes sync_tool_brush: it saves the session brush
for the outgoing tool and loads the new tool's on every switch. UiState's
smoothing_tool/tool_smoothing become brush_tool/tool_brushes (serde default, so
saved UI state still loads), and the session's own fields (colours, erase flag,
stroke seed) are never carried across a swap.

Called from the frame start, the options bar before the brush chip, both canvas
stroke paths, ui.set {tool} (so tool + brushSize in one call sets the new tool's
size) and select_tool_preset. A tool seen for the first time inherits the brush
in hand at Photoshop's 10 % smoothing.

Tests: each_tool_keeps_its_own_brush, the renamed per-tool smoothing test,
per-tool coverage in the ui.set brushSize test, and pencil_tests switching tools
before setting the smoothing as the options bar does.
2026-10-09 16:06:07 +07:00
callmeBallochandClaude Opus 5.5 6deb1e0934 AF.3: attribute the Affinity corpus, one sample count, run it on --changed
From the review on storytold/photocraft#1607:
- ATTRIBUTION.md gets a row for corpus/affinity: the four upstreams at
  their pinned commits, with authors and licences (CC0-1.0, and MIT by
  Nick Beeuwsaert, Jeremy Cantu and DAIKI).
- The README said 176 sample documents in the provenance and 189 in the
  limits. It now says 189 distinct public documents in both places; the
  reader opens all of them (298 files with duplicates, no failures).
- crates/affinity/ joins CRITICAL, so test-corpus --changed runs the
  corpus when the reader changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-09 07:41:49 +00:00
callmeBallochandClaude Opus 5.5 2b279ba61b Merge storytold/main into AF.3 native Affinity import
No conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-09 06:38:46 +00:00
callmeBallochandClaude Opus 5.5 a8d7c6ef3f AF.3: put the Affinity fuzz targets and corpus back in CI
The maintainers approved the new crate, its fuzz targets and the corpus
upstreams in principle (storytold/photocraft#1607), so this undoes the
interim opt-in: ci.yml fuzzes preview and import_preview again, corpus
--all fetches the Affinity set, and its test runs under the normal
corpus feature. The provenance section stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-09 06:38:40 +00:00
kubuntugamer 950eb1dd28 fix(automation): a pathless PSD or PSB save leaves the document dirty (#1547)
Headless::save recorded the saved revision only for .pcraft, so saving a
document back to its own PSD or PSB wrote the file correctly and still
left session.list reporting dirty: true. Automation clients that use the
flag could not tell a saved document from unsaved work.

The test is now "was this a layered document save" (PSD, PSB or .pcraft)
rather than "was this .pcraft". A flat export (PNG, JPEG, ...) stays a
copy: it leaves dirty and the document's path alone. The desktop app.save
path already recorded the revision for every format, so this only affects
the headless JSON-lines server and the MCP stdio server, which both route
through Headless::save.

Tests cover the reported sequence for both .psd and .psb -- create, reopen
the saved file, edit, then doc.save with no path -- plus a control that a
flat export is a copy. docs/control-protocol.md now states the outcome of
doc.save for the dirty flag and the document path.

Co-authored-by: Space Bunny Free <chasbigham@gmail.com>
2026-10-09 13:24:07 +07:00
callmeBallochandClaude Opus 5.5 edb42922c1 AF.3: keep Affinity out of CI's corpus and fuzz jobs; state the clean-room provenance
Review on storytold/photocraft#1607 asked maintainers to decide on new
fuzz targets in ci.yml and four third-party corpus upstreams in
corpus --all. Until they do, neither touches CI: ci.yml is main's again
(the targets stay in crates/affinity/fuzz, run locally), and the
Affinity corpus is fetched only by corpus --affinity and tested with
--features corpus-affinity, so --all and test-corpus are unchanged.
The plan is to move those files into photocraft-corpus.

The crate README now spells out the provenance: no Affinity software,
afread's MIT description re-described without translating code, every
structure confirmed on public files (CRC-32 per entry, self-typed
fields), semantics fitted to Affinity's own thumbnails, and how the
sample documents were licensed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-09 05:19:56 +00:00
Claude 52552d7127 Rotate View with ui_set: describe rotation, drop the duplicate Greek row, regenerate the scorecard
- #1599 tests that ui_set's description names every field ui.set accepts; #1611 adds
  `rotation` to ui.set, so the description now names it.
- #1611's el.tsv row for "Pick screen color" duplicates the one #1618 added on main.
- docs/scorecard.md regenerated with cargo xtask scorecard after merging both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHgFEHEsefoQoBParH47JA
2026-10-09 05:07:07 +00:00
Claude 31cf872333 Merge #1611 (mvanhorn): Rotate View tool
# Conflicts:
#	docs/scorecard.md
2026-10-09 05:06:50 +00:00
WilandClaude Opus 5.5 3091a2843c Actions: edit steps, nested action calls, F-key shortcuts and recorded Fit on Screen (#1093)
Steps can be deleted and dragged into a new order, live while recording. Playing an action
while recording stores one named actions.play call, and nested playback stops on a child
failure, rejects cycles and goes at most 16 levels deep. Right-click an action to give it
F1-F12 (saved in preferences). View > Fit on Screen (Cmd+0), Zoom In/Out and 100% record and
replay. New actions.move command; actions.delete takes a step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:03:35 -04:00
Jason XiangandClaude Opus 5.5 1bc25d363f New Document: save named presets (Saved category) (#1516)
Save Preset... in File > New stores width, height, resolution, mode, depth, background (with
its colour) and display units in preferences. They are listed under a Saved category, where a
preset can be selected or deleted. Adds document.presets.save/list/get/delete; get returns
params for file.new, which gains an optional backgroundColor. Bad saved entries are skipped one
at a time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:54:37 -04:00
Matt Van Horn 4f7bd1f28f Regenerate the scorecard after the Rotate View tool
Marks TOOL-214-17 done and drops the now-read trackpad rotate preference
from the unread list. The Paint Bucket test mapping carries the view's
camera angle.
2026-10-09 04:40:22 +00:00
Matt Van Horn 690dafd61b Add the Rotate View tool in the Hand flyout
Turns the canvas camera around its centre without rewriting pixels.
Reset View zeros the angle; Match Rotation copies it across documents.
Trackpad rotate follows Preferences › Enhanced Controls › Rotate View with Trackpad.
2026-10-09 04:40:22 +00:00
Γιῶργος (George)andClaude Opus 5.5 1910b9f87c Add Greek (Ελληνικά) UI localization (#1562)
A complete Greek catalog (el.tsv) registered with the other complete-menu languages: menus,
dialogs, preferences, filters, tool names (Greek with the English name in parentheses) and
font weights, plus Greek Services / Hide Others / Show All in the macOS app menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:31:00 -04:00
abc2cbandClaude Opus 5.5 0256eaa4e0 Type Color Picker opens the full Color Picker; screen eyedropper with a pixel loupe (#1232)
The Type options bar and Character panel swatches open the full Color Picker (Text Color),
applying to the selected characters or the whole layer via type.setStyle; Cancel is inert. A
shared "Pick screen color" action in the full dialog and compact popups samples the desktop:
X11/Windows/macOS snapshots with an 11x11 magnifying loupe (4x-24x), the XDG PickColor portal on
Wayland, the EyeDropper API on the web. Captures stay in memory, are bounded at 64 MP, and are
ICC-converted to sRGB where the display publishes a profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:30:50 -04:00
callmeBallochandClaude Opus 5.5 57ae2fb1a3 Merge storytold/main into AF.3 native Affinity import
Conflicts: File › Open and batch extension lists (SVG, swatches and
Affinity together); the import dispatcher (upstream's type-layer
preparation with the new result fields); the pinned EXR and Affinity
corpora side by side; README, book and development docs.

Affinity type layers now draw through text_import::prepare, so they get
the same raster bound as other imported type, and SVG import fills the
two new ImportResult fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-09 04:26:18 +00:00
harrisonoconnorhover 0e0311d245 Reject unsupported document indices in MCP screenshots 2026-10-09 11:12:46 +07:00
MarekSpodBiedry fb71daf2c6 Control channel: ui.click rejects a count above 256 instead of queueing unbounded input (#982) (#1446) 2026-10-09 11:12:34 +07:00
MarekSpodBiedry 746f2530e6 Plug-in names reject bidi controls, zero-width spaces and other invisible format characters, and need a visible character (#1011) (#1444) 2026-10-09 11:12:27 +07:00
Harrison O'Connor-Hoover 672c0775de Reject control requests that expire before dispatch (#1525) 2026-10-09 11:11:47 +07:00
Harrison O'Connor-Hoover de9cc5f12c Do not replay bridge requests after an uncertain result (#1527) 2026-10-09 11:11:44 +07:00
BFlatandClaude b693d690e1 docs: MCP tool names and job tools, codec README JPEG metadata and deep EXR (#1552, #1553, #1559) (#1573)
- architecture.md listed dotted MCP tool names (doc.open, command.run...) that the server
  rejects; it now uses the advertised underscore names, adds the missing tools, and points
  out that dotted names belong to the JSON control protocol.
- development.md's MCP tool inventory gains jobs_list and jobs_cancel.
- crates/codecs/README.md: oversized JPEG EXIF/XMP is dropped with a warning (XMP first sheds
  its layered-document properties), not an error; supported deep EXR opens flattened with a
  DeepFlattened warning, and only deep ZIP and mip/rip-map tiles are unsupported.


Claude-Session: https://claude.ai/code/session_01UHgFEHEsefoQoBParH47JA

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-09 10:23:19 +07:00
Xus BadiaandClaude Opus 5.5 bfc59c784f macOS DMG: branded window background and icon layout (#1201)
The DMG opens on a 660x400 Finder window with the PhotoCraft artwork, 128 pt icons and the
Applications link beside the app. packaging/macos/dmg/ holds the SVG source, a reproducible
generator, an 87 KB HiDPI palette TIFF (was 1.0 MB) and the .DS_Store layout. The volume is
named "PhotoCraft" (the background alias resolves by volume name); the DMG file name keeps
the version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:11:00 -04:00
Filip PłachecińskiandClaude Opus 5.5 f0ae12dd22 Self-host the web app with Docker (nginx, community-maintained) (#1334)
A multi-stage Dockerfile builds photocraft-web with Trunk and serves dist/web from an
unprivileged nginx on :8080, with /healthz, precompressed gzip, the wasm MIME type and
immutable hashed assets. Rust and Trunk follow the release workflow, and the
PHOTOCRAFT_BUILD_SHA/DATE build args stamp About. Documented in packaging/web/README.md;
not built in CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:10:55 -04:00
optimalbyteeandoptimalbytee c7dbb37b3c Speed up wide Motion Blur with adaptive FFT convolution (#1471)
Keep the merged upstream row kernel for shorter streaks and unsupported inputs.
Use bounded overlap-save convolution of its merged bilinear coefficients when
channel pairs, parallelism and memory estimates favor FFT. Preserve alpha cutoff
behavior, cancellation, selections and depth/model-neutral filtering.

Validate 303 algorithm tests in debug and release, plus native checks and full
image comparisons. Repeated current-upstream comparisons show 2.31x at 24 MP
and 4.15x at 1.5 MP for angle 30 / distance 1000 on the measured host.

Co-authored-by: optimalbytee <optimalbytee@users.noreply.github.com>
2026-10-09 09:02:00 +07:00
Brandon ThomasandClaude Opus 5.5 0b5803500c Regenerate docs/scorecard.md and docs/parity.md after the latest community merges (#1530)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:24:37 -04:00
619095bfd0 Pattern Stamp tool in the S-group flyout (#922)
* Add Pattern Stamp as a Clone Stamp flyout sibling

Introduce paint.patternStamp to paint the current pattern through a
brush stroke. Aligned strokes keep a document-space tile origin;
unaligned strokes restart at the first point; Impressionist jitters
each dab with a seeded RNG. Empty patterns and strokes larger than
4096² pixels return an error instead of allocating.

* Record Pattern Stamp on the tools scorecard

Allow the aligned stamp helper's argument count under clippy.

* Pattern Stamp: raise the stroke cap to 8192² so a 24 MP diagonal fits

The 4096² bounding-box cap refused a corner-to-corner stroke on a 6016x4000 canvas (~24M px).
Unit test covers that diagonal and a still-rejected 9000² box; the hostile-input test uses a
footprint above the new cap. Scorecard note labels Impressionist as an approximation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* i18n(pl): translate the Pattern Stamp strings

The Polish catalog landed on main after this PR was written; the
translation-coverage tests need every language to carry new UI strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Tool::ALL holds 51 tools now that Red Eye and Pattern Stamp both landed

The rebase onto main (with #1084's Red Eye tool) leaves Tool::ALL one entry
longer; bump the array length and the count test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Flyout test: qualify egui::Vec2 (panels.rs no longer imports Vec2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:07:06 -04:00