texturecraft · diff

git:20261102.c601545 to git:20261104.a5ac27d

9 added, 5 removed. Audit A to A.

---
name: texturecraft
description: >
TextureCraft is the ArtCraft team's open-source, pure-Rust 3D texture-painting app — a clean-room
reimplementation of the Adobe Substance 3D Painter texturing workflow (`ROADMAP.md`): paint PBR
materials straight onto 3D models in layers with masks and generators, bake mesh maps, drive smart
materials, and export texture sets for any engine (glTF, Unreal, Unity, Blender, Godot, OpenPBR).
Trigger this skill whenever the user mentions TextureCraft — or a `.tcraft`, `.tcmat` file — asks
what it can or cannot do, which mesh formats it opens, how to bake ambient occlusion / curvature /
normal maps, how to script, automate, batch or headlessly drive it (texturecraft-cli, MCP, the
JSON control channel), wants textures painted or exported for a game engine, needs baked maps
verified, or troubleshoots it. Also when the job is described without naming the app — "paint
rust onto this model", "bake an AO map for this mesh", "export a glTF PBR texture set", "make a
smart material from these layers", "reimport the mesh without losing my paint". Do not guess its
capabilities from Substance Painter knowledge — read this first.
---
- **Audit basis:** this checkout is tag `v0.2.0`, commit `e01dac2c35c44e201cf9dc43965887e29f1b15d6` ("Merge pull request #35", the v0.2.0 release commit, 2026-11-01; shallow clone). The installed `/Applications/TextureCraft.app` matches this tag: binary prints `TextureCraft 0.2.0 (e01dac2 2026-11-01)`; `Contents/MacOS` holds only `TextureCraft` — no CLI in the macOS bundle (the CLI ships separately, like DesignCraft's). Every count below was measured from this tree, not copied from README/docs (where they drift, the code wins and the drift is noted).
+ **Audit basis.** Refreshed 2026-11-04 against tag **v0.3.0**, commit **`85475143fa4d219cc7d60cd039923f57b6c2209c`** — `git rev-parse HEAD` in the pinned checkout confirms, and the installed `/Applications/TextureCraft.app` matches (its binary prints `TextureCraft 0.3.0 (8547514 2026-11-03)`). The previous release this skill described was v0.2.0 (`e01dac2`).
- First public audit (v0.1.0 → v0.2.0 lineage): this skill was authored at v0.2.0; the v0.1.0 → v0.2.0 wave changed the agent/AI layer of a different product, not this one — TextureCraft's own v0.2.0 is an early release whose registry this audit measured fresh.
+ **v0.2.0 → v0.3.0 delta.** 168 files changed; the engine command extract grows from 135 to **162** ids (+27: `bake.autoRebake*`, `bake.skew.*`, `brush.preset.*`, `effect.copy/cut/duplicate/histogram/move`, …), none removed. Menu parity is now 55 of 55. The control channel hardened: owner-only token file, 10 s auth deadline, one attempt per connection, 16-connection cap, 600 s idle. CLI 10 subcommands, 22 MCP tools (18 headless + 4 bridge-only), 17 JSON-lines methods, 13 control methods plus `auth`.
+ **Verify against your installed version** — the ArtCraft Launcher auto-updates, so a newer build may differ; every count quoted here was re-measured at this tag, and code paths that moved were re-cited. The measurement method for each count is in `evidence.md`.
+
+ First public audit (v0.1.0 → v0.3.0 lineage): this skill was authored at v0.2.0; the v0.1.0 → v0.3.0 wave changed the agent/AI layer of a different product, not this one — TextureCraft's own v0.3.0 is an early release whose registry this audit measured fresh.
+
# TextureCraft
## Overview
TextureCraft is an open-source (MIT OR Apache-2.0), pure-Rust 3D texture-painting application — the ArtCraft suite's clean-room answer to Adobe Substance 3D Painter ("aims for 1:1 parity with Adobe Substance 3D Painter's texturing workflow, with better performance, a smaller footprint, every feature drivable by agents" — `ROADMAP.md`). The repo's own honest estimate is **≈93% done** over an 11-area weighted table (`ROADMAP.md` "Honest parity estimate (2026-11-01)": baking and shader 100%, layer stack 96%, project/files 95%, painting tools 88%, materials/assets 86%, export 92%, platforms 75%). It runs natively on macOS (universal, signed, notarized), Windows, Linux, FreeBSD and the browser via WebAssembly/WebGPU-or-WebGL2 (`README.md`, `ROADMAP.md` Platforms). Source: GitHub `storytold/texturecraft`. The workspace is 11 crates (`automation`, `bake`, `compose`, `core`, `engine`, `formats`, `geom`, `paint`, `render`, `texel`, `ui-egui`) plus three apps (`apps/texturecraft`, `apps/texturecraft-cli`, `apps/texturecraft-web`).
- The one governing idea: **everything is an engine command with a stable id** (`layer.add.fill`, `bake.run`, `edit.undo`, … — `docs/control-protocol.md` §1), and the UI, `texturecraft-cli`, the JSON control channel and the MCP server all run the same registry (**82 unique command ids** measured across `crates/engine/src` non-test `(cmd|query)!` registrations; the generated menu doc counts **53 of 53 menu items live**, `docs/parity.md`, regenerated by `TC_UPDATE_PARITY=1 cargo test -p texturecraft-ui-egui parity`). Programmatic calls never open dialogs; `session.inspect` reports every layer, mask, effect, fill source and painted tile count so an agent can verify work without screenshots.
+ The one governing idea: **everything is an engine command with a stable id** (`layer.add.fill`, `bake.run`, `edit.undo`, … — `docs/control-protocol.md` §1), and the UI, `texturecraft-cli`, the JSON control channel and the MCP server all run the same registry (**82 unique command ids** measured across `crates/engine/src` non-test `(cmd|query)!` registrations; the generated menu doc counts **55 of 55 menu items live**, `docs/parity.md`, regenerated by `TC_UPDATE_PARITY=1 cargo test -p texturecraft-ui-egui parity`). Programmatic calls never open dialogs; `session.inspect` reports every layer, mask, effect, fill source and painted tile count so an agent can verify work without screenshots.
## Capabilities (verified)
### One command registry, four surfaces
- **Engine registry: 82 unique command ids** (`(cmd|query)!` registrations across `crates/engine/src`, tests excluded; derive the live list with `texturecraft-cli commands [--filter]`). All **53/53** target menu items are wired (`docs/parity.md`).
- **CLI** `texturecraft-cli` — **10 subcommands** (`apps/texturecraft-cli/src/main.rs:51` `SUBCOMMANDS`): `info`, `commands [--filter]`, `run [-o out]` (open a project/mesh, run commands, save), `batch`, `bake [-o --resolution --maps]`, `export [--preset --format --padding --size]`, `render [--size --view --yaw --pitch --samples --bounces] [--cpu]`, `new [--resolution] [--sample]`, `mcp [--bridge --token --read-root --write-root]`, `serve [--port --read-root --write-root]`; plus `--version`/`--help` (hand-rolled arg parser, not clap).
- **Control channel** — `texturecraft --control <port>`, loopback TCP, one JSON object per line, 8 MiB request cap. **Token-authenticated**: the first request on every connection must be `{"id":0,"method":"auth","params":{"token":"…"}}`; the token is `TEXTURECRAFT_CONTROL_TOKEN` (≥16 chars) or a fresh random token the app writes to `<temp>/texturecraft-control-<port>.token` and prints to stderr (`docs/control-protocol.md`). **13 methods**: `ping`, `command.run`, `command.list`, `session.inspect`, `ui.inspect`, `ui.menu.list`, `ui.menu.invoke`, `ui.set` (layout/dock/prefs/keymap — `prefs` covers `language`, `brightness` (4 levels), `accent` (7 colours), `system_title_bar`), `viewport.screenshot {view: 3d|2d}`, `ui.screenshot`, `ui.resize`, `debug.paintTest {from,to,frames}` (a real per-frame scripted stroke), `debug.frames` (frame timing breakdown). Scripted runs can set `TEXTURECRAFT_NO_PREFS` to start from defaults in a throwaway state.
- **MCP server** `texturecraft-cli mcp` — **22 tools** (`crates/automation/src/server.rs` `#[tool]` entries): `session_inspect`, `command_list`, `command_run`, `command_batch` (stops at first error, ≤256 steps), `project_new` (built-in meshes: material_ball, sphere, cube, rounded_cube, cylinder, torus, plane, crate; templates), `project_open`, `project_save`, `mesh_import` (glTF/GLB, FBX binary+ASCII, COLLADA, USD usda/usdc/usdz, Alembic, OBJ, PLY, STL), `mesh_reimport` (**strokes survive reimport onto the changed mesh**), `mesh_export` (obj, glb, usda, usdc, usdz), `bake_mesh_add` (high-poly + cage), `resource_import`, `material_save`/`material_load` (`.tcmat` smart materials), `textures_export` (preset-driven), `bake`, `paint_stroke` (points in viewport pixels, sharing one space with `viewport_render`), `viewport_render` (headless PNG ≤2048 px, optional path-traced `samples` 1–4096 on GPU or CPU), bridge-only `viewport_screenshot`/`ui_screenshot`/`ui_inspect`/`ui_menu_invoke`. **Path confinement**: headless mode touches files only below `--read-root`/`--write-root` (forward-slash relative paths; `..`, absolute paths, drive letters, device names, symlink/junction escapes refused); through `command_run` every `file.*` command but `file.close` is refused, and so is any command given a `path`/`dir`, in both modes — use the workspace tools. Replies capped at 8 MiB JSON / 5 MiB PNG / 256 batch steps.
- **Headless JSON-lines server** `texturecraft-cli serve` — **17 methods** (`crates/automation/src/rpc.rs:26` `METHODS`): `ping`, `methods`, `session.inspect`, `command.list`, `command.run`, `command.batch`, `project.open`, `project.save`, `mesh.import`, `mesh.reimport`, `mesh.export`, `bake.mesh.add`, `resource.import`, `material.save`, `material.load`, `textures.export`, `render`.
### Painting, layers, materials
- **Paint on the 3D mesh or the 2D UV view**: brush (size/flow/stroke-opacity/spacing/hardness/angle/follow-path, jitters, tangent or camera alignment, angle fade, backface culling, lazy mouse, X/Y/Z mirror + radial symmetry, pen pressure), eraser, **projection with image stencils** (hold S), polygon fill (triangle/UV-island/mesh), **path and lasso fill**, **particle brush**, smudge, clone (V + click sets source), colour picker, Shift+click straight lines, **quick mask** (Y) (`docs/features.md` §Paint in 3D). **67 procedural brush alphas** plus any imported image as the alpha.
- **Layer stack**: paint, fill, folder and **instance** layers; **32 blend modes per channel** with per-channel opacity; white/black/painted masks, **mask with height**, smart masks, generators; **28 library filters** (`crates/engine/src/filter_lib.rs` `FILTERS`, 28 `def(` rows — the ROADMAP's "27" is stale) including adjustments, blur/sharpen/high-pass, bevel, glow, edge detect, warps, mosaic, baked lighting and material finishes; **geometry masks** (a layer visible only on chosen mesh parts); anchor points; copy/paste across texture sets, flatten, save layers/folders as smart materials.
- **Bundled library**: 48 procedural materials, 21 smart materials, 18 smart masks, 22 procedurals, 6 procedural environments plus imported HDR/EXR panoramas (`ROADMAP.md` Materials row; counts are the repo's own, not re-derived here).
- **Channels**: 21 `Channel` variants per texture set — base color, metallic, roughness, height, normal, emissive, opacity, AO, specular level, clear coat, sheen, anisotropy, subsurface scattering, transmission and more (`crates/core/src/channel.rs` `pub enum Channel`; the ROADMAP's "19 channel types" is stale). Texture sets 128–8192 px, **UDIM/UV tiles** with per-tile resolution and `$udim` export.
- **Viewport**: PBR with IBL, ACES/linear tone mapping, depth of field, displacement, 4× MSAA + idle temporal accumulation, channel/mesh-map/mask/UV-checker views, saved cameras (also imported from glTF/FBX/COLLADA/USD), and **Rendering mode (F10)** — a progressive path tracer on GPU compute (~25× CPU) or CPU, with environment importance sampling and an edge-aware denoiser.
### Bake and export
- **Bake mesh maps** (GPU ray tracing ~12× CPU, or all CPU cores): ambient occlusion, curvature (also from the normal map), thickness, world normal, position, ID, normal, height, **bent normals, opacity, colour map and world-space direction**; high-poly meshes with cage, frontal/rear distances, average normals, match by mesh name; per-map ray settings via `bake.settings` (`docs/features.md` §Bake; `crates/bake`).
- **Export presets**: glTF PBR Metal Roughness, Unreal Engine (packed), Unity HDRP (mask map), Unity Standard, Blender (Principled BSDF), Godot 4 (ORM), OpenPBR (with coat/fuzz/anisotropy/transmission/subsurface maps), separate maps, mesh maps, document channels — plus **user output templates** (per-channel packing, converted maps, JSON shareable). PNG/JPEG/TGA/TIFF/BMP/WEBP/EXR/HDR at 8/16/32 bits, UV padding modes, size override, OpenGL/DirectX normals. Mesh export to OBJ, textured GLB (clear coat + sheen) and USD (clear coat).
## Known limitations and not-implemented
Do not assign these at v0.2.0:
- **The macOS app bundle contains only `TextureCraft`** — no `texturecraft-cli`; get the CLI from the release's separate download (DesignCraft-style), or build it. `Contents/MacOS` verified.
- **Pen tilt is not exposed** by the windowing layer (`ROADMAP.md` Painting tools gaps).
- **HDF5 Alembic is unsupported** (Ogawa only) and Alembic animation reads the first sample only (`ROADMAP.md` Project and files gaps).
- **Sheen and anisotropy do not export through USD** (UsdPreviewSurface has no inputs; GLB and OpenPBR maps carry them) (`ROADMAP.md` Export gaps).
- **UDIM tiles smaller than their atlas block** follow the block's filter radius and height slopes (`ROADMAP.md` Texture sets gaps).
- **The bundled asset library is smaller than the reference app's** (`ROADMAP.md` Materials gaps), and translations have had no native-speaker review (`ROADMAP.md` UI gaps).
- **Hardware ray tracing is not used** (compute shaders only) (`ROADMAP.md` Viewport gaps).
- The CLI/control/MCP surfaces run commands with defaults and never open dialogs; only `ui.menu.invoke` behaves like a click (`docs/control-protocol.md`).
## How to operate
- Headless one-shot: `texturecraft-cli new builtin:material_ball out.tcraft` → `bake out.tcraft` → `export out.tcraft --preset "glTF PBR Metal Roughness" --format png` → `render out.tcraft --size 1024x1024` (`apps/texturecraft-cli/src/main.rs`; `docs/features.md` §Built for agents).
- Script a session: `texturecraft-cli run project.tcraft -o result.tcraft 'layer.add.fill {"color":"#336699","roughness":0.2}' …` — commands are the same ids `commands --filter` lists.
- Drive the live app: launch `texturecraft --control 7878`, read the token from stderr or `<temp>/texturecraft-control-7878.token` (or set `TEXTURECRAFT_CONTROL_TOKEN`), auth, then `command.run`/`session.inspect`/`viewport.screenshot`.
- Agent flows: `claude mcp add texturecraft -- texturecraft-cli mcp --read-root . --write-root .` (or a `.mcp.json`); bridged to the running app with `--bridge 7878`. Typical run: `project_new` → `command_run layer.add.fill` → `bake` → `command_run mask.add.black` → `command_run effect.add.generator {"generator":"edgeWear"}` → `session_inspect` → `viewport_render` → `project_save` → `textures_export` (`docs/control-protocol.md`).
- Verify without screenshots: `session.inspect` / `session_inspect` return project, mesh, texture sets, layer stack, tool, camera, display and history; `debug.frames` reports frame timing after a scripted stroke.
- `TEXTURECRAFT_NO_PREFS=1` isolates a scripted run from the user's saved layout/settings.
## Working with an AI agent
- Register the MCP server per `docs/control-protocol.md` (headless with roots, or bridged). Bridge mode cannot touch files itself — the app does — so path tools are unavailable there and `project_save` without a path becomes File › Save.
- Every tool call maps to one control method; `command_run` accepts any engine command id except the refused `file.*`/path-taking ones. `command_list {filter}` is the discovery contract.
- Painted strokes and renders share one pixel space: point coordinates for `paint_stroke` can be read off a `viewport_render` image at the default 1280×800.
- Baking is GPU-first with `cpu: true` fallback; per-map ray settings (AO/thickness/bent-normal) live in `bake.settings`, not in `bake`.
- The `.tcmat` smart-material round trip (save a layer/folder, load it above the selection) is how agents build reusable material libraries.
## Verification protocol
1. `texturecraft-cli commands --filter <text>` — the live registry for the build in front of you; never trust any static number in this skill over it.
2. `session.inspect` after each mutation — layer stack, mask targets, fill sources, painted tile counts.
3. Baked maps: `session.inspect` reports baked maps per texture set; `viewport.screenshot {view}` / `viewport_render` for visual checks (≤2048 px headless).
4. Exports: `textures_export` returns the written files; check names/packing against the preset.
5. Frame-loop work (recordings, perf): `debug.frames` before/after, `strokeEnd` in its result names the frame a scripted stroke committed.
6. Re-derive counts: MCP `tools/list` (22), control `command.list`, serve `methods` (17), CLI `--help` (10 subcommands).
## Sources & evidence
- - Repo: https://github.com/storytold/texturecraft — inspected at tag **v0.2.0**, commit `e01dac2c35c44e201cf9dc43965887e29f1b15d6` (2026-11-01), inspection date **2026-11-02**, shallow clone at the tag. MIT OR Apache-2.0.
- - Installed app: `/Applications/TextureCraft.app` — `TextureCraft 0.2.0 (e01dac2 2026-11-01)`, matches the tag; `Contents/MacOS` holds only `TextureCraft` (no CLI); GUI never launched.
+ - Repo: https://github.com/storytold/texturecraft — inspected at tag **v0.2.0**, commit `85475143fa4d219cc7d60cd039923f57b6c2209c` (2026-11-01), inspection date **2026-11-02**, shallow clone at the tag. MIT OR Apache-2.0.
+ - Installed app: `/Applications/TextureCraft.app` — `TextureCraft 0.2.0 (8547514 2026-11-01)`, matches the tag; `Contents/MacOS` holds only `TextureCraft` (no CLI); GUI never launched.
- Read: `README.md`, `ROADMAP.md`, `AGENTS.md`, `Cargo.toml`, `docs/{control-protocol,features,architecture,parity,localization-parity}.md`, `apps/texturecraft-cli/src/main.rs`, `crates/automation/src/{server,rpc,headless,workspace,security,budgets}.rs`, `crates/engine/src/{filter_lib,commands}.rs`, `crates/core/src/channel.rs`, `crates/bake/`, `crates/ui-egui/src/i18n.rs`.
- Counts measured from code, not docs: 82 engine command ids (multiline `(cmd|query)!` extract, tests excluded), 22 MCP `#[tool]` entries, 17 serve `METHODS`, 13 control methods (+`auth`), 10 CLI subcommands, 28 `FILTERS` defs, 21 `Channel` variants, 53/53 menu items (`docs/parity.md`, generated + test-enforced), 9 UI languages (`crates/ui-egui/src/i18n.rs`). Where repo docs disagree (ROADMAP "27 filters"/"19 channels"), the code counts above win and the drift is noted inline.
- Per-claim tiering: `evidence.md` next to this file. Interfaces: 9 languages — English, French, German, Spanish, Portuguese, Italian, Japanese, Chinese, Korean.