github storytold/photocraft v0.3.0
PhotoCraft v0.3.0

7 hours ago

Highlights since 0.2.0

182 commits from 183 merged pull requests, including work from 31 community contributors (thank you!), and 146 issues closed.

  • Your work is safer:
    • Recovered unsaved documents survive a second crash.
    • Deeply nested .pcraft files reopen.
    • photocraft-cli batch refuses to overwrite its input folder.
    • Preferences no longer get lost when two windows or tabs save, or when a save fails.
  • Languages: the interface is available in 日本語, 简体中文, 繁體中文, Español, Русский and Čeština (Edit › Preferences › Interface › Language), with CJK fonts and IME input in the Type tool.
  • Files:
    • JPEG and other no-alpha exports composite transparency over white.
    • Formats without colour profiles get sRGB.
    • Truncated JPEGs and multi-frame files open with a warning instead of silently.
    • TGA is offered in Save As and Export As.
  • Editing:
    • Free Transform a Copy and Transform Again on a Copy.
    • Keyboard layer navigation, number keys for opacity, Alt-click colour sampling.
    • New from Clipboard.
    • Undo and redo restore the targeted layer.
    • Shortcuts pressed in quick succession all run, in order.
  • Automation (CLI, MCP, control channel):
    • Stricter, clearer parameter and flag errors, and <subcommand> --help.
    • Background jobs that agents can wait for or poll.
    • Recorded actions run in batch.

Scorecard

This is the first release with docs/scorecard.md, so these numbers are its baseline. 0.2.0 had no scorecard to compare against. Area counts are done / partial / missing.

Area Done Partial Missing Measured
Performance 3 22 12 46 scenarios: 3 within budget, 22 over budget or failing, 13 tracked only, 4 not run, 8 not yet measurable (baseline 2026-10-05)
File compatibility 1 8 18 io corpus oracle ≥ 146/170, round trip ≥ 169/170; psd-tools oracle ≥ 229/309, round trip ≥ 307/309; Photoshop-authored oracles ≥ 130/256, round trip 258/258
Tools 3 14 13
Workspace and UI 0 4 19 settings that do nothing: 60 of 133 (target 0)
Type 0 3 6
Automation 1 3 7 626 of 626 menu items live
Reliability 3 1 3 never-crash lints on 26 of 26 crates; panic_hunt fuzzes every command
Distribution 4 3 4
Open bugs 0 3 29

