Valentin KleinandFredApps a4bde72bca .aep: import twice as fast, faster export (#3302)
* aep: a layer's markers and Source Text are read where they are stored, not searched for (#3276)

A layer's marker list is a direct child of its root tdgp, and its Source Text record
btds a direct child of the ADBE Text Properties group. Markers walked the whole layer
subtree twice per layer (most layers have no marker list, so the walk always ran to the
end), and the three text-document accessors walked it once each.

* aep export: build the prototype template once, sort names with cached keys (#3277)

The template every export clones from is immutable; it is now built by the
first export of the process and kept (about 0.93 MB). The name sort builds
each natural key once instead of on every comparison. Root solids move into
the Solids folder instead of being copied. The two key-list rewrites share one
emit-local helper and match names compare as bytes instead of a decoded String.
Output is byte-identical.

* aep container: size sibling lists, hex and write output once; borrow plain .aepx attributes (#3275)

- read.rs: count the chunk headers of a sequence first and allocate the
  children Vec once (bounded by the input and by the chunk limit).
- aepx.rs: decode_hex sizes its output once; attribute values without
  an entity are borrowed instead of copied through decode_entities.
- typed.rs: PropGroup::get compares match names without building a
  String (same result as the lossy compare, invalid UTF-8 included).
- write.rs: reserve the exact output size up front (try_reserve, so a
  hand-built tree cannot abort on the allocation).
- read.rs, settings.rs, values.rs: use the shared bytes.rs readers.

Output is identical on the corpus (tree, written bytes, import).

* aep container: review fixes (#3275)

- read.rs: reserve with try_reserve_exact, so a raised chunk limit on a
  small target cannot abort before parsing; the capped reservation and a
  deep, retry-heavy nest of broken lists are pinned by tests.
- write.rs: a tree past the 32-bit container size fails with TooLarge
  before anything is serialised.
- aepx.rs: drop an unneeded local and lifetime annotation.

* aep export: note what the concurrency test covers and why a failed template build is not kept (#3277)

* aep: text documents are read without a String per token, defaults built once (#3276)

TextDocument::parse reads a borrowed tree: names, bare words and strings without
escapes point into the body, keys are borrowed when they are /names, numbers parse from
the borrowed bytes, and dictionaries and arrays are moved into vectors of their exact size
when they close. The style and paragraph defaults are built once instead of per document.
parse_text_dict keeps its public TextValue result (the borrowed tree turned owned).

The old owning parser stays as a test-only oracle: a differential test compares both on
40 000 generated bodies (every key form the owned keys canonicalise, non-UTF-8 names,
escapes, unclosed strings, non-finite numbers), every cut of a realistic document and
nesting around the depth limit.

* aep: text-dict test builds its prefix without repeat(1) (#3276)

* aep: an escaped text string drops its byte order mark without a range drain (#3276)

* aep export: one key-time loop, key-list rewrite, tdmn decoder and byte writer for the listed modules (#3278)

In masks, shapes, styles, synth, fxsynth, base, camlight, skeleton,
textanim and tree (effects.rs, plan.rs and emit.rs keep their copies for
the follow-up work):
- New export/keys.rs: the key-time loop (timed_keys), the key-list rewrite
  (fill_key_list, set_key_list, replace_cdat) and the spatial key record,
  shared by masks, shapes and styles.
- One tdmn decoder (synth::tdmn_name, lossy UTF-8 up to the first NUL, as the
  importer reads it) and one encoder (synth::tdmn) instead of the copies in
  masks, styles, shapes, textanim, camlight and skeleton.
- One byte writer: tree::put, which errors. base::bytes, synth::tdb4,
  synth::key_list, fxsynth::pard, masks::shph and the keyed path records write
  through it; their fixed layouts keep the infallible signatures behind
  tree::fixed, which logs, and a test builds every layout and requires no error.
- camlight::put_group uses the shared group split (tree::split_group), which
  errors on a match name without a node instead of stopping quietly.

Export output is byte-identical on the corpus and the synthetic fixtures.

* aep export: pin the key-time loop's report, name the layout in the base::bytes log (#3278)

* aep export: review fixes for #3278

- tree::Fixed replaces tree::fixed: a fixed layout writes every field that
  fits (as the old code did) and keeps the first error; finish() logs it
  once with the layout's description and counts it per thread, so the
  every-layout test cannot race with other tests.
- base::bytes logs one line naming its length and fields.
- masks::build_atom errors when the prototype has no Mask Shape instead of
  dropping the path of every mask quietly.
- log sorted into the dependency list.

* aep: review fixes for #3276 text documents and markers

text_document reads the first btdk in the Source Text record, the documents
text_document_count counts. The old slot checks (same, is_neutral, undecoded_fields)
join the test oracle and are compared on 20 000 generated slot dictionaries; mixed
dictionary/array chains and a document left open at the depth limit join the parser
differential. An escaped string's byte order mark is drained without a copy.

* aep: remove test-only container accessors, share report and time-base code (#3281)

- Remove 35 public container accessors that only tests called (header,
  camera/light, keys, footage, masks, shapes, version) and the dead
  StyleMap::switch_name. Tests now check the importer's own reading of the
  same bytes, or the decoder it uses; three import tests gain the values
  the removed checks covered.
- Import and export reports share one loss entry (Loss<C>) with record,
  total, count and summary; the JSON shape is pinned for both.
- Collector::lose_with builds a detail only below the detail cap (callers
  switch later).
- The export uses the container's TimeBase; one NTSC table serves import
  and export; TimeBase::frames saturates like units instead of returning 0.

* aep: review fixes for #3281: NTSC table beside TimeBase, real-path NTSC round trip, light and camera defaults on import, doc wording

* aep: drop a local check tool committed by mistake (#3281)

* aep export: sort keys as one compact byte string, bounded by the name (#3277)

The cached natural keys were Vecs of (bool, String, u128) segments: a 255-byte
name of alternating letters and digits took about 14 KB, held for every item at
once. Each key is now one byte string whose byte order is the natural order,
at most 5 bytes per name byte. Order and output are unchanged.

* aep container: check bdata digits and size before reserving (#3275)

decode_hex reserved the decoded size before it knew the value decodes,
so a large bdata with a bad digit reserved half its length first. It now
refuses a value larger than a chunk's 32-bit size field (TooLarge), checks
every digit in one vectorisable pass, and only then reserves, with
try_reserve_exact so a value that does not fit in memory is an error
instead of an abort.

* aep export: the every-layout test counts from a baseline, not from zero (#3278)

* aep export: correct the order the natural sort key doc gives for equal numbers (#3277)

* aep: the format notes name the accessors that remain (#3281)

* aep: the format notes name the 1 x 1 mask scale of text and shape layers (#3281)

* aep: read imports through a flat tree index (#3300)

Import reads an .aep through TreeIndex, one depth-first array of chunks that
borrows the file's bytes, instead of building and freeing the owned Chunk tree
(one Vec per list). The parser mirrors read::Parser step for step: the same
chunk count order against max_chunks, the same depth limit and opaque
fallbacks, the same errors. The typed view reads through Node, a handle to a
chunk of either tree, so the accessors work unchanged on both; .aepx keeps its
owned tree. Chunk, parse and write stay for export and editing.

The array starts small and doubles, never past what the input can hold or the
chunk limit allows; a failed allocation is TooLarge, a tree past u32 indices
TooManyChunks.

* aep export: the time remap and Transform keys use the shared key-list and match-name helpers; doc comments for the audit's functions (#3300)

* #3300: import .aepx through the flat index

The .aepx reader no longer builds the owned chunk tree element by
element. It decodes every body (hex, text, alias JSON, numbers) into
one buffer and records the chunks as depth-first entries whose bodies
are ranges of that buffer; TreeIndex::from_drafts turns them into the
index the importer reads, which borrows the buffer. read_aepx converts
that index into the owned tree in one pass.

The tree and the errors are those of the previous reader, which the
tests keep as the reference: generated and damaged documents under
seven limit sets, invalid UTF-8, hostile input, the fixture directory,
and imports through both. Bound tests pin the chunk list to the input
and the limit, and check that dropped content leaves nothing behind.

* #3300: read_aepx keeps its own owned-tree reader

read_aepx, read_aepx_with_limits and parse_any build the owned chunk
tree element by element again, as before the .aepx index, instead of
converting the index (which held the decoded buffer and the owned tree
at the same time). Import keeps the index reader. The tests now
compare the two production readers.

* #3300: test keys that round to the same time

* aep: compare the destination projects in the index-equivalence tests

both() and both_aepx() kept only the ImportResult of each path; they now keep
both destination Projects and assert structural and serialized equality, so a
layer or property value regression cannot pass on equal ids and reports.

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-13 00:54:29 +01:00
…
…
…
…
…
…

ArtCraft

EffectCraft icon: an engraved unicorn on a pink tile

EffectCraft

Motion graphics and visual effects; an open-source, professional motion graphics and visual effects studio, built in pure Rust.

A free, open-source compositor: compositions, layers, keyframes, 308 effects, layer styles, expressions, 3D cameras and lights, and a render queue, native on macOS, Windows and Linux, and in the browser. Young, moving fast, and already usable.

Status: young and moving fast Written in Rust License: MIT OR Apache-2.0
Scanned by SonarCloud Reviewed by CodeRabbit

Join the ArtCraft community on Discord

EffectCraft on getartcraft.com · ArtCraft · All Crafting Apps


EffectCraft's main window: the animated demo composition in the Composition panel, the Project panel, a Timeline with text, shape and solid layers, and the Properties panel showing the selected text layer's transform, font and paragraph settings

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.

What it is · Animate · Effects · 3D · Export · Agents · Get started · Status · How it's made · Downloads · The Crafting Apps · License

What EffectCraft is

EffectCraft is for animated titles, motion graphics and compositing work: the kind of thing motion designers and VFX artists need. You build a composition out of layers (solids, shapes, text, footage, other compositions), animate their properties with keyframes, stack effects on them and render the result.

The interface feels natural and responsive, with dedicated panels (Project, Composition, Timeline, Layer, Footage, Effect Controls, Tools, Preview, Effects & Presets, Audio, Info, Paragraph, Character, Align, Progress, Render Queue) and standard motion graphics shortcuts, going further in a few places where it matters to us:

  • Lottie import and export built in, so animations can go straight to the web and apps without a plugin.
  • A project file you can read. Projects are versioned JSON (.ecproj), so they diff cleanly in version control.
  • Everything is scriptable. Menu actions, timeline edits and property changes are exposed as commands. Engine commands are available through the CLI, JSON control channel and MCP; UI-only commands use the frontend dispatcher and can be invoked through the control channel or an attached MCP bridge.
  • No FFmpeg. Video and audio decoding and encoding are pure Rust: FilmCraft's codecs and EffectCraft's own VP9, AV1, HEVC and Opus encoders.

Animate

The panels, menus and shortcuts follow standard motion design conventions: Project, Composition, Timeline, Effect Controls, Properties, Effects & Presets, Character, Paragraph, Align, Info, Preview, Audio and the Render Queue, docked the way you expect. Drag footage, comps and effects between them: onto the comp viewer, where they land under the pointer, or into the Timeline, between layers and at the time you point to.

  • Layers of every kind: solids, shapes, text, footage, nested compositions, nulls, adjustment layers, cameras and lights; parenting, track mattes, all 38 blend modes, motion blur.
  • Keyframes that behave the same: linear, Bezier, hold, auto and continuous Bezier, roving keys, Easy Ease (F9), Keyframe Velocity and Interpolation dialogs, copy and paste at the current time, and a Graph Editor with value and speed graphs and draggable handles.
  • Time: time remapping, time stretch, time-reverse, freeze frame, work area, markers, exact frame-accurate timing at every frame rate including 29.97 drop-frame.
  • Shapes and masks: shape layers with trim paths, repeaters, round corners, offset, zig zag, twist, wiggle, merge paths and gradient strokes; masks drawn with the pen tool, with modes, feather, expansion and vertex editing in the viewer.
  • Text: point and paragraph text with real shaping in any font installed on your machine, the Character and Paragraph panels, and text animators with range selectors.
  • Expressions: JavaScript with the standard motion expressions model (wiggle, loopOut, thisComp.layer("…"), vector maths on arrays), an inline editor and the pick-whip.
  • Timeline like you know it: twirl layers open to Transform, masks, effects and the rest; drag rows to reorder layers; rename with Enter or a double-click; the property shortcuts (A, P, S, R, T, M, F, E, L, U and their double presses AA, PP, SS, RR, TT, MM, FF, EE, LL, UU), Shift to add properties, Alt+Shift+A/P/S/R/T to key the current time, Ctrl+` to twirl selected layers.
  • Puppet tools: Position, Advanced, Bend, Starch and Overlap pins on a mesh built from the layer, real-time pin recording, rotate/scale handles, pins driven by (or carrying) nulls for rigging, and follow-through for hair and cloth.

The Graph Editor showing an eased value curve for a text animator's Range Start, with the graph editor's button bar for hold, linear, auto Bezier and Easy Ease

Effects

308 built-in effects across its categories, each with its parameter names, order and defaults: blur and sharpen, channel, color correction (Curves, Levels, Hue/Saturation, a full color-grading panel…), distort (Warp, Bulge, Turbulent Displace, Perspective Pin…), generate (Fractal Noise, Gradient Ramp, Stroke, Write-on, Audio Spectrum…), keying, matte, noise and grain, perspective, simulation (Particle Emitter 3D, Rainfall, Shatter, Card Dance, Caustics, Wave World…), stylize (Glow, Glass Relief…), time (Echo, Posterize Time, Timewarp, Time Displacement…), audio (Reverb, Parametric EQ, Delay, Stereo Mixer…), text, transitions, utility and expression controls. All nine Layer Styles (Drop Shadow, Inner/Outer Glow, Bevel and Emboss, Satin, overlays, Stroke) with Global Light. Preview plays audio in sync, with meters and waveforms.

3D

Classic 3D compositing: 3D layers with orientation and material options, one- and two-node cameras with depth of field, lights (parallel, spot, point, ambient) with soft ray-traced shadows, layers that intersect correctly, orbit, pan and dolly camera tools, and Front, Top, Left and Custom views.

The 3D Showcase demo in Custom View 1: intersecting cards lit by a spot light with soft shadows on a gridded floor, with the camera frustum and light drawn as wireframes

Export

A dedicated Render Queue, with Render Settings and Output Modules: H.264 MP4 and ProRes MOV (Proxy to 4444 XQ with alpha) with audio, HEVC (Main / Main 10) and AV1 MP4, WebM (VP9 with inter frames and alpha, or AV1; Opus audio), PNG, JPEG, TIFF, Targa and 32-bit EXR sequences, animated GIF and WAV/AIFF. Field rendering with 3:2 pulldown, effect/solo/guide/depth overrides, crop, region of interest and resize, Render Settings and Output Module templates with defaults, post-render actions, storage overflow and render logs. The same queue runs from the command line. Every encoder is pure Rust (craft-libs' H.264, ProRes, HEVC, VP9, AV1 and AAC; EffectCraft's own Opus); there is no FFmpeg inside.

Lottie goes both ways: File ▸ Export ▸ Lottie JSON… writes a composition (precomps, shape, solid, image, text and null layers, eased and spatial keyframes, masks, track mattes, blend modes, time remapping, optionally expressions) as .json or .lottie, and lists anything Lottie cannot express; File ▸ Import ▸ Lottie… opens one as a new composition.

The Render Queue panel with two compositions queued

Built for agents

Engine commands are available through the CLI, JSON control channel and MCP. UI-only commands need the running app's frontend dispatcher: complete menu access requires the app's control channel or an attached MCP bridge. Headless MCP sessions expose supported engine commands, but not UI-only commands or bridge-only ui_* tools.

  • MCP server: effectcraft-cli mcp speaks the Model Context Protocol over stdio, headless or bridged to the running app (--bridge 9877). Tools cover commands, the project and property tree, keyframes and rendered frames. This repository ships a ready .mcp.json.
  • Command line: one-shot calls with JSON output, for example effectcraft-cli set Main '#1' transform/position '[100,360]' --time 0 main.ecproj --save or effectcraft-cli render --comp Main --out main.mp4, or effectcraft-cli exec file.exportLottie '{"comp":"Main","path":"main.json"}' main.ecproj.
  • Control channel: effectcraft --control 9877 accepts JSON lines to run commands, inspect and click any widget by its automation id, and take screenshots.

See docs/agents.md and docs/control-protocol.md.

Get started

Installers for each version are on the Releases page: a universal macOS app; Windows MSIs and portable zips for x64, x86 and ARM64; Linux AppImage, Flatpak, deb, rpm and tar.gz for x86_64 and aarch64, plus a riscv64 tar.gz; a FreeBSD x86_64 tarball; and the web build. Downloads lists every file. The Windows ARM64 build runs natively on Windows on ARM, without x64 emulation. CI installs that MSI on Windows 11 ARM64 hardware, checks both programs are ARM64 and runs the command-line tool there, but it doesn't open the app's window or run the test suite natively on ARM64 yet, so please report anything that behaves differently.

On Gentoo, the community ::snakebyte overlay packages the Linux release as media-video/effectcraft-bin (not maintained by the EffectCraft team):

eselect repository add snakebyte git https://github.com/switch87/snakebyte-overlay.git
emaint sync -r snakebyte
echo 'media-video/effectcraft-bin ~amd64' >> /etc/portage/package.accept_keywords/effectcraft
emerge --ask media-video/effectcraft-bin

To build it yourself you need Rust 1.95 or newer.

git clone https://github.com/storytold/effectcraft
cd effectcraft
cargo run --release -p effectcraft          # the app (add `-- --demo` to open the demo project)
cargo run --release -p effectcraft-cli -- render --out intro.mp4    # render the demo headless
cargo xtask web --serve 8765                # the browser build on http://127.0.0.1:8765/ (docs/web.md)

New to it? docs/footage.md covers importing footage and image sequences and Interpret Footage.

To work on it: cargo test --workspace, and cargo xtask ci before every commit (format, lints, tests, layering, asset attribution and the WebAssembly build). See CONTRIBUTING.md, docs/architecture.md and docs/testing.md.

Where it stands

EffectCraft is young: its first commit was on 1 October 2026. A comprehensive feature set exists, including 308 effects, but breadth is not the same as full maturity across every edge case. Today it's a good place to try things and to tell us what breaks. It isn't yet recommended for production client work. In particular:

  • Native project format. Projects are saved as .ecproj, readable versioned JSON. Proprietary project formats and After Effects SDK plug-ins are not supported.
  • Fidelity is still being refined. Automated rendering tests currently focus on small compositions, so please report visual discrepancies or unexpected behaviour.
  • macOS is the most tested platform. Linux and Windows users have hit basic interaction bugs, which we're fixing first.
  • The trained models are new. Roto Brush can use MobileSAM (an optional 40 MB download in Settings ▸ Roto Brush) and face tracking can use Google's MediaPipe Face Landmarker (an optional 3.8 MB download in Settings ▸ Face Tracking). Both are actively undergoing evaluation and tuning.

EffectCraft is in alpha: about 91% of the features tracked in docs/target-app-parity.md exist, and we estimate it is about 45% of the way to being ready for full professional production work. The ROADMAP has the plan, docs/target-app-parity.md the measurement and docs/gaps.md every known shortfall. The web build (docs/web.md) runs the full app in the browser. Bug reports are the most useful thing you can send us right now.

How it's made

  • Engine first. A stack of small crates with strict layering. The interface (egui) sits on top and nothing underneath depends on it.
  • Clean room. We work from public documentation and observable behavior, never from proprietary files, icons, presets or code. No code is copied from GPL projects. The full rules are in AGENTS.md.
  • Private by default. No telemetry, and no network access unless you ask for it.
  • One family. EffectCraft shares its time model and text engine design with FilmCraft, and gets its video and audio codecs from it.

Downloads

New to EffectCraft? Download it from the EffectCraft 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) effectcraft-<ver>-windows-x64.msi effectcraft-<ver>-windows-x64-portable.zip
arm64 (Snapdragon and other ARM PCs) effectcraft-<ver>-windows-arm64.msi effectcraft-<ver>-windows-arm64-portable.zip
x86 (32-bit) effectcraft-<ver>-windows-x86.msi effectcraft-<ver>-windows-x86-portable.zip

Installers and executables are code-signed. The installer asks who to install EffectCraft for and where. By default it installs for your account only, into %LOCALAPPDATA%\Programs\ArtCraft\EffectCraft, without an administrator prompt; "Everyone on this computer" installs into C:\Program Files\ArtCraft\EffectCraft (Program Files (x86) for the 32-bit build). Later versions install into the same folder. To install silently into a folder of your choice: msiexec /i effectcraft-<ver>-windows-x64.msi /qn INSTALLFOLDER="D:\Apps\EffectCraft". A silent install is per-user by default. INSTALLFOLDER chooses the folder, not who it is installed for; add ALLUSERS=1, from an elevated terminal or deployment tool, for an all-users install.

macOS

Build File Notes
App, universal (Apple silicon + Intel) effectcraft-<ver>-macos-universal.dmg Signed and notarized
Command-line tool, universal effectcraft-cli-<ver>-macos-universal.zip Signed and notarized

Linux

Format x86_64 aarch64 (ARM64) Notes
AppImage effectcraft-<ver>-linux-x86_64.AppImage effectcraft-<ver>-linux-aarch64.AppImage Runs anywhere; updates itself with AppImageUpdate (.zsync files)
Flatpak effectcraft-<ver>-linux-x86_64.flatpak effectcraft-<ver>-linux-aarch64.flatpak Sandboxed; flatpak install --user <file>
Debian/Ubuntu effectcraft-<ver>-linux-x86_64.deb effectcraft-<ver>-linux-aarch64.deb
Fedora/RHEL/openSUSE effectcraft-<ver>-linux-x86_64.rpm effectcraft-<ver>-linux-aarch64.rpm
Tarball effectcraft-<ver>-linux-x86_64.tar.gz effectcraft-<ver>-linux-aarch64.tar.gz Unpack anywhere

RISC-V 64-bit: effectcraft-<ver>-linux-riscv64.tar.gz (tarball only; needs glibc 2.39+, e.g. Ubuntu 24.04+ or Debian 13+).

File drag-and-drop on Linux: The current eframe/winit 0.30 native Wayland backend does not deliver file-hover or file-drop events. On Hyprland and other native Wayland sessions, use File ▸ Import ▸ File… (which accepts multiple files), or start EffectCraft via XWayland if XWayland is installed and DISPLAY is set:

env -u WAYLAND_DISPLAY effectcraft

When the backend delivers events (X11/XWayland, Windows and macOS), dropping media anywhere in the window imports it, and a drop-target hint appears while hovering. On native Wayland the app cannot detect an attempt that generates no event; it shows a startup notice with the File ▸ Import fallback instead.

FreeBSD

Build File
x86_64 effectcraft-<ver>-freebsd-x86_64.tar.gz

Web (WebAssembly)

Build File Notes
Static site effectcraft-web-<ver>.zip Runs in a modern browser; host it on any static server

The Crafting Apps

EffectCraft 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 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
FigCraft Interface design and prototyping GitHub Website
WordCraft Word processing and documents GitHub Website
SoundCraft Audio recording and editing GitHub Website
DeckCraft Presentations and slide decks GitHub Website
CADCraft Computer-aided design GitHub Website
GridCraft Spreadsheets and data GitHub Website
TextureCraft 3D texture painting GitHub Website
Craft Anything See how any software works, then build your own GitHub Website
SolidCraft Parametric 3D CAD by Tangency Labs (community app) GitHub

And ArtCraft itself, our AI image and video studio for artists who want real control.


Join the ArtCraft community on Discord

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 · EffectCraft

License and credits

EffectCraft is dual-licensed under MIT or Apache-2.0, at your option. Copyright (c) 2026 ArtCraft Team and the EffectCraft 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.

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 EffectCraft, under docs/brand/LICENSE-brand.txt. Forks and modified versions must remove them.

ArtCraft
Made by the ArtCraft team and community.

Star history

Star History Chart

Languages
Rust 96.3%
WGSL 2.1%
JavaScript 1.2%
PowerShell 0.2%
Shell 0.1%