PhotoCraft
An image editor that aims at Photoshop feature by feature, written from scratch in Rust, with every action exposed as a command so the menus, a CLI, a JSON control channel and an agent all drive the same engine.

What it is
An image editor for people who already know Photoshop and would rather not rent it. The menus, the shortcuts and the panels are arranged the way Adobe arranges them, and a document can be opened, layered, masked, retouched, typeset, adjusted through live adjustment layers and written back out as a layered PSD. Underneath there is no web view, no Electron and no C++: a pure-data document model, a registry of commands that every surface dispatches by id, a CPU compositor kept as the reference and a GPU compositor tested against it, and a colour engine that reads ICC profiles itself. It ships as a signed desktop application on macOS, Windows, Linux and FreeBSD, and as the same Rust compiled to WebAssembly for the browser. The project calls itself early alpha and puts a number on how far along it is.
Who built itAn organisation account created in 2021, with 56 public repositories and 25,251 followers. It publishes seven desktop applications under one house style and one set of written conventions: PhotoCraft, VectorCraft, FilmCraft, LightCraft, PdfCraft, EffectCraft and DesignCraft, plus ArtCraft itself, a hosted image and video studio. The PhotoCraft repository names 184 accounts across its 1,256 commits; the largest is @echelon, credited with 240 commits and 281,036 lines added, and 228 commit trailers name that account as a co-author. contributors/people.toml holds the names a dozen contributors chose for the About window, and the file asks each person to add only their own entry.
How it is put together
The parts · 6The organising idea is that the engine is the product and the interface is a client of it. A document is pure data: a layer is an enum whose variants include pixel, adjustment, fill, text, shape and smart content, and the pixels live in 256-pixel tiles behind Arc pointers, so taking a snapshot costs one pointer per layer and undo, autosave and a background job all read a document without a lock. Nothing user-visible exists outside one command registry. A menu item, a keyboard shortcut, the command palette, a recorded action, the command-line tool, a loopback JSON control channel and an MCP server all resolve to the same command id with the same typed parameters, which is what lets an agent drive the application with no screen attached. Bit depth and colour model are runtime data on every surface, so an 8-bit RGB document and a 32-bit float CMYK one move through the same code. Two compositors are maintained in parallel: a CPU one that is the reference oracle and a wgpu one that is measured against it. The shell is deliberately thin, egui on eframe with no webview and no JavaScript anywhere in the project, and the same crates compile to WebAssembly, which the build enforces rather than hopes for.
- crates/geom, color, cms, raster
- The foundation layer: geometry, pixel formats and the blend math that operates on them, an ICC colour engine that parses profiles and builds transforms and LUTs, and the copy-on-write tile store every other crate allocates through.
- crates/psd and crates/codecs
- Format crates that depend on nothing else in the workspace, so each can be published and read on its own. The PSD crate is the whole Photoshop file: header, layer records and masks, colour mode data, the descriptor and tagged-block readers, and parsers for brushes (
.abr), swatches (.aco), gradients (.grd), patterns and TIFF. - crates/doc
- The document model as data and nothing else: layers, groups, clipping, pixel and vector masks, adjustment layers, layer styles, smart objects with smart filters, alpha and spot channels, guides and slices. No rendering, no toolkit, no I/O.
- crates/ops, paint, algo, text, vector
- History and the journal, the brush engine with its dynamics and deterministic replayable strokes, the imaging algorithms, the type engine, and paths and shapes with their boolean operations.
- crates/compose, gpu, format
- The CPU compositor that serves as the oracle, the wgpu compositor that draws the canvas on Metal, Vulkan, DX12 or WebGPU and is tested against the CPU one, and
.pcraft, the native format that fails to compile when a document field is added and not mapped, so a save cannot silently drop one. - crates/engine and crates/ui-egui
- The session and the command registry, roughly 700 commands declared with id, label, menu path, default shortcut, parameter documentation, an enabled gate and a run closure, plus the egui shell that owns only view state and dispatches everything else.
crates/automationadds the MCP server, andapps/photocraft,apps/photocraft-cliandapps/photocraft-webare three front doors onto the same engine.
Choices, and the alternative
Make every user-visible action a command in one registry over implementing features in the interface and exposing some of them later
It is rule one in
AGENTS.md, with the reason attached: the UI, CLI, control channel and MCP all dispatch by id, so a feature written as a command is drivable by an agent and by a script the day it lands, and using the id from the Photoshop menu catalogue makes the menu item live with no interface work at all.Carry bit depth and colour model as runtime data on every surface over an 8-bit RGB core with high-depth paths bolted on
The architecture document opens with a section titled Avoiding GIMP's hole, which walks through what it cost GIMP to hard-code 8-bit tiles: a second engine, GEGL, started around 2000 and only finished in 2.10 in 2018. PhotoCraft puts a
PixelFormat { depth, model, alpha }on every surface, forbidsu8in public engine APIs, and runs its golden tests at 8, 16 and 32-bit.Keep the CPU compositor as the oracle for the GPU one over shipping the GPU path and trusting it
Two compositors are tested against each other, and the CPU one decides whether the GPU one is right. The project advertises agreement within 1/255 of a channel, and
crates/gpu/tests/parity.rsis the file that has to keep saying so.Write the PSD crate from Adobe's published specification over reading another implementation of the format
The contributing guide names the sources and states the rule that goes with them: behaviour may be studied, code may not be copied, and implementations come from the published specification. It is also why unmodelled blocks are carried through a round trip rather than dropped.
Forbid panics and
unsafein non-test code over treating crashes as bugs to be fixed as they are reportedThe workspace denies the whole panic family (
unwrap,expect,panic!,unimplemented!and its kin) across clean crates and forbidsunsafeeverywhere except the isolated pen-input crate, and an integration test fuzzes every command with adversarial parameters. The stated reason is that people trust the application with work they cannot recreate.Compile the engine and the shell to WebAssembly over shipping a native-only application
No crate below the shell may use a toolkit, file-system code is behind a
cfg(not(target_arch = "wasm32")), and the build checks the whole lower stack against the wasm target. The browser build is the same application, and the size constraint is written into the Cargo profile: a fat-LTO, size-optimised profile with the pixel-processing crates pinned back toopt-level 3, which took the wasm from 26.3 MB to 18.8 MB.
Read fromAGENTS.md, ROADMAP.md, docs/architecture.md, docs/target-app-parity.md, docs/gaps.md, docs/scorecard.md, docs/parity-checklist.md, docs/contributing.md, docs/development.md, docs/releasing.md, README.md, ATTRIBUTION.md, Cargo.toml, contributors/contributors.json, .github/workflows/ci.yml and release.yml, scorecard/, perf/budgets.toml and the code under crates/ in storytold/photocraft, read 2026-10-11.
Build log
5 stages- 01
What the eighteen megabytes are
The tree I cloned on 2026-10-11 holds 1,053
.rsfiles, 18,512,884 bytes of Rust and 408,084 lines. GitHub's own language breakdown agrees to within a rounding error (18,510,175 bytes of Rust) and puts WGSL shaders a distant second at 53 KB. The mass sits in two places:crates/ui-eguicarries 129,589 lines of egui interface, andcrates/engineanother 87,855 lines of commands. Below themalgo(42,272),io(26,545),codecs(16,154),psd(13,813),compose(11,146) andraw(9,818) are where the image processing lives, and the file names there are algorithms rather than plumbing:nonlocal.rs,inpaint.rs,matting.rs,puppet.rs,liquify.rs,seam.rs,poisson.rs,panorama.rs,camera_raw.rs. Roughly a third of the tree is tests: 83,731 lines inside inline#[cfg(test)]modules, 61,398 more undertests/directories, and 5,733#[test]attributes, with 511 files carrying an inline test module of their own. Nothing is stubbed:unimplemented!()appears zero times in the whole tree, and clippy is configured to deny it along with the other macros that mark work as unfinished. The largest single file iscrates/ui-egui/src/canvas.rsat 5,921 lines, and it is not a table. Not counted in the 18.5 MB are the sixteen interface translations undercrates/ui-egui/src/i18n/, about 1.9 MB of.tsv, or the 4.5 MB of icons, fonts and a SCOWL word list underassets/. The repository counts itself:docs/architecture.md, rewritten on 2026-10-10, says ~393,000 lines of Rust in ~1,020 files and ~5,460 test functions, which is the same tree measured a few hours earlier. The README, on the same day, advertises "more than 1,700 tests". - 02
The first thirty-four commits added 175,558 lines
The repository was created on 2026-09-30, and its second commit is messaged
one-shot. It touched 241 files and added 42,038 lines. Three more did the same:continued wip(+37,493 across 181 files),more algorithms, progress(+43,275 across 213 files) andAnalysis, notes, proof views, workspaces (+ in-progress work of other agents)(+34,026 across 162 files). Those four commits carry about 157,000 lines between them, and the 34 commits that landed before 2026-10-03 add up to 175,558. Only after that does the history start to look like a repository: small commits, a subject line, a body, a pull-request number. The method is written down in the tree.AGENTS.mdopens by announcing that it is a guide for AI agents, and its sixth section is titled Parallel agents: each one is told to setCARGO_TARGET_DIR=target/agent-<name>so they never contend for Cargo's build lock, to write new commands into new modules rather than growing shared ones, and that each target directory costs about ten gigabytes. It points atlog/devlog.mdas the way the next agent picks up, on the grounds that sessions end abruptly through crashes and context limits;log/is gitignored, so none of that record is in the clone. Standards shared across the family of apps live in a sibling checkout calledcraftrules, and the docs repeat three times that it is not public. The commit trailers hold the rest of the answer. Of the 1,256 commits onmain, 898 carry aCo-authored-byline; 782 of those name a Claude model, 31 name Copilot, and 228 name the maintainer. Read the other way round: near enough two commits in three credit a model. The project's own units follow from that.ROADMAP.mdestimates the work left to beta as 1,100 to 1,800 Opus 5.5 agent-hours, and its calibration section says those hours come from the repository's own merged pull requests. - 03
The clean-room claim, and how far it can be checked
The claim is in the repository description: a clean-room reimplementation of Photoshop. What the repository does about it is written as a rule.
AGENTS.mdrule 3 says Photoshop and other proprietary editors were studied for behaviour and look only, that their code, shaders, profiles and assets are never copied, and that implementations come from public specifications, naming the Adobe PSD specification, the ICC specification and ISO 32000 for the blend modes. Parts of that are checkable from the tree. The PSD support is its own crate with no workspace dependencies, and its tests run against corpora pinned by sha256 inxtask/src/corpus_pins.rs: the project's own Photoshop-authored oracles, plus the psd-tools, ag-psd and PngSuite sets. The colour engine parses and writes ICC profiles itself, and the one CMYK profile it ships is synthetic, generated bycrates/cms/src/synth.rsand released under a CC0 dedication.ATTRIBUTION.mdcarries a row per non-code asset with path, author, source and licence, and the rows are the boring kind: Lucide and Feather icons under ISC and MIT, Inter and JetBrains Mono under the OFL, a SCOWL word list. Those are the files where a copy would show up. Where the target came from is where reading stops being auditable from the repository.docs/target-app-parity.mdsays Photoshop 2026 was inspected without launching it: document types fromInfo.plist, read and write flags from the format plug-ins' PiPL resources,.lprojlanguage packs, theDefault Keyboard Shortcuts.kysfile and strings read out of the main binary. Reading a purchased bundle is not reading source, but a reader cannot check that distinction from here. The question is open on the tracker and the project has not answered it. Issue #341, filed 2026-10-06 by @soapdog, asks whether code generated by a model trained on an unaudited corpus can be called clean-room at all. It has 13 comments, all from outside accounts, and they turn on two points: a model's training set cannot be audited, and a human's memory cannot be audited either. The repository is not in the thread. A second one is quieter and has no reply either: #2332, filed 2026-10-10, points out that the Adwaita colour palettes the themes use come from LGPL desktop stylesheets, against the rule that bundled assets must be permissively licensed. - 04
Six hundred and twenty-eight menu items, and what that measures
The repository generates its own report card, and it is a harsher critic than the README.
cargo xtask paritycompares Photoshop's menu tree against the live command registry and writesdocs/parity-checklist.md; a test holds the result above a floor of 627 so it cannot regress. The current file reads 628 of 628 menu items live, menu by menu: File 52, Edit 75, Image 61, Layer 161, Type 44, Select 25, Filter 75, View 74, Window 61. The README then says what that is worth in its own words: every Photoshop menu item is wired to a command, and that measures wiring, not behaviour. The measured half of the scorecard is indocs/scorecard.mdand the numbered gap list indocs/gaps.md, and the two agree with each other. Toolbox tools are 53 of 68, with 15 named as missing: Artboard, the single-row and single-column marquees, Perspective Crop, Frame, Color Sampler, Color Replacement, Art History Brush, Freeform and Curvature Pen, the three anchor-point tools, and the two type-mask tools. Panels are 30 of 35. File formats are 13 of 31 in Photoshop's own directions, with 4 partial. Of 149 preferences, 46 do nothing. PSD is where the numbers in the tree disagree. The scorecard's oracle compares PhotoCraft's render against Photoshop's own merged image and matches 133 of 256 Photoshop-authored files (52%), 146 of 170 of the project's io corpus (86%) and 236 of 309 of the psd-tools set (76%). The README leads instead with round-trip rendering, 307 of the 309 psd-tools files, which is a different and easier question, and the website says 134 of 135 real-world files round-trip byte for byte. Performance is measured against budgets inperf/budgets.toml, and 3 of 25 scenarios meet theirs. Moving a layer that carries layer styles takes 321 ms against a 25 ms budget, an opacity change 276 ms against 20, and pasting a 12-megapixel image 1.2 s against 100 ms. Artificial intelligence is the room with nothing in it: there is no ML runtime in the tree at all, so selection and removal are classical work (max-flow graph cuts, non-local patch completion, PatchMatch-style inpainting) and Generative Fill, Neural Filters and Sky Replacement are absent rather than approximated. Add those up and the project's own answer is on the first screen of its roadmap: feature breadth about 76%, ready for real work about 45% with a stated range of 40 to 50, stage alpha, and one blocking beta gap, that Photoshop will not reliably reopen what PhotoCraft writes (#1281, #2469). - 05
It runs, and how you would know
Build instructions are four lines: clone,
cargo run --release -p photocraft -- image.psd. The workspace wants Rust 1.95 and edition 2024, its lock file pins 728 packages, and the fonts for the Type tool are an optional checkout of a second repository rather than files in this one. Eight releases were cut in eleven days, from v0.1.0 on 2026-10-02 to v0.6.0 on 2026-10-10, and the latest carries 24 files: MSI and portable ZIP for Windows on x64, arm64 and x86, a universal notarized DMG and a matching command-line tool for macOS, AppImage, Flatpak, deb, rpm and tarball for Linux on x86_64 and aarch64, a FreeBSD 14 tarball laid out for/usr/local, and an 11 MB static site for the WebAssembly build. The v0.6.0 files have been downloaded 73,049 times, 24,040 of them the Windows x64 installer. I checked that installer rather than taking the README's word for it.Get-AuthenticodeSignatureon the downloaded MSI reports Valid: signed byCN=Learning Machines Incof Atlanta, Georgia, issued by Microsoft ID Verified CS EOC CA 03, and countersigned by Microsoft's public timestamping authority. The repository's own gap list, written the same day, still carries "Windows code signing (material not obtained)" as missing, and the distribution checklist still says signing is skipped with a warning until the material exists. The released file says otherwise. The caveats are in the README rather than discovered later. On a Wayland session a file dropped on the window does not open, because winit 0.30 has no drag and drop there (#386), and the README prints the workaround. The FreeBSD build is produced in a VM and shipped as a plain tarball. There is no in-app update check and no in-app bug report. The website that sells the downloads is one release behind: on 2026-10-11 it still offered 0.5.0 installers and asked for Rust 1.90, while the repository had been on 0.6.0 for a day. The continuous integration is not a formality. Eight workflows, 6,583 runs, and aci.ymlthat runs formatting, clippy, the workspace tests on Linux and Windows, a pass without the optional HEIC decoder, a pass with the font input present, the layering check, a wasm check and the corpus tests, leaving macOS to the release pipeline because the organisation keeps its five macOS slots for signing. Of the last 60 completed runs of that workflow, GitHub reports 3 green. Twelve of the cancelled ones are pushes tomain, while the file carries a comment saying runs onmainare never cancelled, so that no merged state goes unverified.
What they would tell you
- The clean-room question is open and unanswered. Issue #341, filed 2026-10-06, has 13 comments from outside accounts and none from the project; a model whose training corpus nobody can audit cannot certify its own provenance, and the repository does not argue otherwise. Issue #2332, filed 2026-10-10, notes that the Adwaita palettes behind some themes come from LGPL stylesheets, against the project's own rule that bundled assets be permissively licensed. Neither has a reply. The licence is MIT or Apache-2.0 at your option, with one carve-out: the ArtCraft name, wordmark and logos are trademarks that may be used only unmodified and only as part of this repository, so a fork has to remove them.
- It is early alpha by its own measurement, and the measurement is specific: about 45% ready for real work against about 76% feature breadth, 22 of 25 performance budgets missed, 46 of 149 preferences wired to nothing, 15 of 68 tools absent, no ML runtime for any of the AI features, and one gap the roadmap calls blocking for beta, that Photoshop does not reliably reopen what PhotoCraft writes (#1281, #2469). The alpha gate is described as passing on six core workflows, four of which are partial in depth.
- The README's numbers are the weakest part of the repository, and three of them disagree with the tree or with each other on the same day. It advertises "more than 1,700 tests" where the source holds 5,733
#[test]attributes and the architecture document of the same date says ~5,460. Its Windows download table says the installers are code-signed whiledocs/gaps.mdstill lists Windows signing as missing, and the MSI in the release verifies as signed. Its PSD headline of 307 of 309 round trips sits beside the scorecard's 133 of 256 against Photoshop's own render and the website's 134 of 135, which are three different questions. - Volume and depth arrived at different times. Menu parity, the number the project leads with, went from 224 items to 532 in a single day and reached completion on 2026-10-03, the fourth day; the user-facing work began once 0.5 and 0.6 were in people's hands, which is why the tracker rather than the README is where the state of the project is written down.
- The tracker is the honest description of what this is. GitHub counts 784 open items on the repository on 2026-10-11; paging through the list the same morning returns 557 issues and 228 pull requests, one more than the counter, since the two are read minutes apart. In eleven days 1,276 issues were filed and 718 closed, and the open titles are user reports against the two releases rather than wishes: a Wacom pen offset by a few pixels, brush lag with large brushes, Arabic layer names rendering as tofu, a crash on a 150-layer document, CMYK broken on the Linux AppImage. The project's own ranked work list puts the backlog at 250 to 400 agent-hours, the largest single item after PSD fidelity and performance.
- The CI does not corroborate the test count. Of the last 60 completed runs of the main workflow, 3 were green, 22 failed, 23 were cancelled and 12 were waiting for a maintainer to approve a fork's workflows. Cloning and building is the check that still works: the releases, the corpus pins and a signed installer are there, and
cargo run --release -p photocraftis the four-line version of the same claim.
Adjacent records
All records →No. 083
OpenChatCut
A local-first video editor whose editing surface is a conversation: the built-in agent and external Codex or Claude Code sessions call the same editing tools the interface itself uses, so every change lands on a real multi-track timeline as a clip, transition, caption, effect or audio item that can still be dragged, undone and exported. Projects and media stay on the machine, and preview and final render both come out of Remotion.
No. 071
Reticle
An MCP server and a dev-only SDK that let a coding agent read and drive a running web or desktop app from the inside, then answer with a verdict and the file and line to fix instead of a screenshot.
No. 142
typesafe-computer-use
It drives a Mac toward a goal typed in plain English: OCR and the accessibility tree read the screen, a TypeSafe classifier picks the next action, and a writing model runs only for free text. A decision costs about $0.0002, a fiftieth of a cent, against $0.032 for a frontier model reading the same screenshot.