* Filter dialogs: paint the preview computed mid-drag instead of waiting for the pointer to stop
A preview that finished while the slider was still moving was thrown away before it
could reach the canvas, because the worker result had to match the request on every
field including the parameters. Every completion of a drag lands after the value has
moved on, so none of them matched, the worker was handed the newest value instead, and
that one went stale in turn. Nothing was ever painted while the pointer moved: the
effect appeared only once the slider had been still for about a frame of preview
time, which is what "I have to stop the slider and wait" looks like.
The display gate a few lines below already had the opposite rule. It compared the
document, revision, dialog, layer, channel target, command and proxy factor and
deliberately left the parameters out, so that a slightly old frame stays on screen
mid-drag. The publish gate disagreed with it and won, so the frame the display gate
was written to keep never existed.
Publish a successful result when the finished request matches the current one on
everything except the parameters, and let the existing display gate decide whether to
keep it. The two gates now share one predicate, FilterPreviewKey::same_target, so
they cannot drift apart again.
Errors keep the exact match. A value the pointer has already dragged past should not
raise a notice, and a failure is not something to show stale.
What this deliberately does not change:
- A reopened dialog has a new id, a committed document a new revision, a different
command or channel target a different key, so a result from another preview is still
never painted. Covered by a_reopened_dialog_discards_the_previous_dialogs_finished_preview.
- The freshly computed request is still what decides whether a new computation starts,
so the worker still converges on the value the dialog actually holds.
- One preview runs at a time and a stale one is still cancelled only once the values
settle, so this adds no work to the worker; it only stops discarding completed work.
- OK still recomputes at full resolution, so a frame shown mid-drag is never what gets
written to the document.
Test: a_preview_computed_mid_drag_reaches_the_canvas starts a blur at one radius, moves
the slider before that preview lands, and requires the completed frame to reach the
canvas while the slider is still on the new value. It fails on the old gate, timing out
after 10 s with no frame published.
* Filter dialogs: three guards on a mid-drag preview, after review
The first version of this let any completed frame through that matched the dialog
on everything but the parameters. Review found three ways that is wrong, and all
three are now closed and pinned by a test.
A stale result with nothing to show. Storing it replaces a good frame with an empty
one, which the display gate paints as "draw nothing": the canvas blinks back to the
unfiltered layer mid-drag. The exact request may still store an empty result, which
is how a filter that no longer applies clears the canvas, so the guard belongs on
the stale arm only. Splitting the match arm is what makes that separable; the
earlier single arm forced a false choice between the two.
A late frame replacing an exact one. Drag the slider away and straight back: the
frame on screen is already exact for the dialog, and the in-flight frame for the
value on the way out would have overwritten it, showing a blur the user has already
undone. A stale result is now dropped when the stored preview is already exact.
Errors were already scoped to the exact request and stay there: a value the pointer
has dragged past should not raise a notice, and the value it comes to rest on will
raise its own when it is recomputed.
Also pinned by test, because both are easy to undo by accident:
- The reopen test was not reaching the gate. discard_closed reclaims a closed
dialog's job a frame earlier in the real app, and the test called it too, so the
stale result never arrived and the test passed even with the dialog id removed
from the comparison. It now drives the gate directly. Verified by mutation.
- The mid-drag test asserted nothing about what the display gate does with the
published frame, so re-adding params there passed. It now asserts the canvas
actually returns something to draw, and it keeps polling until a frame for the
dialog's current value lands, which is what pins fresh to an exact match.
Tests are deterministic: the worker job is gated on a channel and signals when its
result is already in the worker channel, so nothing sleeps and nothing races the
150 ms settle timer that cancels a job whose values stopped changing.
Verified by mutating each guard and confirming a test catches it:
publish gate back to exact-match ................. killed
drop the is_some guard ........................... killed
drop the already-exact guard .................... killed
same_target ignores the dialog id ............... killed
display gate compares params again .............. killed
fresh relaxed to same_target .................... killed
same_target ignores k ........................... killed
k stays in the comparison on purpose. A 36 MP document previews at k=4, and
preview_factor lowers k as a pixel-sized parameter approaches its minimum, so k does
change under the slider. Relaxing it would paint a frame at a scale the preview
policy exists to avoid, and would loosen the display gate further than upstream
wrote it. The cost is a one-computation pause when the slider crosses a threshold
on a large document; that test keeps the choice visible.
* Filter dialogs: fix a race in the new tests that let CI pass them
The four new tests signalled each other through a channel the worker sends from inside
`compute`. But the worker only puts the result into the channel after `compute` returns:
let result = compute(&work);
let _ = tx.send(result);
So a test that woke on the signal and called `ensure_filter_preview` immediately could
reach `poll()` before that send. On a loaded CI runner it did: ubuntu failed
`a_mid_drag_empty_result_leaves_the_preview_alone` with no frame published at all. The
comment in the test claimed the result was already in the channel, which was the one
thing it was not.
The tests now drive the canvas until the state they need appears, which does not depend
on the order of that send. They also check their invariant on every pass rather than
only at the end: a wrongly published frame can be replaced by the next, correct one
before the loop stops, which had already left the reopen, late-frame and empty-result
tests unable to see their own mutation.
Unchanged: the assertions, the production code, and the four mutations that broke each
guard — re-verified, 7 of 7 still caught.
Runs: 30 back-to-back runs of the four tests on 12 cores, no failure; the full crate
twice, 2800 pass.
---------
Co-authored-by: agent-346022 <340881286+agent-346022@users.noreply.github.com>
PhotoCraft
Image editing; an open-source, clean-room reimplementation of Adobe Photoshop, rebuilt in pure Rust.
Layers, masks, adjustment layers, layer styles, type, vectors, brushes and real PSD files,
in a native app written entirely in Rust. Open source, offline, and yours.
PhotoCraft on getartcraft.com · ArtCraft · All Crafting Apps
A caption card with a drop shadow, live type, and Vibrance and Curves adjustment layers, with the Curves editor open.
The Great Wave off Kanagawa, Katsushika Hokusai, c. 1831
Note
ArtCraft is a community of artists from all walks of life. Digital, generative, music, games — if you make things, you're one of us. Come say hi on Discord.
Features · Everything in the box · PSD · Agents · Under the hood · Get started · Downloads · Crafting Apps · Discord
🎛️ Familiar by designThe menus, shortcuts, panels and tools are where your hands expect them, from ⌘J to ⇧⌘D. If you know Photoshop, you already know PhotoCraft. |
⚡ Native and fastA GPU compositor on wgpu (Metal, Vulkan, DX12, WebGPU), copy-on-write tiles and multithreaded filters. No Electron, no web view, no waiting. |
🗂️ Real PSD filesOpen, edit and save layered Photoshop documents. Re-saving keeps the render of 307 of the 309 psd-tools test files. |
🤖 Agent-readyEvery action is a command, so you can drive the same engine from the UI, the CLI, a JSON control channel or an MCP server. |
Features
Every screenshot here is the real app at work on public-domain art, rendered offscreen through its control channel.
Levels and Vibrance adjustment layers, with the live Histogram panel. Impression, Sunrise, Claude Monet, 1872 Edit without regretAdjustment layers keep every edit live. Stack Levels, Curves, Vibrance, Hue/Saturation and a dozen more, mask them to an area, reorder them, or turn them off, and your original pixels never change.16 adjustment layers that also apply directly to pixels, including Curves with per-channel editing, Levels with a live histogram, Black & White, Channel Mixer, Gradient Map, Photo Filter, Selective Color and Color Lookup (.cube, .3dl, .look). Plus Shadows/Highlights, Replace Color, Match Color, HDR Toning, Desaturate and Equalize. |
Outer Glow and Stroke on a live type layer, in the Layer Style dialog. Earthrise, William Anders / NASA, 1968 Styles that sell the shotDrop Shadow, Inner Shadow, Outer and Inner Glow, Bevel & Emboss, Satin, Stroke, and Color, Gradient and Pattern Overlay, live on any layer, including type. Patterns come from a library (built-ins, Edit › Define Pattern,.pat import/export) and PSD Patt blocks.
Copy and paste styles between layers, hide all effects at once, and open styles straight from your PSDs, rendered to match Photoshop. |
An elliptical selection becomes the mask of a Hue/Saturation layer, so only the face keeps its color. Girl with a Pearl Earring, Johannes Vermeer, c. 1665 Selections that understand your imageMarquees, lassos and the Magic Wand for precision; Quick Selection, Object Selection and Select Subject when you want the computer to do the tracing; Select and Mask to refine hair-fine edges.Feather, expand, contract, smooth, grow, reselect. Turn any selection into a layer mask, a vector path or a shape. Smart selection runs on your machine, with no cloud and no account. |
A headline edited in place, with a byline and a paragraph of body text. Among the Sierra Nevada, California, Albert Bierstadt, 1868 Type that sets beautifullyPoint and paragraph text, edited right on the canvas, with full Character and Paragraph controls: font, weight, size, leading, tracking, alignment and colour. The full Type Color Picker also supports screen sampling with a pixel loupe.Type layers stay editable, take layer styles, and round-trip through PSD. |
A badge made of shape layers: a gradient-filled lotus, a star and a dotted ring. Water Lilies, Claude Monet, 1906 Pixel-perfect vectorsRectangle, Ellipse, Triangle, Polygon, Line and the Pen, Freeform Pen and Curvature Pen tools, with resolution-independent shape layers, gradient fills, and dashed, aligned strokes.Combine shapes (unite, subtract, intersect, exclude), keep paths in the Paths panel, use them as vector masks, or stroke and fill them. 116 of 116 shape layers in our PSD corpus match Photoshop's pixels. |
Twirl previews live on the canvas, only inside the selection. The Starry Night, Vincent van Gogh, 1889 See it before you commitEvery filter dialog previews live on the canvas, through your selection. Blurs (Gaussian, Box, Motion, Radial, Surface, Smart, Lens, Shape, and the Blur Gallery: Tilt-Shift, Iris, Field, Spin, Path), sharpening, Reduce Noise, distortions (Twirl, Wave, Ripple, Displace, Shear, Zig Zag…), Pixelate, Stylize (Oil Paint, Wind, Extrude…), Render (Clouds, Fibers, Lens Flare, Lighting Effects) and more.Run filters on a smart object and they stay editable: change, hide, reorder or mask them at any time. Large-radius blurs use running-sum box passes across all cores: a radius-180 Gaussian on 3.6 MP takes under a second. |
Free Transform on a rotated print, with every step listed in History. The Tetons and the Snake River, Ansel Adams, 1942 Shape it any way you likeFree Transform with scale, rotate, skew, distort and perspective; exact 90° and 180° rotations and flips; Transform Again. Layers, type, shapes, masks and selections all transform together.Full history, Toggle Last State and the History Brush mean every step can be undone, even one brush stroke at a time. |
Export As in the light theme, with a preview and a file-size estimate. The Kiss, Gustav Klimt, 1907–1908 Ship it anywhereExport As with format, quality, transparency and scale, plus a preview and an instant file-size estimate. Quick Export to PNG in one click.Choose a dark Pro theme, the airy Studio themes, or a Classic look. |
Everything in the box
🧰 67 toolsMove · Artboard · Rectangular and Elliptical Marquee · Single Row Marquee · Single Column Marquee · Lasso · Polygonal Lasso · Magnetic Lasso · Object Selection · Quick Selection · Magic Wand · Crop · Perspective Crop · Slice · Slice Select · Frame · Eyedropper · Color Sampler · Ruler · Note · Count · Remove · Spot Healing Brush · Healing Brush · Patch · Content-Aware Move · Red Eye · Brush · Pencil · Mixer Brush · Color Replacement · Clone Stamp · Pattern Stamp · History Brush · Eraser · Background Eraser · Magic Eraser · Gradient · Paint Bucket · Blur · Sharpen · Smudge · Dodge · Burn · Sponge · Pen · Freeform Pen · Curvature Pen · Add Anchor Point · Delete Anchor Point · Convert Point · Horizontal and Vertical Type · Horizontal and Vertical Type Mask · Path Selection · Direct Selection · Rectangle · Ellipse · Triangle · Polygon · Line · Custom Shape · Hand · Rotate View · Zoom |
🖌️ A real brush engineShape Dynamics, Scattering, Texture, Dual Brush, Color Dynamics, Transfer, Brush Pose, Wet Edges, Build-up and Smoothing (including Pulled String), driven by pen pressure, tilt, rotation and direction. Brush presets, Define Brush from Selection, and deterministic, replayable strokes. |
🗃️ Layers, done properlyGroups, clipping masks, pixel and vector masks, fill layers (solid, gradient and pattern), adjustment layers, live smart objects with smart filters and lossless transforms and warps, multi-layer selection with align, distribute and link, alpha channels and Quick Mask, 27 Photoshop blend modes plus six Paint.NET variants, opacity and fill, locks, colour labels, a layer kind filter, merge, flatten, rasterize, Layer via Copy/Cut, Paste Into. |
🎨 Any colour, any depthRGB, Grayscale, CMYK and Lab documents at 8, 16 and 32 bits per channel. Bit depth and colour model are runtime data, so every tool works at every depth.Real ICC colour management in pure Rust: embedded profiles, Assign and Convert to Profile with all four rendering intents and black point compensation, soft proofing (⌘Y) and Gamut Warning (⇧⌘Y) on the GPU. |
🗂️ FormatsPSD and PSB, layered TIFF (Photoshop's layer data in the TIFF, read and written in either byte order), Paint.NET PDN3 (read, with editable layers and all 14 blend modes), OpenRaster (read and write, with layers, groups and blend modes, for Krita, MyPaint and GIMP), Krita .kra (read, with paint layers, groups, blend modes and transparency masks), SVG (opens as shape layers, places as a vector Smart Object), plus flat PNG, JPEG, TIFF, WebP (lossy and lossless), GIF, BMP, TGA, ICO, QOI, PNM, OpenEXR, Radiance HDR and FITS (astronomy images: 8/16-bit and 32-bit float, gray or RGB, header kept), and the native.pcraft format. Flat formats retain the depths they support: PNG keeps 8/16-bit samples, TIFF keeps 8/16-bit and 32-bit float samples, and OpenEXR keeps half/float samples; JPEG, WebP and the other 8-bit formats reduce higher-depth samples with an export warning. See the codec capability matrix for each format. HEIC photos from iPhone and Mac are read-only (included in official builds; optional --features heif for source builds). AVIF is write-only with the optional avif build feature; AVIF decoding and JPEG XL are unavailable. Affinity documents (.af, .afdesign, .afphoto, .afpub) open natively, read only, with artboards, layers, vectors, text, images and masks; effects, adjustments and other unsupported parts are listed in a warning, and Affinity export is unavailable.
|
🪄 The everyday essentialsAuto Tone, Contrast and Color · Equalize · Image and Canvas Size · Crop and Trim · Reveal All · Edit › Fill and Stroke · Copy Merged · Paste in Place · guides, rulers, grid and snapping · Actions record and replay · a command palette (⌘F). |
PSD without compromise
PhotoCraft's PSD support is a standalone crate written from Adobe's public specification and tested against a corpus of real-world files.
- Faithful round trips: opening and re-saving a document renders the same for 307 of the 309 files in the psd-tools test set and 169 of 170 in our mixed ag-psd/psd-tools set (
crates/io/tests/corpus.rs; fetch the psd-tools set withcargo xtask corpus --psd-tools), and anything we don't model yet (raw blocks, descriptors, extras) is carried over instead of being dropped. A re-saved file is not byte-identical to its source: PhotoCraft rewrites image resources, layer records and the composite. Only the standalonephotocraft-psdcrate, parsing and writing a file without the document model, reproduces every parseable corpus file byte for byte (crates/psd/tests/corpus.rs). - Pixels that match: a composite oracle compares our render with Photoshop's own merged image, covering gradient interpolation (Classic, Perceptual and Linear), layer effects, shape strokes, clipping and fill opacity.
- Large documents: PSB, 16 and 32-bit files, and CMYK and Lab documents open natively.
Built for agents
Every menu item, tool and dialog runs a command from one registry of 500+ commands. The UI, the CLI, the JSON control channel and the MCP server all call the same commands, so anything you can click, a script or an AI agent can do too.
# Headless: open, edit, save
photocraft-cli run wave.psd \
--cmd filter.sharpen.smartSharpen --params '{"amount":80}' \
--cmd layer.newAdjustmentLayer.curves --params '{"points":[[0,0],[64,48],[192,212],[255,255]]}' \
--out wave-final.png
# Apply one action list to a folder of images
photocraft-cli batch --actions grade.json --in ./raw --out ./graded
# Every subcommand explains itself
photocraft-cli batch --help
# Let an agent drive it over MCP (headless, or bridged to the running app)
photocraft-cli mcp
The desktop app also offers an authenticated, loopback-only control channel (photocraft --control) for inspecting UI state, driving tools with pointer events, and taking offscreen screenshots. Every image in this README was rendered that way. See docs/control-protocol.md.
Under the hood
- Engine first: a pure-data document model and a command engine, with a thin egui UI on top. Layering is enforced at build time across 24 crates.
- Two compositors: a CPU compositor serves as the reference oracle, and a wgpu compositor puts the canvas on the GPU. They are tested against each other.
- Copy-on-write tiles: 256² sparse tiles make undo cheap and huge canvases light, and effect maps are cached per layer state.
- Runs in the browser: the whole engine and UI compile to WebAssembly.
- Clean-room: implemented from public specs and observed behaviour only. No proprietary code, shaders or assets.
- Tested: more than 1,700 tests, including PSD round trips, synthetic generators, compositor oracles and multi-depth checks.
Get started
git clone https://github.com/storytold/photocraft
cd photocraft
cargo run --release -p photocraft -- image.psd # the desktop app
cargo test --workspace # the test suite
Japanese fonts for the UI and Type tool come from craft-fonts, an optional build input (desktop release builds always include it). Without it PhotoCraft uses your system's CJK fonts:
git clone https://github.com/storytold/craft-fonts ../craft-fonts
CRAFT_FONTS_DIR="$PWD/../craft-fonts" cargo run --release -p photocraft
New contributors and AI agents: start with AGENTS.md, then docs/.
Installers for macOS, Windows, Linux, FreeBSD and the web are attached to each GitHub release. On Linux you can pick an AppImage, a .deb, an .rpm, a tarball or a Flatpak bundle. The bundle needs the freedesktop runtime from Flathub, which flatpak offers to install along with it:
flatpak install --user photocraft-<version>-linux-x86_64.flatpak # or -linux-aarch64
flatpak run ai.storyteller.photocraft
The AppImage needs no install: the first run registers its launcher icon and menu entry in ~/.local/share so the dock shows PhotoCraft's icon on Wayland. Set PHOTOCRAFT_NO_DESKTOP_INTEGRATION=1 to skip that, and see docs/releasing.md › Linux to undo it.
On a Wayland session, files dropped on the window don't open yet: winit 0.30, the windowing library under egui, has no Wayland drag and drop (#386). Use File › Open, or copy the image in your file manager and paste it with Ctrl+V. To drag and drop, start PhotoCraft under XWayland: WAYLAND_DISPLAY= photocraft, WAYLAND_DISPLAY= ./photocraft-<version>-linux-x86_64.AppImage, or flatpak run --nosocket=wayland --socket=x11 ai.storyteller.photocraft. On Wayland, PhotoCraft shows the command for your install in a notice until you dismiss it. Preferences › Performance › Linux display server = X11 does the same on every launch. With a fractional display scale (125%, 150%, 175%) an XWayland window is drawn at a lower resolution and enlarged by the compositor, so the interface is blurred there; native Wayland stays sharp (#1072).
On macOS, the command-line tool comes as photocraft-cli-<version>-macos-universal.zip. The binary is signed with the same Developer ID as the app and notarized by Apple. A bare binary can't carry a stapled notarization ticket the way the DMG does, so the first time you run it macOS checks the notarization online. You can confirm it yourself:
ditto -x -k photocraft-cli-<version>-macos-universal.zip .
spctl --assess --type install -vv photocraft-cli-<version>-macos-universal/photocraft-cli
# ... accepted, source=Notarized Developer ID
On FreeBSD 14 (x86_64), the release has a tarball laid out like /usr/local. Install the runtime libraries, then unpack it there:
pkg install libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader gtk3 fontconfig freetype2 alsa-lib
tar -xzf photocraft-<version>-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local
photocraft
Maintainers: docs/releasing.md explains how releases are built, signed and published.
Important
Status: PhotoCraft is in early alpha, and we want to be straight about where it stands: much of Photoshop's feature surface exists in some form, but it is not yet a Photoshop replacement for daily professional work. The biggest gaps are AI/generative features, 15 missing tools, depth in typography and pro workflows, and plug-in compatibility. Every Photoshop menu item is wired to a command (
docs/parity-checklist.md), but that measures wiring, not behaviour. The honest, dimension-by-dimension picture and where we're going next are in the roadmap and parity assessment. Expect rough edges, and please file issues (include your OS, document size, layer count and a screenshot). You can also tell us what broke on Discord.
Documentation
Developer, architecture, automation, format, and security documentation is maintained in the PhotoCraft documentation book.
To self-host the browser version with Docker, see Docker web hosting.
Security
Security architecture, threat modeling, parser hardening, fuzzing, and vulnerability reporting are covered in the security documentation and the repository security policy.
Test corpora
PhotoCraft is tested against real files: our own Photoshop-authored oracle PSDs in
photocraft-corpus plus the psd-tools, ag-psd and PngSuite sets, pinned and
sha256-verified. Fetch them with cargo xtask corpus --all and run the tests with
cargo xtask test-corpus (details in docs/development.md).
Downloads
New to PhotoCraft? Download it from the PhotoCraft page on getartcraft.com. That's the easiest way to install it.
Want a specific build or format? On GitHub, the latest release has every build listed below, and all releases has earlier versions and their notes. <ver> in the file names is the version number, and SHA256SUMS.txt lists a checksum for every file.
Windows
| Build | Installer | Portable |
|---|---|---|
| x64 (64-bit Intel/AMD) | photocraft-<ver>-windows-x64.msi |
photocraft-<ver>-windows-x64-portable.zip |
| arm64 (Snapdragon and other ARM PCs) | photocraft-<ver>-windows-arm64.msi |
photocraft-<ver>-windows-arm64-portable.zip |
| x86 (32-bit) | photocraft-<ver>-windows-x86.msi |
photocraft-<ver>-windows-x86-portable.zip |
Installers and executables are code-signed.
macOS
| Build | File | Notes |
|---|---|---|
| App, universal (Apple silicon + Intel) | photocraft-<ver>-macos-universal.dmg |
Signed and notarized |
| Command-line tool, universal | photocraft-cli-<ver>-macos-universal.zip |
Signed and notarized |
Linux
| Format | x86_64 | aarch64 (ARM64) | Notes |
|---|---|---|---|
| AppImage | photocraft-<ver>-linux-x86_64.AppImage |
photocraft-<ver>-linux-aarch64.AppImage |
Runs anywhere; updates itself with AppImageUpdate (.zsync files) |
| Flatpak | photocraft-<ver>-linux-x86_64.flatpak |
photocraft-<ver>-linux-aarch64.flatpak |
Sandboxed; flatpak install --user <file> |
| Debian/Ubuntu | photocraft-<ver>-linux-x86_64.deb |
photocraft-<ver>-linux-aarch64.deb |
|
| Fedora/RHEL/openSUSE | photocraft-<ver>-linux-x86_64.rpm |
photocraft-<ver>-linux-aarch64.rpm |
|
| Tarball | photocraft-<ver>-linux-x86_64.tar.gz |
photocraft-<ver>-linux-aarch64.tar.gz |
Unpack anywhere |
RISC-V (riscv64): photocraft-<ver>-linux-riscv64.tar.gz only, built against Ubuntu 24.04 (needs glibc 2.39+).
FreeBSD
| Build | File |
|---|---|
| x86_64 | photocraft-<ver>-freebsd-x86_64.tar.gz |
Web (WebAssembly)
| Build | File | Notes |
|---|---|---|
| Static site | photocraft-web-<ver>.zip |
Runs in a modern browser; host it on any static server |
The Crafting Apps
PhotoCraft is one of the Crafting Apps: free, open-source creative tools from the ArtCraft team, each written from scratch in Rust and each able to stand on its own.
| App | What it's for | Code | Learn more | |
|---|---|---|---|---|
| PhotoCraft | Image editing: layers, masks, type and real PSD files · you are here | GitHub | Website | |
| VectorCraft | Vector illustration | GitHub | Website | |
| FilmCraft | Video editing, color and sound | GitHub | Website | |
| LightCraft | Photo library and raw development | GitHub | Website | |
| PdfCraft | Reading, organizing and protecting PDFs | GitHub | Website | |
| EffectCraft | Motion graphics and visual effects | GitHub | Website | |
| DesignCraft | Page layout and publishing | GitHub | Website |
And ArtCraft itself, our AI image and video studio for artists who want real control.
The Crafting Apps share the same conventions: clean-room and pure Rust, native on macOS, Windows and Linux, in the browser via WebAssembly, and fully drivable by agents.
Come make things with us
Our Discord is where artists of every kind hang out: people who paint, shoot, draw, cut film, set type, and people still figuring out what they like to make. Share what you're working on, ask for help, tell us what's broken, or tell us what you wish these tools could do. Whatever your medium and however long you've been at it, you're welcome here.
discord.gg/artcraft · getartcraft.com · The Crafting Apps · PhotoCraft
License and credits
PhotoCraft is dual-licensed under MIT or Apache-2.0, at your option. Copyright (c) 2026 ArtCraft Team and the PhotoCraft contributors. Required notices are in NOTICE.
Bundled fonts, icons, images and other assets keep their own open licenses; each one is listed with its author, source and license in ATTRIBUTION.md.
Every artwork shown is in the public domain (Wikimedia Commons, NASA, U.S. National Archives); sources are listed in docs/images/SOURCES.md.
The ArtCraft name, wordmark and logos in docs/brand/ are trademarks of the
ArtCraft Team and are not covered by this license. They may be used only unmodified, and only as
part of this repository and PhotoCraft, under docs/brand/LICENSE-brand.txt.
Forks and modified versions must remove them.
Adobe, Photoshop, Illustrator, Premiere Pro, Lightroom, Acrobat, After Effects and InDesign are trademarks or registered trademarks of Adobe Inc. in the United States and/or other countries. PhotoCraft is an independent, open-source project and is not affiliated with, sponsored by or endorsed by Adobe Inc.; these names are used only to describe the workflows it is compatible with.
Made by the ArtCraft team and community.







