ArtCraft: 14 free creative apps, like Photoshop, Premiere, Word or AutoCAD

🌐 Español · English · Português · Français · Italiano · Deutsch · Nederlands · Polski · Русский · Українська · Türkçe · Ελληνικά · العربية · فارسی · עברית · हिन्दी · বাংলা · தமிழ் · Bahasa Indonesia · Tiếng Việt · ไทย · 中文 · 日本語 · 한국어 · Kiswahili

The story: one cancellation fee too many

The story going round forums and social media these weeks is that ArtCraft was born out of anger: its author “got scammed”. Behind the project is Brandon Thomas, a software engineer from Atlanta (USA) with fifteen years in the trade, who posted on Reddit as u/ai_art_is_art. “Scam” is the crowd’s word; what he says is that Adobe charged him its subscription cancellation fee.

“They charged me the ‘cancellation fee’ on multiple occasions and I’ve hated them ever since,” he wrote on Reddit. On Hacker News he said he had been caught by that “dark pattern” too many times: the penalty charged for leaving early an annual plan that is paid monthly. It is not an isolated complaint: in June 2024 the US Department of Justice sued Adobe for hiding those fees and making cancelling hard. Adobe maintains that its terms are transparent.

His answer was to rebuild the programs and give them away. With the help of Claude, Anthropic’s AI, and the Rust language, between late September and early October 2026 he published the first seven apps on GitHub — the equivalent of Photoshop, Illustrator, Premiere, Lightroom, After Effects, InDesign and Acrobat — and within a few weeks added Word, PowerPoint, Excel, AutoCAD, Pro Tools and Figma. He says they are “clean-room” reimplementations, built from the public specifications of the file formats, without anyone’s code.

The phrase he summed it up with, “software is over”, went round the world: if one person with AI can rebuild in weeks what took decades, paid software is in trouble. Some have doubts: Professor Andres Guadamuz of the University of Sussex points out that we do not yet know whether that “clean-room” process stands up to scrutiny, nor how much code he wrote and how much the AI did. Thomas insists it is not “a one-off flash in the pan that will die”, and for now the almost daily pace of releases proves him right.

ArtCraft is an open-source project (MIT or Apache-2.0 licence) by the storytold team that is rewriting, from scratch and in Rust, the tools we use every day to create. They are native, lightweight programs with no subscriptions, which mimic how the best-known commercial apps work without copying their code. They run on Windows, macOS, Linux and FreeBSD, many of them in the browser too, and new versions come out almost every week. The commercial names we mention are only a reference: these apps have no connection with those brands.

The tools, one by one

ArtCraft Launcher v0.8.1

Start here. It installs all the others: it shows the full catalogue, installs each app in one click choosing the right build for your computer, checks the download is not damaged and tells you when updates are out. There is no single package with everything, but this launcher is the closest thing.

PhotoCraft v0.16.0

The image editor, in the spirit of Photoshop: layers, selections, brushes, adjustments and retouching. It is the project’s most popular tool on GitHub.

LightCraft v0.14.0

A photo library and non-destructive RAW developer, Lightroom-style: organise your photos and adjust exposure, colour and cropping without ever touching the original file.

VectorCraft v0.17.0

Vector illustration as in Illustrator: curves, shapes, strokes and text that scale without losing quality. Good for logos, icons and posters.

FilmCraft v0.13.0

A non-linear video editor, similar to Premiere Pro: a multi-track timeline, cuts, colour correction and sound.

EffectCraft v0.17.0

Motion graphics, compositing and visual effects along the lines of After Effects: titles, keyframe animation and layers that blend together.

SoundCraft v0.13.1

An audio workstation to record, edit and mix, inspired by Pro Tools: multiple tracks, cuts, effects and the final mix.

DesignCraft v0.13.0

Page layout and publishing, InDesign-style: magazines, brochures and books with pages, columns, text styles and images.

FigCraft v0.11.2

Interface design and prototyping, like Figma: app and web screens, reusable components and mock-ups that show how something will work before it is built.

PdfCraft v0.14.0