What's Changed

  • perf(compose): avoid unnecessary backdrop snapshots by @MikeeI in #109
  • perf(compose): prepare gradient stops outside pixel loops by @MikeeI in #103
  • Fix stale effect maps after default-only mask changes by @MikeeI in #105
  • Preserve HDR samples when importing white-matted PSD composites by @MikeeI in #106
  • Mix pass-through group coverage in premultiplied space by @MikeeI in #108
  • perf(compose): avoid redundant effect-halo rendering by @MikeeI in #110
  • Preserve merged PSD alpha at the exported sample precision by @MikeeI in #111
  • perf(compose): reuse compiled vector masks within each render by @MikeeI in #112
  • perf(compose): reuse bounded pattern preparation across render tiles by @MikeeI in #104
  • fix(ui): pasting an image copied in another app never ran by @tiredIsa in #102
  • fix(ui): make Move transform controls interactive by @Ni-zav in #99
  • Menu overlap and overflow #92 by @Ni-zav in #98
  • PR #96 — Liquify undo by @Ni-zav in #97
  • fix(ui): shape tools show the shape while dragging by @sommerper in #87
  • security: bound automation previews and reply resources by @Gh0stlyKn1ght in #93
  • Japanese support: IME input in the Type tool and CJK glyphs in the UI by @kntrttm in #101
  • Community batch follow-ups: on-demand OS clipboard paste; fmt + egui 0.36 test port by @echelon in #134
  • perf(ui): borrow the active layer from its document snapshot by @MikeeI in #121
  • perf(ui): reuse exact cached content bounds by @MikeeI in #116
  • perf(ui): skip offscreen layer thumbnail generation by @MikeeI in #117
  • perf(ui): retain channel thumbnails across view-only revisions by @MikeeI in #120
  • fix(ui): prune thumbnails for removed layers and documents by @MikeeI in #119
  • fix(ui): prune closed-document display and preview resources by @MikeeI in #118
  • Disambiguate colliding document identities at session admission by @MikeeI in #114
  • Warn when the PSD channel limit drops a Quick Mask by @MikeeI in #115
  • Preserve compositing properties in single-layer flat export by @MikeeI in #122
  • Preserve selected real masks during PSD import by @MikeeI in #130
  • Scale artboard bounds in proxy documents by @MikeeI in #131
  • Crop tool: move and resize the crop frame, Space repositions while drawing by @echelon in #132
  • Fix flaky canvas_geom undo test (process-wide text gamma raced by another test) by @echelon in #135
  • Dock: fixed-height panel groups, splitters, collapse, reorder; panels never vanish by @echelon in #139
  • Brush Settings panel: Photoshop structure and depth, edits through tools.setBrush by @echelon in #136
  • Selecting current bit depth must preserve redo by @MikeeI in #133
  • Detect PhotoCraft archives independent of ZIP entry order by @MikeeI in #137
  • Type tool: caret/selection land on the glyph under the pointer; font size is live, one undo step, ~60x faster (#123, #124) by @echelon in #142
  • Layers groups expand/collapse (#126); every displayed shortcut fires (#127) by @echelon in #141
  • Layers rows: names never run under the indicators; fx triangle; Collapse All Groups; designer PSD for QA by @echelon in #167
  • fix(geom): saturate Rect::translate and inflate on i32 overflow by @kevin9327 in #159
  • fix(ui): make tall menus scrollable on short displays by @Ni-zav in #160
  • PSD type layers: bounds regression tests; #148 is the layer's vector mask, not text bounds by @echelon in #165
  • Flatpak single-file bundles as release artifacts by @echelon in #163
  • Roadmap: honest parity assessment (2026-10-05) by @echelon in #182
  • AGENTS.md: no Tauri, Electron or webview shells by @echelon in #184
  • Menus scroll and navigate by keyboard on small displays; Color Range dialog on the no-GPU path (#145, #138) by @echelon in #168
  • Docs: where we stand and where we're going (roadmap, README, AGENTS.md) by @echelon in #186
  • Brushes: Tilt Scale, Brush Projection, Spacing checkbox, section locks, Mixer Wetness/Mix; Brushes grid + drag and drop; options bar through tools.setBrush by @echelon in #174
  • fix(ui): refresh Liquify preview after undo by @Ni-zav in #175
  • fix(ui): sample eyedropper colours while dragging by @Ni-zav in #176
  • fix(ui): keep Curves endpoint handles inside the graph area by @Ni-zav in #177
  • fix(ui): avoid duplicate sliders for wide filter ranges by @Ni-zav in #179
  • Dock polish: Layers gets the height, Character/Paragraph group, eliding tab strips, reveal the active layer (#147, #150, #151, #152) by @echelon in #181
  • Move/Free Transform modifier keys (#90); sharp full-resolution transform preview (#91) by @echelon in #183
  • CJK UI font fallback: Simplified/Traditional Chinese and Korean, lazily loaded in locale order (#149) by @echelon in #185
  • Layers mask thumbnails + chains; Channels/Paths temporary rows and footers (#153, #154) by @echelon in #191
  • GPU compositor: paged residents and effect maps, so 20k+ documents refresh on the GPU (#49) by @echelon in #187
  • Properties: uniform sections, per-kind Quick Actions, full-width controls (#155) by @echelon in #192
  • PSD corpus: psd-tools set (pinned, verified), an oracle for every file, and the fixes it found by @echelon in #195
  • Tool feedback: selection-mode cursor badges, scrubby zoom, contrasting outlines, Shift lines by @echelon in #188
  • PSD fidelity: 16/32-bit colour modes, Lab, Levels, Exposure, Dissolve oracle (corpus 133 → 140, psd-tools 212 → 222) by @echelon in #202
  • Fix tests on FreeBSD with RADV by @mekanix in #194
  • fix(clipboard): use the wayland clipboard for images by @nuIIpointerexception in #222
  • FreeBSD: build and test the workspace in a FreeBSD VM by @echelon in #223
  • Fix automatic UI scaling on 4K monitors by @john8675309 in #225
  • FreeBSD: serialise canvas GPU tests, CI template, RAM detection, CJK font paths by @echelon in #227
  • Title bar: never draw the window title over the menus or controls by @echelon in #241
  • Packaging: Linux runtime deps + start-up library check (#201); wasm 26.3 -> 18.8 MiB (#198) by @echelon in #237
  • Fix live brush preview drawing a polygon (#189) by @echelon in #240
  • PSD effects fidelity: spread metric, emboss, gradient geometry, text gamma (113 -> 118 oracle passes) by @echelon in #224
  • Scorecard: cargo xtask perf + scorecard, budgets, checklists, nightly perf (#221) by @echelon in #239
  • Layout documents: fix GPU device loss, live Move tool, local damage, no per-frame work (#125, #128) by @echelon in #226
  • PSD export: write tagged blocks other readers can parse (#200) by @echelon in #236
  • CR2: measure the colour filter row phase instead of assuming RGGB (#193) by @echelon in #244
  • Atomic saves: one crash-safe atomic_write for every document write by @echelon in #230
  • Preferences: wire tooltips, Home screen, recent files; hide what nothing reads by @echelon in #245
  • Eraser on locked layers: no lock-out from the simple lock button; Stroke Path erases to the background colour (#76) by @echelon in #229
  • Retouch tools paint the mask/channel target; Sample All Layers for Blur/Sharpen/Smudge; premultiplied Smudge (#207) by @echelon in #234
  • Free Transform: selection moves only its part of a linked mask; masked preview; target masks and channels (#205) by @echelon in #242
  • Vertical type (tategaki): lay out, render, edit and round-trip (#199) by @echelon in #246
  • PSD stroke effects: outlines of filled shapes, vector stroke above interior effects, joined subpaths by @echelon in #233
  • Live gradients: Gradient tool makes editable Gradient Fill layers (on-canvas handles, stops, midpoints) + Classic mode (#180) by @echelon in #197
  • Marquee: Shift squares, Alt draws from the centre, live W × H readout (#208) by @echelon in #247
  • GPU: crash-safe startup and device-loss fallback (#243, #4) by @echelon in #252
  • Text: deterministic font family order; hide private system families (fixes a flaky test) by @echelon in #264
  • Photoshop oracles via storytold/photocraft-corpus: pinned corpora, corpus feature, test-corpus, CI job by @echelon in #190
  • Masks: Alt-click to view mask, Cmd-click vector mask to select, vector-mask target brackets (#196) by @echelon in #256
  • Stylus pressure, tilt, rotation and eraser on macOS and X11 by @echelon in #255
  • Fix Windows MSI advertised shortcut icons by @CQMHV in #238
  • Windows taskbar icon: .exe icon id for the MSI shortcut + icon regression tests (#248) by @echelon in #269
  • Colours: handle non-hex Unicode values without an internal error by @storybored379 in #261
  • Align the CJK fallback font's baseline with Latin text by @kntrttm in #260
  • UI: platform shortcut notation in every label and tooltip (#251) by @tiredIsa in #262
  • New Document: a typed Width/Height reaches Create (#254) by @echelon in #270
  • Menus are as tall as their items; scroll only when the window is too short (#235) by @echelon in #272
  • Portable mode: keep settings beside the exe in the Windows portable zip (#228) by @echelon in #267
  • Brush Settings for every brush: options-bar toggle and real preset picker (#258) by @echelon in #268
  • Ctrl+Alt-drag resizes the brush on the canvas (#231) by @echelon in #271
  • Shift rubber band: preview the straight line before the click (#257) by @echelon in #273
  • Selection drag previews: regression tests for #253 (visible mid-drag, 1x and 2x) by @echelon in #274
  • Shortcuts: rebindable fill keys, D/X and held temporary tools (#249) by @echelon in #275
  • PSD manual and optical kerning: import, export, render, edit (#206) by @echelon in #259
  • Localise the UI: i18n foundation and a Japanese catalog (menus, dialogs, panels) by @kntrttm in #169
  • Pencil tool, Edit › Fill… dialog and "Rasterize?" prompt (#213) by @echelon in #279
  • Fast Select › Modify › Smooth and Feather (part of #211) by @echelon in #280
  • Compositor: effect maps never block inside parallel tiles (fixes #276 deadlock) by @echelon in #281
  • FreeBSD release tarball and README platform lines by @echelon in #284
  • fix: forward document index in bridge inspection by @kuishou68 in #287
  • Marquee: stop the selection at the canvas edge by @Multipad-cyber in #263
  • Background layer: double-click, masks and cut behave like Photoshop by @Multipad-cyber in #266
  • i18n: add Simplified Chinese localization by @CQMHV in #282
  • Enable dictionary segmentation for Japanese type by @midasdf in #250
  • Smart Objects and Smart Filters survive PSD save and open by @echelon in #288
  • Apply EXIF orientation on open, write Orientation = 1 on export (#285) by @echelon in #318
  • PSD export: 32-bit files open in Photoshop (HDR toning Color Mode Data, #291) by @echelon in #327
  • Windows on ARM64: release builds, PE header check, install test on ARM64 hardware by @echelon in #333
  • Fix preference usage scanning on CRLF checkouts by @CQMHV in #331
  • Windows: Alt-click clone hint and Ctrl+N channel errors (#251 follow-up) by @bommerts in #336
  • Move tool: Auto-Select on by default; a click picks and drags the layer under the pointer (#296) by @echelon in #330
  • Cmd+Enter (Ctrl+Enter) loads the path as a selection (#306) by @echelon in #329
  • Layers panel: rename commits on click elsewhere, Enter or Tab; one at a time (#314) by @echelon in #326
  • Keyboard Shortcuts: Ctrl+F records as Ctrl+F, not Ctrl+ControlLeft (#292) by @echelon in #323
  • macOS CLI: verify the shipped CLI is Developer ID signed and notarized in the release workflow (#308) by @echelon in #320
  • fix(ui): feed every pointer move per frame so fast strokes stay smooth by @leonaci in #317
  • Fix logic Show the clone crosshair only while Option is held by @juansebsol in #301
  • i18n: add Traditional Chinese (zh-hant) UI catalog by @WildfootW in #302
  • Add a Spanish catalog (menus, dialogs, panels) by @Mawfyy in #299
  • Localise the UI into Russian: a complete catalog and the missed tl! call sites by @tiredIsa in #298
  • Preferences: add an Apply button by @CQMHV in #325
  • i18n: add Czech (cs) UI translation by @petrleocompel in #328
  • Menus: no menu or submenu covers the menu bar (#319) by @echelon in #337
  • Menus stay above the taskbar; oversized windows open maximized (#315) by @echelon in #343
  • Background jobs: engine job API, progress and cancel (part of #210) by @echelon in #289
  • Background jobs in the app: progress, Cancel, open-as-job (part of #210) by @echelon in #373
  • Harden EXIF orientation: limits after rotation, fallible allocation, strict IFD parsing by @echelon in #345
  • Fonts: use craft-fonts as an optional build input; move the Japanese fonts out by @echelon in #353
  • Stamp Visible (Cmd+Alt+Shift+E) and Stamp Down; Alt+Merge keeps the originals (#217) by @echelon in #356
  • Right-click on the canvas lists the layers under the pointer (#307) by @echelon in #360
  • Canvas scrollbars, and Preferences > Tools > Overscroll works (#300) by @echelon in #367
  • Alt+right-drag resizes the brush and changes its hardness (#297) by @echelon in #370
  • Alt+scroll zooms the canvas in 5% steps around the pointer (#293) by @echelon in #371
  • ui.set: reject unknown fields; the theme error names all five themes (#412, #413) by @bflatastic in #437
  • serve: methods lists jobs.list and jobs.cancel (#414) by @bflatastic in #438
  • MCP command_batch and serve batch honour each step's wait (#415) by @bflatastic in #439
  • Headless saves without path never flatten over the opened file (#416) by @bflatastic in #447
  • Alt-click with the Brush, Pencil, Gradient or Paint Bucket samples a colour (#417) by @bflatastic in #450
  • Layers panel: double-click beside a layer's name opens Layer Style (#350) by @bflatastic in #452
  • Batch runs report inputs that share an output name instead of overwriting (#420, #422) by @bflatastic in #448
  • New from Clipboard, and Paste with nothing open makes a document (#368) by @bflatastic in #458
  • CLI: unknown flags are usage errors, <subcommand> --help prints usage, usage lists --quality (#421, #423) by @bflatastic in #460
  • Liquify remembers its brush settings between uses and launches (#418) by @bflatastic in #461
  • The main window opens centred on the screen (#419) by @bflatastic in #462
  • Keyboard layer navigation: Alt+[ / Alt+] / Alt+, / Alt+. and Shift to add (part of #352) by @bflatastic in #470
  • Transform Again on a Copy (Cmd+Alt+Shift+T): step and repeat (part of #352) by @bflatastic in #474
  • Number keys set opacity, Shift+[ / Shift+] step hardness, Shift+Cmd+A opens Camera Raw (part of #352) by @bflatastic in #473
  • Export: TGA in Save As and Export As (#363) by @Pedroj-64 in #377
  • Docs and MCP schema: use the real Gaussian Blur id (#378) by @floflo777 in #390
  • Image Size shows the one-pixel minimum it applies (#441) by @HEOJUNFO in #468
  • prefs.reset resets a single colorSettings key (#445) by @HEOJUNFO in #467
  • Content-Aware Scale: enlarging a 1 px wide or tall layer no longer panics by @Ar-maan05 in #387
  • Build desktop app by default (#392) by @agorevski in #425
  • fix(engine): use wasm-safe timing for Liquify by @naumanAhmed3 in #393
  • Profile mismatch: compare profiles by colour, not bytes (sRGB vs sRGB prompt) by @ljkx in #394
  • Type: dragging a paragraph box handle resizes the box (#351) by @Pedroj-64 in #376
  • docs: correct VectorCraft sibling name by @agorevski in #429
  • Free Transform a Copy (Cmd+Alt+T); Esc takes the copy back (part of #352) by @bflatastic in #482
  • Raise rust-version to 1.95, the minimum egui 0.36 needs by @carterwsmith in #471
  • docs: add star history chart to README by @coygeek in #469
  • Move drag reveals a larger-than-canvas layer's off-canvas pixels by @sommerper in #526
  • Spanish: add missing tool, filter and path translations by @neversaynv3r in #488
  • Dialogs keep their top-left when their content resizes by @sommerper in #487
  • PSD export selects PSB above size limit (#212) by @agorevski in #431
  • 32-bit documents: Exposure works on the stored linear values by @floflo777 in #400
  • Ctrl+Insert copies and Shift+Insert pastes on Linux; Shift+Insert pastes images on Windows by @sommerper in #531
  • Docs: roadmap, scorecard and README after the 2026-10-07 fixes by @bflatastic in #538
  • CLI batch: recorded-action steps, --format .ext, strict --quality, refuse --out = --in (#489, #490, #491, #492) by @bflatastic in #545
  • Gradients honour explicit transparency stops; smart filter commands accept an explicit layer target (#465, #466) by @bflatastic in #544
  • Recovered documents keep their recovery data until saved or closed (#444) by @bflatastic in #549
  • History: tool and preset names, Frame from Layers as one step, undo/redo restore the targeted layers (#513, #528, #446, #496, #495) by @bflatastic in #551
  • Shortcuts run in the order pressed; Shift+Delete fills on Windows; colour pickers stay put while dragging (#440, #530, #534) by @bflatastic in #552
  • Control channel: menu/dialog requests wait for their job; right-click menus at the point; MCP ui_pointer button (#510, #511, #512, #514) by @bflatastic in #548
  • Automation: non-object params rejected; headless sees finished jobs; serve stdio survives a bad line; MCP batch keeps results (#503, #504, #505, #506, #529) by @bflatastic in #546
  • Formats: deep .pcraft groups reopen; zero-size PSD rejected; JPEG mattes over white; no-ICC formats get sRGB (#517, #519, #521, #522) by @bflatastic in #555
  • Preferences merge with other tabs/windows and retry failed saves; web startup shows a Reload hint (#475, #476, #477) by @bflatastic in #561
  • FreeBSD CI: run the GPU integration tests one at a time by @bflatastic in #576
  • Import warns when it keeps only the first frame or page, or a JPEG ends early (#518, #523) by @bflatastic in #563
  • Linux: AppImage update information and a .zsync beside it (#349) by @ianswope in #399
  • Color Picker and Color panel fields accept typed values by @carterwsmith in #485
  • Release 0.3.0 by @bflatastic in #577

New Contributors

Full Changelog: v0.2.0...v0.3.0

Don't miss a new photocraft release

NewReleases is sending notifications on new releases.