For reading, organising and protecting PDFs, along the lines of Acrobat: open, annotate, reorder pages and save protected documents.

WordCraft v0.11.0

A word processor similar to Word, for letters, reports and documents with styles, tables and images.

DeckCraft v0.11.1

Presentations and slide shows, PowerPoint-style: slides with text, images and shapes to present full screen.

GridCraft v0.12.1

A spreadsheet like Excel: formulas, data tables, charts, and sorting or filtering information.

CADCraft v0.13.0

Computer-aided design and technical drawing, along the lines of AutoCAD: plans with exact measurements, layers and dimensions.

ArtCraft v0.41.0

The app the project is named after, and the only one that stands apart from the rest: a studio for creating images and video with artificial intelligence, made for artists, designers and filmmakers. For now on Windows and Mac only.

Keep them all: source code and executables

If you like to keep a copy of everything (in case a project disappears one day, or to install without Internet), this Linux script downloads the source code of each tool and every executable of its latest release, sorted into folders by tool and by system (Windows, macOS, Linux, FreeBSD and web). Unzip it and run it; the argument is the destination folder, and PLATFORMS and EXCLUDE choose what to download. (Its comments are in Spanish.)

⬇ Download the script (artcraft-mirror.zip)

chmod +x artcraft-mirror.sh
./artcraft-mirror.sh ~/artcraft

PLATFORMS="windows linux" EXCLUDE='riscv64|aarch64' ./artcraft-mirror.sh ~/artcraft
  • It can be interrupted: if it stops, run it again and it carries on where it left off.
  • It only fetches what is new: when a release comes out it creates its folder and leaves the older ones alone.
  • It verifies everything against the SHA-256 sums each release publishes.
  • It takes a lot of space: all platforms add up to about 24 GB per release; if you only need some, filter.
Show the full script
#!/usr/bin/env bash
# artcraft-mirror.sh — espejo local de las Craft Apps de ArtCraft (github.com/storytold)
#
# Estructura que genera:
#   <DEST>/<herramienta>/code/<rama>-<herramienta>-AAAAMMDD.zip   (+ .sha con el commit)
#   <DEST>/<herramienta>/release-<versión>/{windows,macos,linux,freebsd,web,otros}/...
#   <DEST>/<herramienta>/release-<versión>/SHA256SUMS.txt
#
# - Reanudable: las descargas van a *.part y continúan con Range (curl -C -).
#   Una release se da por terminada sólo cuando todo se verificó contra SHA256SUMS
#   (queda el marcador .complete). Si se corta, se vuelve a ejecutar y sigue.
# - Incremental: sólo mira la última release de cada herramienta; las carpetas
#   release-* anteriores y los zip de código de días anteriores no se tocan.
# - El código fuente se baja sólo si el commit de la rama principal cambió.
#
# Uso:
#   ./artcraft-mirror.sh [DEST]           (DEST por defecto: carpeta del script)
# Variables opcionales:
#   GITHUB_TOKEN=ghp_...                  sube el límite de la API de 60 a 5000 llamadas/h
#   PLATFORMS="windows linux macos"       sólo estas plataformas (por defecto todas)
#   EXCLUDE='riscv64|aarch64|flatpak'     regex de nombres de archivo a omitir
#   TOOLS="photocraft cadcraft"           sólo estas herramientas
#   EXTRA_TOOLS="anicraft"                añadir repos de storytold no incluidos en el catálogo
#   SKIP_CODE=1 / SKIP_RELEASES=1

set -uo pipefail

OWNER=storytold
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
DEST=${1:-$SCRIPT_DIR}
PLATFORMS=${PLATFORMS:-"windows macos linux freebsd web otros"}
EXCLUDE=${EXCLUDE:-}
TODAY=$(date +%Y%m%d)

# Catálogo de respaldo por si no se puede leer el del launcher
FALLBACK_TOOLS="photocraft vectorcraft filmcraft lightcraft pdfcraft effectcraft designcraft
figcraft wordcraft soundcraft deckcraft cadcraft gridcraft"
# Fuera del catálogo del launcher pero con releases propias
ALWAYS_TOOLS="craft-launcher artcraft"

for bin in curl jq git sha256sum flock; do
    command -v "$bin" >/dev/null || { echo "Falta '$bin'" >&2; exit 1; }
done

mkdir -p "$DEST"
exec 9>"$DEST/.artcraft-mirror.lock"
flock -n 9 || { echo "Ya hay otra ejecución en curso en $DEST" >&2; exit 1; }

log()  { printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*"; }
warn() { printf '[%s] AVISO: %s\n' "$(date +%H:%M:%S)" "$*" >&2; }

api() {
    local auth=()
    [[ -n ${GITHUB_TOKEN:-} ]] && auth=(-H "Authorization: Bearer $GITHUB_TOKEN")
    curl -fsSL --retry 3 -H "Accept: application/vnd.github+json" "${auth[@]}" \
        "https://api.github.com/$1"
}

# Descarga: $1 url, $2 destino final, $3 tamaño esperado.
# Con tamaño conocido continúa el .part (Range); sin él (zip de código, generado
# al vuelo y sin Range) empieza de cero.
fetch() {
    local url=$1 out=$2 size=${3:-} part="$2.part" have resume=()
    mkdir -p "$(dirname "$out")"
    if [[ -n $size && -f $part ]]; then
        have=$(stat -c %s "$part")
        if (( have == size )); then mv -f "$part" "$out"; return 0; fi
        if (( have > size )); then rm -f "$part"; fi
        resume=(-C -)
    else
        rm -f "$part"
    fi
    curl -fL --retry 5 --retry-delay 5 --retry-all-errors "${resume[@]}" \
        --progress-bar -o "$part" "$url" || return 1
    mv -f "$part" "$out"
}

platform_of() {
    case $1 in
        SHA256SUMS*)                              echo . ;;
        *windows*|*.msi|*.exe)                    echo windows ;;
        *macos*|*.dmg|*.app.tar.gz|*universal*)   echo macos ;;
        *freebsd*)                                echo freebsd ;;
        *linux*|*.AppImage*|*.deb|*.rpm|*.flatpak) echo linux ;;
        *-web-*)                                  echo web ;;
        *)                                        echo otros ;;
    esac
}

wanted() {
    local name=$1 plat=$2
    [[ $plat == . ]] && return 0
    [[ " $PLATFORMS " == *" $plat "* ]] || return 1
    [[ -n $EXCLUDE && $name =~ $EXCLUDE ]] && return 1
    return 0
}

tool_list() {
    if [[ -n ${TOOLS:-} ]]; then echo $TOOLS; return; fi
    local cat
    cat=$(curl -fsSL "https://raw.githubusercontent.com/$OWNER/craft-launcher/main/crates/core/src/catalog.rs" 2>/dev/null \
          | grep -oE "\"$OWNER/[a-z0-9-]+\"" | tr -d '"' | cut -d/ -f2 | grep -v '^craft-launcher$' | sort -u)
    [[ -z $cat ]] && { warn "no pude leer el catálogo del launcher; uso la lista interna"; cat=$FALLBACK_TOOLS; }
    echo $cat $ALWAYS_TOOLS ${EXTRA_TOOLS:-} | tr ' ' '\n' | awk 'NF && !seen[$0]++'
}

mirror_code() {
    local tool=$1 dir="$DEST/$1/code" head branch sha last
    head=$(git ls-remote --symref "https://github.com/$OWNER/$tool" HEAD 2>/dev/null) \
        || { warn "$tool: no pude consultar el repositorio"; return 1; }
    branch=$(awk '/^ref:/ {sub("refs/heads/","",$2); print $2}' <<<"$head")
    sha=$(awk '$2=="HEAD" && $1!="ref:" {print $1}' <<<"$head")
    mkdir -p "$dir"

    last=$(ls -1 "$dir"/*.zip.sha 2>/dev/null | sort | tail -1)
    if [[ -n $last && $(<"$last") == "$sha" ]]; then
        log "$tool: código al día ($branch@${sha:0:8})"
        return 0
    fi
    local zip="$dir/$branch-$tool-$TODAY.zip"
    log "$tool: bajando código $branch@${sha:0:8} → $(basename "$zip")"
    # El zip por commit garantiza que el archivo corresponde al sha anotado
    fetch "https://github.com/$OWNER/$tool/archive/$sha.zip" "$zip" || { warn "$tool: falló el zip"; return 1; }
    echo "$sha" > "$zip.sha"
}

verify() { # $1 archivo, $2 SHA256SUMS → 0 ok / 1 mal / 2 sin suma publicada
    local file=$1 sums=$2 expected
    [[ -f $sums ]] || return 2
    expected=$(awk -v n="$(basename "$file")" '{f=$2; sub(/^\*/,"",f)} f==n {print $1}' "$sums")
    [[ -z $expected ]] && return 2
    [[ $(sha256sum "$file" | cut -d' ' -f1) == "$expected" ]]
}

mirror_release() {
    local tool=$1 json tag ver rdir
    json=$(api "repos/$OWNER/$tool/releases/latest") || { warn "$tool: sin releases o límite de API alcanzado"; return 1; }
    tag=$(jq -r .tag_name <<<"$json")
    ver=${tag#"$tool"-}; ver=${ver#v}
    rdir="$DEST/$tool/release-$ver"

    if [[ -f $rdir/.complete && $(<"$rdir/.complete") == "$PLATFORMS|$EXCLUDE" ]]; then
        log "$tool: release $ver ya completa"
        return 0
    fi
    log "$tool: release $ver"
    mkdir -p "$rdir"
    jq -c '{tag_name, name, published_at, html_url, body}' <<<"$json" > "$rdir/release.json"

    local ok=1 name url size plat out sums="$rdir/SHA256SUMS.txt"
    # SHA256SUMS primero para poder verificar el resto
    while IFS=$'\t' read -r name url size; do
        plat=$(platform_of "$name")
        wanted "$name" "$plat" || continue
        if [[ $plat == . ]]; then out="$rdir/$name"; else out="$rdir/$plat/$name"; fi

        if [[ -f $out ]]; then
            verify "$out" "$sums"; case $? in
                0) continue ;;
                2) [[ $(stat -c %s "$out") == "$size" ]] && continue ;;
            esac
            warn "$tool: $name no coincide, se vuelve a bajar"; rm -f "$out"
        fi
        log "  ↓ ${out#"$rdir"/} ($((size / 1048576)) MiB)"
        if ! fetch "$url" "$out" "$size"; then warn "  falló $name"; ok=0; continue; fi
        verify "$out" "$sums"; case $? in
            1) warn "  checksum INCORRECTO: $name (se borra)"; rm -f "$out"; ok=0 ;;
            2) [[ $name != SHA256SUMS* ]] && [[ $(stat -c %s "$out") != "$size" ]] && { warn "  tamaño incorrecto: $name"; rm -f "$out"; ok=0; } ;;
        esac
    done < <(jq -r '.assets | sort_by(.name | startswith("SHA256SUMS") | not)[]
                    | [.name, .browser_download_url, .size] | @tsv' <<<"$json")

    if (( ok )); then echo "$PLATFORMS|$EXCLUDE" > "$rdir/.complete"; log "$tool: release $ver completa ✔"
    else warn "$tool: release $ver incompleta; vuelve a ejecutar el script para continuar"; return 1; fi
}

fail=0
for tool in $(tool_list); do
    echo "──────── $tool"
    [[ -z ${SKIP_CODE:-} ]]     && { mirror_code "$tool"    || fail=1; }
    [[ -z ${SKIP_RELEASES:-} ]] && { mirror_release "$tool" || fail=1; }
done

(( fail )) && { warn "Hubo errores; ejecuta de nuevo para reintentar lo pendiente."; exit 1; }
log "Todo al día en $DEST"

These are very young programs, nearly all marked early alpha: they promise a lot, but they do not yet replace professional tools for serious work. Try them, keep copies of your files and, if you find a bug, report it on their GitHub.

References