diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ae2f93fb..7f2730a3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -78,7 +78,7 @@ jobs:
- name: CLI without the MCP server still builds
if: runner.os == 'Linux'
- run: cargo check -p printcraft-cli --no-default-features
+ run: cargo check -p pdfcraft-cli --no-default-features
wasm:
name: wasm32 check
diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml
index 4c9849b0..a86fc140 100644
--- a/.github/workflows/freebsd.yml
+++ b/.github/workflows/freebsd.yml
@@ -49,4 +49,4 @@ jobs:
CARGO_PROFILE_DEV_DEBUG=0 cargo test --workspace --locked
# The release packaging, end to end (a quicker release profile than the real release).
CARGO_PROFILE_RELEASE_LTO=false CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16 packaging/freebsd/package.sh
- tar -tzf dist/release/printcraft-*-freebsd-*.tar.gz | grep -E '/bin/printcraft$|/bin/printcraft-cli$|applications/'
+ tar -tzf dist/release/pdfcraft-*-freebsd-*.tar.gz | grep -E '/bin/pdfcraft$|/bin/pdfcraft-cli$|applications/'
diff --git a/.github/workflows/packaging-lint.yml b/.github/workflows/packaging-lint.yml
index 29817c7e..39adb8d5 100644
--- a/.github/workflows/packaging-lint.yml
+++ b/.github/workflows/packaging-lint.yml
@@ -46,12 +46,12 @@ jobs:
}
- name: XML, desktop entry, AppStream, Flatpak manifest
run: |
- xmllint --noout packaging/windows/printcraft.wxs packaging/macos/*.plist* packaging/linux/*.xml*
+ xmllint --noout packaging/windows/pdfcraft.wxs packaging/macos/*.plist* packaging/linux/*.xml*
# Windows Installer needs Icon ids ending in .ico or .exe, or shortcuts show a blank icon (#57).
- if grep -oE '"$RUNNER_TEMP/ai.storyteller.printcraft.metainfo.xml"
- appstreamcli validate --no-net --explain "$RUNNER_TEMP/ai.storyteller.printcraft.metainfo.xml"
- python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.printcraft.yml')); assert m['id'] == 'ai.storyteller.printcraft' and m['command'] == 'printcraft'"
+ desktop-file-validate packaging/linux/ai.storyteller.pdfcraft.desktop
+ sed -e 's/@VERSION@/0.0.0/' -e 's/@DATE@/2026-01-01/' packaging/linux/ai.storyteller.pdfcraft.metainfo.xml.in >"$RUNNER_TEMP/ai.storyteller.pdfcraft.metainfo.xml"
+ appstreamcli validate --no-net --explain "$RUNNER_TEMP/ai.storyteller.pdfcraft.metainfo.xml"
+ python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.pdfcraft.yml')); assert m['id'] == 'ai.storyteller.pdfcraft' and m['command'] == 'pdfcraft'"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7533b7c6..7e709422 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,5 +1,5 @@
# Release pipeline: every push to `release` builds signed installers for every platform and
-# creates or updates the draft GitHub Release "PrintCraft v". See docs/releasing.md.
+# creates or updates the draft GitHub Release "PdfCraft v". See docs/releasing.md.
#
# All jobs run in the `release` environment (restricted to the `release` branch), which holds
# the signing secrets. Every secret is optional: missing ones produce unsigned artifacts and a
@@ -28,7 +28,7 @@ env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
RUST_BACKTRACE: 1
- PRINTCRAFT_BUILD_SHA: ${{ github.sha }}
+ PDFCRAFT_BUILD_SHA: ${{ github.sha }}
INPUT_VERSION: ${{ inputs.version }}
jobs:
@@ -58,7 +58,7 @@ jobs:
echo "date=$(date -u +%Y-%m-%d)"
echo "prerelease=$pre"
} >>"$GITHUB_OUTPUT"
- echo "### PrintCraft v$v (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY"
+ echo "### PdfCraft v$v (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY"
macos:
name: macOS universal
@@ -66,8 +66,8 @@ jobs:
runs-on: macos-15
environment: release
env:
- PRINTCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PRINTCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
+ PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
+ PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
steps:
- uses: actions/checkout@v4
# The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
@@ -85,7 +85,7 @@ jobs:
key: release-macos-universal
- name: Apply version override
if: inputs.version != ''
- run: cargo xtask version set "$PRINTCRAFT_VERSION"
+ run: cargo xtask version set "$PDFCRAFT_VERSION"
- name: Import signing certificate
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
@@ -125,8 +125,8 @@ jobs:
# .github/workflows/windows-arm64.yml installs and runs it on ARM64 hardware.
- { arch: arm64, target: aarch64-pc-windows-msvc }
env:
- PRINTCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PRINTCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
+ PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
+ PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
steps:
- uses: actions/checkout@v4
# The craft-fonts build input (Japanese fonts): every release embeds it. Bump deliberately.
@@ -145,7 +145,7 @@ jobs:
- name: Apply version override
if: inputs.version != ''
shell: bash
- run: cargo xtask version set "$PRINTCRAFT_VERSION"
+ run: cargo xtask version set "$PDFCRAFT_VERSION"
- name: Install WiX
shell: pwsh
run: dotnet tool install --global wix --version 5.0.2
@@ -183,8 +183,8 @@ jobs:
- { arch: x86_64, runner: ubuntu-22.04, deb: amd64 }
- { arch: aarch64, runner: ubuntu-22.04-arm, deb: arm64 }
env:
- PRINTCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PRINTCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
+ PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
+ PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
NFPM_VERSION: 2.47.0
steps:
- uses: actions/checkout@v4
@@ -210,7 +210,7 @@ jobs:
key: release-linux-${{ matrix.arch }}
- name: Apply version override
if: inputs.version != ''
- run: cargo xtask version set "$PRINTCRAFT_VERSION"
+ run: cargo xtask version set "$PDFCRAFT_VERSION"
- name: Build and package (AppImage, deb, rpm, tar.gz)
env:
CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
@@ -219,9 +219,9 @@ jobs:
- name: Check the packages
run: |
dpkg-deb --info dist/release/*.deb
- dpkg-deb --contents dist/release/*.deb | grep -E 'usr/bin/printcraft$|metainfo|applications'
- ldd target/release/printcraft
- python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.printcraft.yml')); assert m['id'] == 'ai.storyteller.printcraft'"
+ dpkg-deb --contents dist/release/*.deb | grep -E 'usr/bin/pdfcraft$|metainfo|applications'
+ ldd target/release/pdfcraft
+ python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.pdfcraft.yml')); assert m['id'] == 'ai.storyteller.pdfcraft'"
for appimage in dist/release/*.AppImage; do
chmod +x "$appimage"
APPIMAGE_EXTRACT_AND_RUN=1 "$appimage" --version
@@ -240,8 +240,8 @@ jobs:
environment: release
timeout-minutes: 180
env:
- PRINTCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PRINTCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
+ PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
+ PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
VERSION_OVERRIDE: ${{ inputs.version }}
steps:
- uses: actions/checkout@v4
@@ -260,7 +260,7 @@ jobs:
usesh: true
cpu: 4
mem: 12288
- envs: "PRINTCRAFT_VERSION PRINTCRAFT_BUILD_DATE VERSION_OVERRIDE"
+ envs: "PDFCRAFT_VERSION PDFCRAFT_BUILD_DATE VERSION_OVERRIDE"
# The same packages as the FreeBSD CI workflow, plus bash for the packaging script.
prepare: |
pkg install -y bash git curl pkgconf cmake python3 libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader gtk3 fontconfig freetype2 alsa-lib
@@ -270,7 +270,7 @@ jobs:
. "$HOME/.cargo/env"
git config --global --add safe.directory "$PWD"
export CRAFT_FONTS_DIR="$PWD/craft-fonts" CRAFT_FONTS_REQUIRED=1
- if [ -n "$VERSION_OVERRIDE" ]; then cargo xtask version set "$PRINTCRAFT_VERSION"; fi
+ if [ -n "$VERSION_OVERRIDE" ]; then cargo xtask version set "$PDFCRAFT_VERSION"; fi
packaging/freebsd/package.sh
# Only dist/ comes back out of the VM: copying the target dir back fails on large builds.
rm -rf target
@@ -286,8 +286,8 @@ jobs:
runs-on: ubuntu-latest
environment: release
env:
- PRINTCRAFT_VERSION: ${{ needs.version.outputs.version }}
- PRINTCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
+ PDFCRAFT_VERSION: ${{ needs.version.outputs.version }}
+ PDFCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
TRUNK_VERSION: 0.21.14
steps:
- uses: actions/checkout@v4
@@ -311,7 +311,7 @@ jobs:
trunk --version
- name: Apply version override
if: inputs.version != ''
- run: cargo xtask version set "$PRINTCRAFT_VERSION"
+ run: cargo xtask version set "$PDFCRAFT_VERSION"
- name: Build and zip
env:
CRAFT_FONTS_DIR: ${{ github.workspace }}/craft-fonts
@@ -349,7 +349,7 @@ jobs:
working-directory: artifacts
run: |
tag="v$VERSION"
- title="PrintCraft v$VERSION"
+ title="PdfCraft v$VERSION"
pre=()
if [ "$PRERELEASE" = true ]; then pre=(--prerelease); fi
if draft="$(gh release view "$tag" --json isDraft --jq .isDraft 2>/dev/null)"; then
diff --git a/.github/workflows/windows-arm64.yml b/.github/workflows/windows-arm64.yml
index bb05a3eb..d831ffc5 100644
--- a/.github/workflows/windows-arm64.yml
+++ b/.github/workflows/windows-arm64.yml
@@ -53,7 +53,7 @@ jobs:
run: ./packaging/windows/package.ps1 -Arch arm64
- uses: actions/upload-artifact@v4
with:
- name: printcraft-windows-arm64
+ name: pdfcraft-windows-arm64
path: dist/arm64/*
if-no-files-found: error
retention-days: 7
@@ -66,7 +66,7 @@ jobs:
steps:
- uses: actions/download-artifact@v4
with:
- name: printcraft-windows-arm64
+ name: pdfcraft-windows-arm64
path: dist
- name: Install the MSI, check it, run it, uninstall it
shell: pwsh
@@ -75,8 +75,8 @@ jobs:
$msi = (Get-ChildItem dist/*.msi | Select-Object -First 1).FullName
$p = Start-Process msiexec.exe -ArgumentList '/i', "`"$msi`"", '/qn', '/l*v', 'install.log' -Wait -PassThru
if ($p.ExitCode -ne 0) { Get-Content install.log -Tail 60; throw "msiexec /i exited $($p.ExitCode)" }
- $dir = Join-Path $env:ProgramFiles 'PrintCraft'
- foreach ($exe in 'printcraft.exe', 'printcraft-cli.exe') {
+ $dir = Join-Path $env:ProgramFiles 'PdfCraft'
+ foreach ($exe in 'pdfcraft.exe', 'pdfcraft-cli.exe') {
$path = Join-Path $dir $exe
if (-not (Test-Path $path)) { Get-ChildItem -Recurse $env:ProgramFiles -Filter $exe | Select-Object -First 3; throw "$exe not installed in $dir" }
$bytes = [System.IO.File]::ReadAllBytes($path)
@@ -85,9 +85,9 @@ jobs:
Write-Output "ok $path (ARM64)"
}
# The installed CLI runs natively: open, render and edit a small PDF through the engine.
- $cli = Join-Path $dir 'printcraft-cli.exe'
+ $cli = Join-Path $dir 'pdfcraft-cli.exe'
& $cli tools | Out-Null
- if ($LASTEXITCODE -ne 0) { throw "printcraft-cli tools exited $LASTEXITCODE" }
+ if ($LASTEXITCODE -ne 0) { throw "pdfcraft-cli tools exited $LASTEXITCODE" }
$body = 'BT /F1 24 Tf 20 150 Td (Hello ARM64) Tj ET'
$objs = @('<< /Type /Catalog /Pages 2 0 R >>', '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
'<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>',
@@ -103,13 +103,13 @@ jobs:
$steps = '[{"tool":"doc_open","args":{"path":"hello.pdf"}},{"tool":"text_paragraphs","args":{"doc":1,"page":1}},{"tool":"text_edit","args":{"doc":1,"page":1,"paragraph":1,"text":"Edited on ARM64"}},{"tool":"page_render","args":{"doc":1,"page":1,"dpi":72},"out":"smoke/page.png"},{"tool":"doc_save","args":{"doc":1,"path":"out.pdf"}}]'
[System.IO.File]::WriteAllText("$PWD\smoke\steps.json", $steps)
$out = & $cli run --script smoke\steps.json --root smoke 2>&1 | Out-String
- if ($LASTEXITCODE -ne 0) { Write-Output $out; throw "printcraft-cli run exited $LASTEXITCODE" }
+ if ($LASTEXITCODE -ne 0) { Write-Output $out; throw "pdfcraft-cli run exited $LASTEXITCODE" }
if ($out -notmatch 'Hello ARM64') { Write-Output $out; throw 'text_paragraphs did not read the page' }
foreach ($f in 'smoke\page.png', 'smoke\out.pdf') { if (-not (Test-Path $f) -or (Get-Item $f).Length -eq 0) { Write-Output $out; throw "$f was not written" } }
- Write-Output 'ok printcraft-cli: opened, read, edited, rendered and saved a PDF on ARM64'
+ Write-Output 'ok pdfcraft-cli: opened, read, edited, rendered and saved a PDF on ARM64'
$p = Start-Process msiexec.exe -ArgumentList '/x', "`"$msi`"", '/qn' -Wait -PassThru
if ($p.ExitCode -ne 0) { throw "msiexec /x exited $($p.ExitCode)" }
- if (Test-Path (Join-Path $dir 'printcraft.exe')) { throw 'uninstall left printcraft.exe behind' }
+ if (Test-Path (Join-Path $dir 'pdfcraft.exe')) { throw 'uninstall left pdfcraft.exe behind' }
Write-Output 'ok uninstalled'
test:
diff --git a/AGENTS.md b/AGENTS.md
index 0c6d8407..0720da26 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -37,7 +37,7 @@ Every asset must be one of:
- **Public domain.**
- **Contributor-original:** created, photographed or generated by a contributor who owns it and licenses it under the project licence (`MIT OR Apache-2.0`).
-**One narrow exception: the ArtCraft brand.** The ArtCraft name, wordmark and logos in `docs/brand/` are trademarks of the ArtCraft Team and are **not** open source (manifest identifier `LicenseRef-Storyteller-Trademark`, terms in `docs/brand/LICENSE-brand.txt`). They may be used only unmodified, only within PrintCraft, and only as `kind = "logo"` entries from that directory, to identify the project. Forks and modified versions must remove them. Never add other files under this licence, and never modify the logos.
+**One narrow exception: the ArtCraft brand.** The ArtCraft name, wordmark and logos in `docs/brand/` are trademarks of the ArtCraft Team and are **not** open source (manifest identifier `LicenseRef-Storyteller-Trademark`, terms in `docs/brand/LICENSE-brand.txt`). They may be used only unmodified, only within PdfCraft, and only as `kind = "logo"` entries from that directory, to identify the project. Forks and modified versions must remove them. Never add other files under this licence, and never modify the logos.
Anything else is forbidden, including assets whose licence you cannot prove from the source. Examples:
- system fonts (Apple, Microsoft, Google Android system UI fonts that are not openly licensed);
@@ -46,7 +46,7 @@ Anything else is forbidden, including assets whose licence you cannot prove from
- "free for personal use" material;
- screenshots of other people's software.
-**Screenshots of PrintCraft** are contributor-original. Everything visible in them must itself be allowed: our UI, Lucide icons, OFL fonts, and demo documents built only from allowed assets. Never screenshot a document that uses proprietary fonts or images.
+**Screenshots of PdfCraft** are contributor-original. Everything visible in them must itself be allowed: our UI, Lucide icons, OFL fonts, and demo documents built only from allowed assets. Never screenshot a document that uses proprietary fonts or images.
### 1.3 Every asset is attributed
@@ -69,7 +69,7 @@ Anything else is forbidden, including assets whose licence you cannot prove from
### 1.4 Fonts live in craft-fonts
- Font assets shared by the Crafting Apps, including every Japanese font, live in [`storytold/craft-fonts`](https://github.com/storytold/craft-fonts), not here. **Never commit a font file to this repository**; adding a font means adding it to craft-fonts. (The Latin UI fonts already in `assets/fonts/` — Inter, JetBrains Mono, Dancing Script — stay.) Team members: the shared rules are in [craftrules `standards/fonts.md`](https://github.com/storytold/craftrules/blob/main/standards/fonts.md) (internal).
-- craft-fonts is an **optional build input**, never a Cargo dependency: `CRAFT_FONTS_DIR= cargo build` makes `crates/fonts/build.rs` embed its fonts as `printcraft_fonts::CRAFT_FONTS`. Without it PrintCraft builds, tests and runs, but has no Japanese face (Japanese UI text shows replacement boxes, and writing Japanese into a PDF returns a clear error). Release builds always set it (`.github/workflows/release.yml`), and `ATTRIBUTION.toml` lists it as a `[[build_input]]`.
+- craft-fonts is an **optional build input**, never a Cargo dependency: `CRAFT_FONTS_DIR= cargo build` makes `crates/fonts/build.rs` embed its fonts as `pdfcraft_fonts::CRAFT_FONTS`. Without it PdfCraft builds, tests and runs, but has no Japanese face (Japanese UI text shows replacement boxes, and writing Japanese into a PDF returns a clear error). Release builds always set it (`.github/workflows/release.yml`), and `ATTRIBUTION.toml` lists it as a `[[build_input]]`.
### 1.5 Procedure for adding or changing an asset
@@ -94,16 +94,16 @@ If you find an asset that breaks these rules, stop and remove it from the reposi
## 3. Agent control (automation and MCP)
-- **Everything is reachable headlessly.** Every user-facing feature must be callable without the GUI: an engine API, then a tool in `crates/automation` (`printcraft-cli run` and MCP use the same table). A feature is not done until its tool exists and has an end-to-end test (`crates/automation/README.md`, "Adding a tool").
+- **Everything is reachable headlessly.** Every user-facing feature must be callable without the GUI: an engine API, then a tool in `crates/automation` (`pdfcraft-cli run` and MCP use the same table). A feature is not done until its tool exists and has an end-to-end test (`crates/automation/README.md`, "Adding a tool").
- **The UI control channel is opt-in too.** It runs only when the app is launched with `--control `. It binds to loopback, uses a fresh random token per launch, and writes it to an owner-only file. Never enable it by default, widen the bind address, or log the token.
-- **The MCP server is opt-in.** Never make the app, the CLI or an installer start it, register it with an agent, or listen on a port by default. It runs only when a user (or an agent the user configured) launches `printcraft-cli mcp`. Any future network transport must be off by default, bound to loopback and authenticated with a token.
+- **The MCP server is opt-in.** Never make the app, the CLI or an installer start it, register it with an agent, or listen on a port by default. It runs only when a user (or an agent the user configured) launches `pdfcraft-cli mcp`. Any future network transport must be off by default, bound to loopback and authenticated with a token.
- **Safe by default.** Tools must never discard unsaved work silently, must write atomically, must honour `--root`, and must return errors an agent can act on (say what was wrong and what is allowed).
- **Track parity honestly.** Every user-facing feature has an entry in `parity/acrobat-features.toml`. Mark it `shipped` only when it works end to end and the entry cites a passing test (`evidence`); `cargo xtask parity` (part of `xtask ci`) rejects claims whose commands, tools or tests don't exist.
-- **Use it to test.** Agents should drive the engine through `printcraft-cli run --script` or the MCP tools, and look at `page_render` output, to check their own changes. For UI changes, launch the app with `--control` and use `printcraft-cli ui` (`inspect`, `click`, `screenshot`) to check the real interface.
+- **Use it to test.** Agents should drive the engine through `pdfcraft-cli run --script` or the MCP tools, and look at `page_render` output, to check their own changes. For UI changes, launch the app with `--control` and use `pdfcraft-cli ui` (`inspect`, `click`, `screenshot`) to check the real interface.
## 4. Never crash
-PrintCraft opens files from strangers, and people trust it with their work. A malformed PDF, a bad tool argument, a corrupt settings file or a full disk must produce an error the user (or agent) can act on, never a crash and never lost work. **This outranks feature work:** don't ship a feature by adding a panic path, and fix a crash before building on top of it. The rules below are the ones that bind this repository; the shared standard for every Crafting App, [`craftrules/standards/never-crash.md`](https://github.com/storytold/craftrules/blob/main/standards/never-crash.md), is internal to the storytold team.
+PdfCraft opens files from strangers, and people trust it with their work. A malformed PDF, a bad tool argument, a corrupt settings file or a full disk must produce an error the user (or agent) can act on, never a crash and never lost work. **This outranks feature work:** don't ship a feature by adding a panic path, and fix a crash before building on top of it. The rules below are the ones that bind this repository; the shared standard for every Crafting App, [`craftrules/standards/never-crash.md`](https://github.com/storytold/craftrules/blob/main/standards/never-crash.md), is internal to the storytold team.
- **Fail with `Result`.** Non-test code returns errors through the crate's error type and `?`. Where readers are lenient by design, fall back gracefully and record the repair (see Fidelity in `CLAUDE.md`).
- **No panicking shortcuts.** No `unwrap()`, `expect()`, `panic!`, `unreachable!`, `todo!` or `unimplemented!` outside tests, unless the call is provably infallible (e.g. writing to a `Vec`), with a comment saying why. `assert!` only for internal invariants that input cannot reach.
diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md
index 2f0ded9a..dc602514 100644
--- a/ATTRIBUTION.md
+++ b/ATTRIBUTION.md
@@ -2,7 +2,7 @@
-Every asset PrintCraft includes, bundles or uses to build its published material, with its author, source and licence. The policy is in [AGENTS.md](AGENTS.md) §1. The machine-readable list, with SHA-256 hashes, is [ATTRIBUTION.toml](ATTRIBUTION.toml). Licence texts are kept beside the assets and summarised in [NOTICE](NOTICE).
+Every asset PdfCraft includes, bundles or uses to build its published material, with its author, source and licence. The policy is in [AGENTS.md](AGENTS.md) §1. The machine-readable list, with SHA-256 hashes, is [ATTRIBUTION.toml](ATTRIBUTION.toml). Licence texts are kept beside the assets and summarised in [NOTICE](NOTICE).
## In this repository (242)
@@ -202,41 +202,41 @@ Every asset PrintCraft includes, bundles or uses to build its published material
| `vendor/hayro-interpret/assets/FoxitSymbol.pfb` | FoxitSymbol (standard-14 substitute font) | Foxit Software Inc. / PDFium Authors | BSD-3-Clause | https://pdfium.googlesource.com/pdfium (via hayro-interpret 0.7.0 assets/) | Renders non-embedded standard-14 fonts (vendored hayro-interpret) |
| `vendor/hayro-interpret/assets/CGATS001Compat-v2-micro.icc` | CGATS001Compat v2 micro ICC profile | Clinton Ingram (saucecontrol/Compact-ICC-Profiles) | CC0-1.0 | https://github.com/saucecontrol/Compact-ICC-Profiles | Default CMYK colour conversion (vendored hayro-interpret) |
| `vendor/hayro-interpret/assets/LAB.icc` | Lab abstract ICC profile | The Hayro Authors (generated with LittleCMS 2) | MIT OR Apache-2.0 | https://github.com/LaurenzV/hayro (hayro-interpret 0.7.0 assets/) | Lab colour space conversion (vendored hayro-interpret) |
-| `docs/brand/artcraft-logo-white.png` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-logo-white.svg` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-logo.png` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-logo.svg` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-mark-black.png` | ArtCraft brand: artcraft-mark-black | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-mark-black.svg` | ArtCraft brand: artcraft-mark-black | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-mark.png` | ArtCraft brand: artcraft-mark | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `docs/brand/artcraft-mark.svg` | ArtCraft brand: artcraft-mark | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it. |
-| `assets/app-icon/printcraft.svg` | PrintCraft app icon (master vector) | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Master artwork; every other app-icon file is rendered from it (packaging/icons.sh) |
-| `assets/app-icon/printcraft-small.svg` | PrintCraft app icon (light vector) | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | README header and assets/app-icon/README.md |
-| `assets/app-icon/printcraft-1024.png` | PrintCraft app icon, 1024 px on Apple's icon grid | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Runtime window/Dock icon on macOS (apps/printcraft/src/main.rs) |
-| `assets/app-icon/printcraft.icns` | PrintCraft app icon (macOS .icns) | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | macOS app bundle icon |
-| `assets/app-icon/printcraft.ico` | PrintCraft app icon (Windows .ico, 16-256 px) | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Embedded in printcraft.exe by apps/printcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab) |
-| `assets/app-icon/hicolor/16x16/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 16 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/24x24/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 24 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/32x32/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 32 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/48x48/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 48 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/64x64/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 64 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/128x128/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 128 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/256x256/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 256 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop); runtime window icon on Windows and Linux (apps/printcraft/src/main.rs) |
-| `assets/app-icon/hicolor/512x512/apps/ai.storyteller.printcraft.png` | PrintCraft app icon, 512 px | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `assets/app-icon/hicolor/scalable/apps/ai.storyteller.printcraft.svg` | PrintCraft app icon (Linux scalable) | PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop) |
-| `docs/images/printcraft-bookmarks.png` | PrintCraft screenshot: Bookmarks | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: navigation. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-dark.png` | PrintCraft screenshot: Dark theme | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: themes. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-find.png` | PrintCraft screenshot: Find text | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: search. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-forms.png` | PrintCraft screenshot: Interactive form | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: forms. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-layers.png` | PrintCraft screenshot: Layers | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layers. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-organize.png` | PrintCraft screenshot: Organize pages | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: organize. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-palette.png` | PrintCraft screenshot: Command palette | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tools. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-properties.png` | PrintCraft screenshot: Document properties | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: metadata. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-scripts.png` | PrintCraft screenshot: Scripts of the world | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: rendering. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-split.png` | PrintCraft screenshot: Split dialog | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: split. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-tools.png` | PrintCraft screenshot: All tools | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tool catalogue. Shows PrintCraft UI, Lucide icons, the showcase PDF built from the [[fetched]] OFL fonts, and the ArtCraft mark (Storyteller trademark from docs/brand/, not covered by this licence) |
-| `docs/images/printcraft-twoup.png` | PrintCraft screenshot: Two-up reading | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layouts. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
-| `docs/images/printcraft-viewer.png` | PrintCraft screenshot: Viewer with comments | PrintCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README hero. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/brand/artcraft-logo-white.png` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-logo-white.svg` | ArtCraft brand: artcraft-logo-white | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-logo.png` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-logo.svg` | ArtCraft brand: artcraft-logo | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-mark-black.png` | ArtCraft brand: artcraft-mark-black | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-mark-black.svg` | ArtCraft brand: artcraft-mark-black | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-mark.png` | ArtCraft brand: artcraft-mark | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `docs/brand/artcraft-mark.svg` | ArtCraft brand: artcraft-mark | ArtCraft Team | LicenseRef-Storyteller-Trademark | ArtCraft Team brand assets (provided by the project owner, 2026-10-01; identical copies in storytold/photocraft) | ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it. |
+| `assets/app-icon/pdfcraft.svg` | PdfCraft app icon (master vector) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Master artwork; every other app-icon file is rendered from it (packaging/icons.sh) |
+| `assets/app-icon/pdfcraft-small.svg` | PdfCraft app icon (light vector) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | README header and assets/app-icon/README.md |
+| `assets/app-icon/pdfcraft-1024.png` | PdfCraft app icon, 1024 px on Apple's icon grid | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs) |
+| `assets/app-icon/pdfcraft.icns` | PdfCraft app icon (macOS .icns) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | macOS app bundle icon |
+| `assets/app-icon/pdfcraft.ico` | PdfCraft app icon (Windows .ico, 16-256 px) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab) |
+| `assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 16 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 24 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 32 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 48 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 64 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 128 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 256 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop); runtime window icon on Windows and Linux (apps/pdfcraft/src/main.rs) |
+| `assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png` | PdfCraft app icon, 512 px | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg` | PdfCraft app icon (Linux scalable) | PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py) | MIT OR Apache-2.0 | Contributor-original (see assets/app-icon/README.md) | Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop) |
+| `docs/images/pdfcraft-bookmarks.png` | PdfCraft screenshot: Bookmarks | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-dark.png` | PdfCraft screenshot: Dark theme | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-find.png` | PdfCraft screenshot: Find text | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-forms.png` | PdfCraft screenshot: Interactive form | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-layers.png` | PdfCraft screenshot: Layers | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-organize.png` | PdfCraft screenshot: Organize pages | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-palette.png` | PdfCraft screenshot: Command palette | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-properties.png` | PdfCraft screenshot: Document properties | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-scripts.png` | PdfCraft screenshot: Scripts of the world | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-split.png` | PdfCraft screenshot: Split dialog | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-tools.png` | PdfCraft screenshot: All tools | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: tool catalogue. Shows PdfCraft UI, Lucide icons, the showcase PDF built from the [[fetched]] OFL fonts, and the ArtCraft mark (Storyteller trademark from docs/brand/, not covered by this licence) |
+| `docs/images/pdfcraft-twoup.png` | PdfCraft screenshot: Two-up reading | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
+| `docs/images/pdfcraft-viewer.png` | PdfCraft screenshot: Viewer with comments | PdfCraft contributors (generated by `cargo xtask screenshots`) | MIT OR Apache-2.0 | this repository | README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts |
| `assets/icons/pin.svg` | Lucide icon "pin" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pin.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/move-right.svg` | Lucide icon "move-right" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/move-right.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/reply.svg` | Lucide icon "reply" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/reply.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
@@ -244,10 +244,10 @@ Every asset PrintCraft includes, bundles or uses to build its published material
| `assets/icons/thumbs-down.svg` | Lucide icon "thumbs-down" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/thumbs-down.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/message-square-plus.svg` | Lucide icon "message-square-plus" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-plus.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/circle-x.svg` | Lucide icon "circle-x" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/circle-x.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
-| `crates/ui-egui/tests/data/form.pdf` | One-page AcroForm test fixture (text, check box, radio group, combo box) | PrintCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects, no third-party content | Form-filling UI tests (crates/ui-egui/tests/forms.rs, commands.rs) |
+| `crates/ui-egui/tests/data/form.pdf` | One-page AcroForm test fixture (text, check box, radio group, combo box) | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects, no third-party content | Form-filling UI tests (crates/ui-egui/tests/forms.rs, commands.rs) |
| `assets/icons/pentagon.svg` | Lucide icon "pentagon" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/pentagon.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/icons/message-square-quote.svg` | Lucide icon "message-square-quote" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/message-square-quote.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
-| `crates/sign/tests/data/openssl-signed.pdf` | One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key | PrintCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/pdf.rs): a signature PrintCraft did not make |
+| `crates/sign/tests/data/openssl-signed.pdf` | One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key | PdfCraft contributors | MIT OR Apache-2.0 | Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md) | Signature validation tests (crates/sign/tests/pdf.rs): a signature PdfCraft did not make |
| `assets/icons/clipboard-paste.svg` | Lucide icon "clipboard-paste" | Lucide Contributors (portions Cole Bemis, Feather) | ISC | https://github.com/lucide-icons/lucide (npm lucide-static 1.49.0, icons/clipboard-paste.svg) | UI icon, embedded via crates/ui-egui/src/icon_data.rs |
| `assets/fonts/DancingScript.ttf` | Dancing Script (variable) | The Dancing Script Project Authors (Pablo Impallari) | OFL-1.1 | https://github.com/google/fonts/blob/9710da1eacb3be272583c3224dcb70f9da6eadbb/ofl/dancingscript/DancingScript%5Bwght%5D.ttf | Fill & Sign typed signatures and initials: the typed name's glyph outlines, drawn as filled paths (the font file itself is not embedded in PDFs) |
diff --git a/ATTRIBUTION.toml b/ATTRIBUTION.toml
index 796b5b6c..b2008de4 100644
--- a/ATTRIBUTION.toml
+++ b/ATTRIBUTION.toml
@@ -2,7 +2,7 @@
# ATTRIBUTION.md is generated from this file: `cargo xtask assets --write`. Checked by `cargo xtask assets` (part of `xtask ci`).
#
# [[asset]] a file in this repository (committed or vendored); `sha256` must match the file.
-# [[bundled]] a file compiled into PrintCraft by a Cargo dependency (its crate version must match Cargo.lock).
+# [[bundled]] a file compiled into PdfCraft by a Cargo dependency (its crate version must match Cargo.lock).
# [[fetched]] downloaded at build time by xtask (never committed), pinned by `sha256`.
# [[build_input]] an optional build input outside this repository (e.g. craft-fonts via CRAFT_FONTS_DIR);
# never committed or downloaded here, its own repository attributes each file.
@@ -2486,7 +2486,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "8b86aeb06a12a90ba77a60e0d90329272310e244ee5c1f9b161b391280ca79d8"
[[asset]]
@@ -2497,7 +2497,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "a3e03dc49f9ad4225b8517d5424309c8d1c864d3996d862190d9cc797d5af427"
[[asset]]
@@ -2508,7 +2508,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "08fc6d9d3717e8f13417bac6f9025b50e11d1e0b32e9e000883d2fe0c4a0c67b"
[[asset]]
@@ -2519,7 +2519,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "3188971e1affdf4f6be4fa65f715376a7a305e6aa741ec78b0296c8f934eff08"
[[asset]]
@@ -2530,7 +2530,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "5954cc0306e1b9d7beb47097e2e842157113a39d9aba078b57304902687936a9"
[[asset]]
@@ -2541,7 +2541,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "570adcb4f7ba8ca0647f97074476bab81d3272988f1cdee52efa21bf026036a4"
[[asset]]
@@ -2552,7 +2552,7 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "9d372157a949c147318561e629b11561c28b7cbc14c84b516a3fe6e84d8fbbad"
[[asset]]
@@ -2563,13 +2563,13 @@ source = "ArtCraft Team brand assets (provided by the project owner, 2026-10-01;
licence = "LicenseRef-Storyteller-Trademark"
licence_file = "docs/brand/LICENSE-brand.txt"
kind = "logo"
-usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PrintCraft; forks and modified versions must remove it."
+usage = "ArtCraft branding next to the community links (About dialog, Help menu, home screen) and in docs. ArtCraft Team trademark, not open source; may be used only unmodified within PdfCraft; forks and modified versions must remove it."
sha256 = "f87af81b6fa411da8820eed2bfdcc54c0ee9cd453b4e868c64f56c69db142d0e"
[[asset]]
-path = "assets/app-icon/printcraft.svg"
-title = "PrintCraft app icon (master vector)"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/pdfcraft.svg"
+title = "PdfCraft app icon (master vector)"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
@@ -2578,9 +2578,9 @@ usage = "Master artwork; every other app-icon file is rendered from it (packagin
sha256 = "52b384a10a2a7fdd3145d9822972cfd568ef0cb7312549bd4399addd89d45a6d"
[[asset]]
-path = "assets/app-icon/printcraft-small.svg"
-title = "PrintCraft app icon (light vector)"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/pdfcraft-small.svg"
+title = "PdfCraft app icon (light vector)"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
@@ -2589,20 +2589,20 @@ usage = "README header and assets/app-icon/README.md"
sha256 = "b036304c11ef5dcad36636d06ca0bf331b51e47650d25d3c916a0e1eabf544c7"
[[asset]]
-path = "assets/app-icon/printcraft-1024.png"
-title = "PrintCraft app icon, 1024 px on Apple's icon grid"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/pdfcraft-1024.png"
+title = "PdfCraft app icon, 1024 px on Apple's icon grid"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Runtime window/Dock icon on macOS (apps/printcraft/src/main.rs)"
+usage = "Runtime window/Dock icon on macOS (apps/pdfcraft/src/main.rs)"
sha256 = "da577d3f21fbcf5c739067787a9e683be2b064d76813b5d5fec9074a7a106538"
[[asset]]
-path = "assets/app-icon/printcraft.icns"
-title = "PrintCraft app icon (macOS .icns)"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/pdfcraft.icns"
+title = "PdfCraft app icon (macOS .icns)"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
@@ -2611,256 +2611,256 @@ usage = "macOS app bundle icon"
sha256 = "2425148222873de241d267aba667a8b234ecdd0149f2ca8bb6e79443b743b1e8"
[[asset]]
-path = "assets/app-icon/printcraft.ico"
-title = "PrintCraft app icon (Windows .ico, 16-256 px)"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/pdfcraft.ico"
+title = "PdfCraft app icon (Windows .ico, 16-256 px)"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Embedded in printcraft.exe by apps/printcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab)"
+usage = "Embedded in pdfcraft.exe by apps/pdfcraft/build.rs (Explorer, taskbar, Start menu, Alt-Tab)"
sha256 = "56daaaae9ae5389794909570885809adf5e1d9183bef2d9669ed2f9bba3ed6f5"
[[asset]]
-path = "assets/app-icon/hicolor/16x16/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 16 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/16x16/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 16 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "9b77095cbe75dcba6b74a1fdcd4064812850efaf7a12edebefc9ded5eabb49da"
[[asset]]
-path = "assets/app-icon/hicolor/24x24/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 24 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/24x24/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 24 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "a4cd466687f6c5cb59eef3fc564bdba1c8f0d9e324754eeebab82f18823efae7"
[[asset]]
-path = "assets/app-icon/hicolor/32x32/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 32 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/32x32/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 32 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "e22279013a5ed5c02571e1e4e9bc4cef9aa0847fcb733a285b2916fabd16bf78"
[[asset]]
-path = "assets/app-icon/hicolor/48x48/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 48 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/48x48/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 48 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "55daf2d5575f6c4e4c4975c9f1c74231178f1801963a8b19f68dfa9bc50cb22f"
[[asset]]
-path = "assets/app-icon/hicolor/64x64/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 64 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/64x64/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 64 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "2975c200f341e247b5fa18f568fb27d390e3fa01e9b2ad37acb48d0e1cc8a124"
[[asset]]
-path = "assets/app-icon/hicolor/128x128/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 128 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/128x128/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 128 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "6ef927ca252b40bc9b5d8843d84137334362f8aa1acbb1bf8c15a02affd25b2b"
[[asset]]
-path = "assets/app-icon/hicolor/256x256/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 256 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/256x256/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 256 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop); runtime window icon on Windows and Linux (apps/printcraft/src/main.rs)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop); runtime window icon on Windows and Linux (apps/pdfcraft/src/main.rs)"
sha256 = "cde7ee8c5ee38f9fc40a429fd9e6d99a035bcd321701fce331bb13bac126614d"
[[asset]]
-path = "assets/app-icon/hicolor/512x512/apps/ai.storyteller.printcraft.png"
-title = "PrintCraft app icon, 512 px"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/512x512/apps/ai.storyteller.pdfcraft.png"
+title = "PdfCraft app icon, 512 px"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "5ede733e93b96f4eb8d94299232cf2f9605fa19b0d913f95fe9828c316a2d066"
[[asset]]
-path = "assets/app-icon/hicolor/scalable/apps/ai.storyteller.printcraft.svg"
-title = "PrintCraft app icon (Linux scalable)"
-author = "PrintCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
+path = "assets/app-icon/hicolor/scalable/apps/ai.storyteller.pdfcraft.svg"
+title = "PdfCraft app icon (Linux scalable)"
+author = "PdfCraft contributors (drawn by the project owner in ArtCraft; vectorised with craftrules vectorize_tile.py)"
source = "Contributor-original (see assets/app-icon/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "assets/app-icon/LICENSE.txt"
kind = "icon"
-usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.printcraft.desktop)"
+usage = "Linux hicolor theme icon (packaging/linux/ai.storyteller.pdfcraft.desktop)"
sha256 = "52b384a10a2a7fdd3145d9822972cfd568ef0cb7312549bd4399addd89d45a6d"
[[asset]]
-path = "docs/images/printcraft-bookmarks.png"
-title = "PrintCraft screenshot: Bookmarks"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-bookmarks.png"
+title = "PdfCraft screenshot: Bookmarks"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: navigation. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: navigation. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "6daf2dceda8737da0c5f9e7895e5c4cc24cc845938ffca478713c2230573240d"
[[asset]]
-path = "docs/images/printcraft-dark.png"
-title = "PrintCraft screenshot: Dark theme"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-dark.png"
+title = "PdfCraft screenshot: Dark theme"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: themes. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: themes. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "18fbd4931b2a8d01a88aef0d5d0837e3cdc12aa35f8529bedbb4a930565d47e5"
[[asset]]
-path = "docs/images/printcraft-find.png"
-title = "PrintCraft screenshot: Find text"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-find.png"
+title = "PdfCraft screenshot: Find text"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: search. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: search. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "b52771502be4c03e2dabf107c77d5183fad7f39655146d59761dda855c2d4b52"
[[asset]]
-path = "docs/images/printcraft-forms.png"
-title = "PrintCraft screenshot: Interactive form"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-forms.png"
+title = "PdfCraft screenshot: Interactive form"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: forms. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: forms. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "f8eb7705056d32e9c8e4d3b8b197c3e500faae08672e4622d6327d2799b536e7"
[[asset]]
-path = "docs/images/printcraft-layers.png"
-title = "PrintCraft screenshot: Layers"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-layers.png"
+title = "PdfCraft screenshot: Layers"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: layers. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: layers. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "20ff9e1c6ecc74d000a7514b82fe9e39f82c8ef5e7c1a52e9060c5ca349020d6"
[[asset]]
-path = "docs/images/printcraft-organize.png"
-title = "PrintCraft screenshot: Organize pages"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-organize.png"
+title = "PdfCraft screenshot: Organize pages"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: organize. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: organize. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "0a309ba73bcfccbe0106824b55fc347cc0b32293d1db68149d5eccec9c087ba1"
[[asset]]
-path = "docs/images/printcraft-palette.png"
-title = "PrintCraft screenshot: Command palette"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-palette.png"
+title = "PdfCraft screenshot: Command palette"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: tools. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: tools. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "74867793e506c03255459e838eef0b08e485c13b7ea8a6b8de3ec16870067eda"
[[asset]]
-path = "docs/images/printcraft-properties.png"
-title = "PrintCraft screenshot: Document properties"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-properties.png"
+title = "PdfCraft screenshot: Document properties"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: metadata. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: metadata. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "86f293543b299fa1665db999a68978138f8d61a4082d7c5b5025498e188da459"
[[asset]]
-path = "docs/images/printcraft-scripts.png"
-title = "PrintCraft screenshot: Scripts of the world"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-scripts.png"
+title = "PdfCraft screenshot: Scripts of the world"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: rendering. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: rendering. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "0dde8ed5a14dee7396379963adff517bd249c7dd0fe494c389b612e643584b15"
[[asset]]
-path = "docs/images/printcraft-split.png"
-title = "PrintCraft screenshot: Split dialog"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-split.png"
+title = "PdfCraft screenshot: Split dialog"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: split. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: split. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "bf31e13b563ead564af968c5fae8d1c07b91ee38867d0cf1aae9e0582efc2fe5"
[[asset]]
-path = "docs/images/printcraft-tools.png"
-title = "PrintCraft screenshot: All tools"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-tools.png"
+title = "PdfCraft screenshot: All tools"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: tool catalogue. Shows PrintCraft UI, Lucide icons, the showcase PDF built from the [[fetched]] OFL fonts, and the ArtCraft mark (Storyteller trademark from docs/brand/, not covered by this licence)"
+usage = "README: tool catalogue. Shows PdfCraft UI, Lucide icons, the showcase PDF built from the [[fetched]] OFL fonts, and the ArtCraft mark (Storyteller trademark from docs/brand/, not covered by this licence)"
sha256 = "61731a921902e285d40826d401f1ef25624dabb8c8ac1f8f0c09c1292a17ee1a"
[[asset]]
-path = "docs/images/printcraft-twoup.png"
-title = "PrintCraft screenshot: Two-up reading"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-twoup.png"
+title = "PdfCraft screenshot: Two-up reading"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README: layouts. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README: layouts. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "a72ed1b84c827e3aa1dd3282d857b4742f02d8ff23fc39b62115c840ebad14b4"
[[asset]]
-path = "docs/images/printcraft-viewer.png"
-title = "PrintCraft screenshot: Viewer with comments"
-author = "PrintCraft contributors (generated by `cargo xtask screenshots`)"
+path = "docs/images/pdfcraft-viewer.png"
+title = "PdfCraft screenshot: Viewer with comments"
+author = "PdfCraft contributors (generated by `cargo xtask screenshots`)"
source = "this repository"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "image"
-usage = "README hero. Shows only PrintCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
+usage = "README hero. Shows only PdfCraft UI, Lucide icons and the showcase PDF built from the [[fetched]] OFL fonts"
sha256 = "ecd261028d8837f7f7c013dd796d81ca7e89643bcfcbad3ab9fbfbe87ded04e3"
[[asset]]
@@ -2943,7 +2943,7 @@ sha256 = "ef1fec17d88794ba6c34c5cf63bdadbd234b3d4dffbcc3d55468b47e3f398472"
[[asset]]
path = "crates/ui-egui/tests/data/form.pdf"
title = "One-page AcroForm test fixture (text, check box, radio group, combo box)"
-author = "PrintCraft contributors"
+author = "PdfCraft contributors"
source = "Contributor-original: hand-written PDF objects, no third-party content"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
@@ -2976,12 +2976,12 @@ sha256 = "69a76b4cd352dbdea61c63ed1e8d1e02083ee1773b3ced2a1c8cdf8c90fb2055"
[[asset]]
path = "crates/sign/tests/data/openssl-signed.pdf"
title = "One-page PDF signed with OpenSSL CMS (adbe.pkcs7.detached) by the RSA test key"
-author = "PrintCraft contributors"
+author = "PdfCraft contributors"
source = "Contributor-original: hand-written PDF objects; signature made with `openssl cms -sign` over its byte ranges (see crates/sign/tests/data/README.md)"
licence = "MIT OR Apache-2.0"
licence_file = "LICENSE-MIT"
kind = "document"
-usage = "Signature validation tests (crates/sign/tests/pdf.rs): a signature PrintCraft did not make"
+usage = "Signature validation tests (crates/sign/tests/pdf.rs): a signature PdfCraft did not make"
sha256 = "8b91c3b4e39c4a31717a0dd0685bd7d0468671df32aee5b9818d44dc72c2bc3c"
[[asset]]
diff --git a/CLAUDE.md b/CLAUDE.md
index 60f00c7f..ccad9e7b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,6 +1,6 @@
-# PrintCraft — instructions for agents
+# PdfCraft — instructions for agents
-PrintCraft is a clean-room, open-source, Rust-native PDF application targeting Adobe Acrobat Pro parity. It runs natively on macOS, Windows, Linux and FreeBSD, and on the web via WASM. It is the sibling of `../photocraft` (a Photoshop-class editor) and follows the same conventions.
+PdfCraft is a clean-room, open-source, Rust-native PDF application targeting Adobe Acrobat Pro parity. It runs natively on macOS, Windows, Linux and FreeBSD, and on the web via WASM. It is the sibling of `../photocraft` (a Photoshop-class editor) and follows the same conventions.
## Start every session here
1. Read `plan/STATUS.md`: the current milestone, the next unchecked task and any blockers. `ROADMAP.md` holds the milestone estimates and progress; update its table and log at the end of every session.
@@ -13,7 +13,7 @@ PrintCraft is a clean-room, open-source, Rust-native PDF application targeting A
## Non-negotiables
- **Assets: read `AGENTS.md` §1 before adding or showing any icon, image, font or document.** No assets from Adobe products, ever. Only openly licensed or contributor-original assets are allowed, each with an entry in `ATTRIBUTION.toml`. `cargo xtask assets` enforces this. `AGENTS.md` overrides this file.
-- **Fonts live in [storytold/craft-fonts](https://github.com/storytold/craft-fonts).** Never commit font files here (`AGENTS.md` §1.4; team members: [craftrules `standards/fonts.md`](https://github.com/storytold/craftrules/blob/main/standards/fonts.md), internal). It is the optional build input `CRAFT_FONTS_DIR`: `git clone https://github.com/storytold/craft-fonts ../craft-fonts && CRAFT_FONTS_DIR=../craft-fonts cargo test --workspace` embeds the Japanese fonts (UI fallback, Japanese text in edited PDFs) and runs their tests, which otherwise skip. Code using `printcraft_fonts::CRAFT_FONTS` must work when it is empty.
+- **Fonts live in [storytold/craft-fonts](https://github.com/storytold/craft-fonts).** Never commit font files here (`AGENTS.md` §1.4; team members: [craftrules `standards/fonts.md`](https://github.com/storytold/craftrules/blob/main/standards/fonts.md), internal). It is the optional build input `CRAFT_FONTS_DIR`: `git clone https://github.com/storytold/craft-fonts ../craft-fonts && CRAFT_FONTS_DIR=../craft-fonts cargo test --workspace` embeds the Japanese fonts (UI fallback, Japanese text in edited PDFs) and runs their tests, which otherwise skip. Code using `pdfcraft_fonts::CRAFT_FONTS` must work when it is empty.
- **Clean-room.**
- Never read, disassemble or copy anything inside the Acrobat bundle (names and listings only). **Never open `Contents/Resources/JavaScripts/`.**
- Behaviour comes from public docs, specs (ISO 32000-2, the Arlington model) and black-box observation (`plan/acrobat/`).
@@ -35,13 +35,13 @@ PrintCraft is a clean-room, open-source, Rust-native PDF application targeting A
- **Commits:** one task id per commit (e.g. `M1.4: xref stream reader`). Commit only green states. End messages with the attribution line required by the environment.
## Running and looking at the app
-- `cargo run -p printcraft -- ` opens the desktop app.
-- `cargo run -p printcraft-cli -- run --script steps.json --root DIR` drives the engine headlessly through the automation tools (`printcraft-cli tools` lists them). Use it, together with `page_render`, to check engine changes. `printcraft-cli mcp` is the opt-in MCP server (AGENTS.md §3).
+- `cargo run -p pdfcraft -- ` opens the desktop app.
+- `cargo run -p pdfcraft-cli -- run --script steps.json --root DIR` drives the engine headlessly through the automation tools (`pdfcraft-cli tools` lists them). Use it, together with `page_render`, to check engine changes. `pdfcraft-cli mcp` is the opt-in MCP server (AGENTS.md §3).
- `cargo xtask fuzz --time 300` mutation-fuzzes open/render/edit/save in child processes. Findings land in `fuzz-out/findings/` (git-ignored; never commit corpus-derived files). Turn every real finding into a small synthetic regression test before fixing it.
- `cargo xtask parity [--partial]` reports Acrobat-parity progress from `parity/acrobat-features.toml`. Update the entry when a feature ships.
-- `cargo xtask demo-pdf` builds `dist/demo/printcraft-showcase.pdf` (needs Chrome) for visual checks.
-- For UI work, **look at the result**. Either launch `printcraft --control FILE doc.pdf` and use `printcraft-cli ui --control FILE screenshot --out x.png` (plus `inspect`, `click`, `key`, `type`, `command`, `set`), or take a headless shot with `cargo run -p printcraft-ui-egui --example shot`. Compare against `plan/acrobat/02-ui-ux.md`. Control-channel tests use kittest (`crates/ui-egui/tests/control.rs`).
+- `cargo xtask demo-pdf` builds `dist/demo/pdfcraft-showcase.pdf` (needs Chrome) for visual checks.
+- For UI work, **look at the result**. Either launch `pdfcraft --control FILE doc.pdf` and use `pdfcraft-cli ui --control FILE screenshot --out x.png` (plus `inspect`, `click`, `key`, `type`, `command`, `set`), or take a headless shot with `cargo run -p pdfcraft-ui-egui --example shot`. Compare against `plan/acrobat/02-ui-ux.md`. Control-channel tests use kittest (`crates/ui-egui/tests/control.rs`).
- Parallel agents: use a separate `CARGO_TARGET_DIR` per agent and separate git worktrees.
## Current bootstrap debt (tracked in STATUS.md)
-- `printcraft-render` renders through the `hayro` crate directly and inspects documents through `lopdf`. Both get replaced by `cos` / `model` / the DisplayList device (M1–M2, ADR-0004).
+- `pdfcraft-render` renders through the `hayro` crate directly and inspects documents through `lopdf`. Both get replaced by `cos` / `model` / the DisplayList device (M1–M2, ADR-0004).
diff --git a/Cargo.lock b/Cargo.lock
index a6efac42..0b4ab6f4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3445,6 +3445,365 @@ dependencies = [
"hmac",
]
+[[package]]
+name = "pdfcraft"
+version = "0.2.1"
+dependencies = [
+ "eframe",
+ "egui",
+ "fmv-macos-events",
+ "pdfcraft-ui-egui",
+ "rustls-native-certs",
+ "serde_json",
+ "ureq",
+ "winresource",
+]
+
+[[package]]
+name = "pdfcraft-a11y"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-model",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-annot"
+version = "0.2.1"
+dependencies = [
+ "hayro-syntax",
+ "pdfcraft-cos",
+ "pdfcraft-fonts",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-automation"
+version = "0.2.1"
+dependencies = [
+ "base64 0.22.1",
+ "image",
+ "pdfcraft-engine",
+ "pdfcraft-organize",
+ "pdfcraft-render",
+ "png 0.18.1",
+ "serde_json",
+]
+
+[[package]]
+name = "pdfcraft-cli"
+version = "0.2.1"
+dependencies = [
+ "base64 0.22.1",
+ "pdfcraft-automation",
+ "pdfcraft-cos",
+ "pdfcraft-engine",
+ "pdfcraft-render",
+ "serde_json",
+]
+
+[[package]]
+name = "pdfcraft-compare"
+version = "0.2.1"
+
+[[package]]
+name = "pdfcraft-content"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-cos",
+]
+
+[[package]]
+name = "pdfcraft-cos"
+version = "0.2.1"
+dependencies = [
+ "hayro-syntax",
+ "pdfcraft-crypt",
+ "pdfcraft-filters",
+ "proptest",
+ "serde_json",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-create"
+version = "0.2.1"
+dependencies = [
+ "hayro-syntax",
+ "image",
+ "pdfcraft-cos",
+ "pdfcraft-fonts",
+ "pdfcraft-model",
+ "png 0.18.1",
+ "thiserror 2.0.21",
+ "tiff",
+]
+
+[[package]]
+name = "pdfcraft-crypt"
+version = "0.2.1"
+dependencies = [
+ "aes",
+ "md-5",
+ "proptest",
+ "sha2",
+ "stringprep",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-edit"
+version = "0.2.1"
+dependencies = [
+ "hayro-syntax",
+ "pdfcraft-annot",
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-fonts",
+ "pdfcraft-model",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-engine"
+version = "0.2.1"
+dependencies = [
+ "chrono",
+ "image",
+ "pdfcraft-a11y",
+ "pdfcraft-annot",
+ "pdfcraft-compare",
+ "pdfcraft-cos",
+ "pdfcraft-create",
+ "pdfcraft-edit",
+ "pdfcraft-export",
+ "pdfcraft-fonts",
+ "pdfcraft-forms",
+ "pdfcraft-js",
+ "pdfcraft-model",
+ "pdfcraft-ocr",
+ "pdfcraft-optimize",
+ "pdfcraft-organize",
+ "pdfcraft-preflight",
+ "pdfcraft-print",
+ "pdfcraft-redact",
+ "pdfcraft-render",
+ "pdfcraft-sign",
+ "pdfcraft-xfdf",
+ "png 0.18.1",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-export"
+version = "0.2.1"
+dependencies = [
+ "flate2",
+]
+
+[[package]]
+name = "pdfcraft-filters"
+version = "0.2.1"
+dependencies = [
+ "flate2",
+ "proptest",
+ "thiserror 2.0.21",
+ "weezl 0.2.1",
+]
+
+[[package]]
+name = "pdfcraft-fonts"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-cos",
+ "skrifa 0.44.0",
+]
+
+[[package]]
+name = "pdfcraft-forms"
+version = "0.2.1"
+dependencies = [
+ "hayro-syntax",
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-fonts",
+ "pdfcraft-model",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-geom"
+version = "0.2.1"
+
+[[package]]
+name = "pdfcraft-js"
+version = "0.2.1"
+dependencies = [
+ "boa_engine",
+]
+
+[[package]]
+name = "pdfcraft-model"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-cos",
+]
+
+[[package]]
+name = "pdfcraft-ocr"
+version = "0.2.1"
+dependencies = [
+ "ocrs",
+ "pdfcraft-fonts",
+ "rten",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-optimize"
+version = "0.2.1"
+dependencies = [
+ "image",
+ "pdfcraft-annot",
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-model",
+ "pdfcraft-render",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-organize"
+version = "0.2.1"
+dependencies = [
+ "hayro-syntax",
+ "pdfcraft-cos",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-preflight"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-cos",
+ "pdfcraft-model",
+]
+
+[[package]]
+name = "pdfcraft-print"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-model",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-redact"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-annot",
+ "pdfcraft-content",
+ "pdfcraft-cos",
+ "pdfcraft-edit",
+ "pdfcraft-fonts",
+ "pdfcraft-forms",
+ "pdfcraft-model",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-render"
+version = "0.2.1"
+dependencies = [
+ "getrandom 0.4.3",
+ "hayro",
+ "hayro-syntax",
+ "kurbo 0.13.1",
+ "log",
+ "lopdf",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-sign"
+version = "0.2.1"
+dependencies = [
+ "aes",
+ "aws-lc-rs",
+ "cbc",
+ "des",
+ "getrandom 0.4.3",
+ "hmac",
+ "p256",
+ "p384",
+ "pbkdf2",
+ "pdfcraft-annot",
+ "pdfcraft-cos",
+ "pdfcraft-fonts",
+ "rc2",
+ "rsa",
+ "security-framework",
+ "sha1",
+ "sha2",
+ "thiserror 2.0.21",
+]
+
+[[package]]
+name = "pdfcraft-ui-egui"
+version = "0.2.1"
+dependencies = [
+ "arboard",
+ "base64 0.22.1",
+ "eframe",
+ "egui",
+ "egui_extras",
+ "egui_kittest",
+ "getrandom 0.4.3",
+ "image",
+ "js-sys",
+ "log",
+ "pdfcraft-cos",
+ "pdfcraft-engine",
+ "pdfcraft-fonts",
+ "pdfcraft-model",
+ "pdfcraft-render",
+ "png 0.18.1",
+ "rfd",
+ "serde",
+ "serde_json",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "pdfcraft-web"
+version = "0.2.1"
+dependencies = [
+ "eframe",
+ "egui",
+ "js-sys",
+ "pdfcraft-ui-egui",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "pdfcraft-xfdf"
+version = "0.2.1"
+dependencies = [
+ "pdfcraft-annot",
+ "pdfcraft-cos",
+ "pdfcraft-forms",
+ "pdfcraft-model",
+ "roxmltree",
+ "thiserror 2.0.21",
+]
+
[[package]]
name = "pem-rfc7468"
version = "1.0.0"
@@ -3776,365 +4135,6 @@ dependencies = [
"wnaf",
]
-[[package]]
-name = "printcraft"
-version = "0.2.1"
-dependencies = [
- "eframe",
- "egui",
- "fmv-macos-events",
- "printcraft-ui-egui",
- "rustls-native-certs",
- "serde_json",
- "ureq",
- "winresource",
-]
-
-[[package]]
-name = "printcraft-a11y"
-version = "0.2.1"
-dependencies = [
- "printcraft-content",
- "printcraft-cos",
- "printcraft-model",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-annot"
-version = "0.2.1"
-dependencies = [
- "hayro-syntax",
- "printcraft-cos",
- "printcraft-fonts",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-automation"
-version = "0.2.1"
-dependencies = [
- "base64 0.22.1",
- "image",
- "png 0.18.1",
- "printcraft-engine",
- "printcraft-organize",
- "printcraft-render",
- "serde_json",
-]
-
-[[package]]
-name = "printcraft-cli"
-version = "0.2.1"
-dependencies = [
- "base64 0.22.1",
- "printcraft-automation",
- "printcraft-cos",
- "printcraft-engine",
- "printcraft-render",
- "serde_json",
-]
-
-[[package]]
-name = "printcraft-compare"
-version = "0.2.1"
-
-[[package]]
-name = "printcraft-content"
-version = "0.2.1"
-dependencies = [
- "printcraft-cos",
-]
-
-[[package]]
-name = "printcraft-cos"
-version = "0.2.1"
-dependencies = [
- "hayro-syntax",
- "printcraft-crypt",
- "printcraft-filters",
- "proptest",
- "serde_json",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-create"
-version = "0.2.1"
-dependencies = [
- "hayro-syntax",
- "image",
- "png 0.18.1",
- "printcraft-cos",
- "printcraft-fonts",
- "printcraft-model",
- "thiserror 2.0.21",
- "tiff",
-]
-
-[[package]]
-name = "printcraft-crypt"
-version = "0.2.1"
-dependencies = [
- "aes",
- "md-5",
- "proptest",
- "sha2",
- "stringprep",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-edit"
-version = "0.2.1"
-dependencies = [
- "hayro-syntax",
- "printcraft-annot",
- "printcraft-content",
- "printcraft-cos",
- "printcraft-fonts",
- "printcraft-model",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-engine"
-version = "0.2.1"
-dependencies = [
- "chrono",
- "image",
- "png 0.18.1",
- "printcraft-a11y",
- "printcraft-annot",
- "printcraft-compare",
- "printcraft-cos",
- "printcraft-create",
- "printcraft-edit",
- "printcraft-export",
- "printcraft-fonts",
- "printcraft-forms",
- "printcraft-js",
- "printcraft-model",
- "printcraft-ocr",
- "printcraft-optimize",
- "printcraft-organize",
- "printcraft-preflight",
- "printcraft-print",
- "printcraft-redact",
- "printcraft-render",
- "printcraft-sign",
- "printcraft-xfdf",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-export"
-version = "0.2.1"
-dependencies = [
- "flate2",
-]
-
-[[package]]
-name = "printcraft-filters"
-version = "0.2.1"
-dependencies = [
- "flate2",
- "proptest",
- "thiserror 2.0.21",
- "weezl 0.2.1",
-]
-
-[[package]]
-name = "printcraft-fonts"
-version = "0.2.1"
-dependencies = [
- "printcraft-cos",
- "skrifa 0.44.0",
-]
-
-[[package]]
-name = "printcraft-forms"
-version = "0.2.1"
-dependencies = [
- "hayro-syntax",
- "printcraft-content",
- "printcraft-cos",
- "printcraft-fonts",
- "printcraft-model",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-geom"
-version = "0.2.1"
-
-[[package]]
-name = "printcraft-js"
-version = "0.2.1"
-dependencies = [
- "boa_engine",
-]
-
-[[package]]
-name = "printcraft-model"
-version = "0.2.1"
-dependencies = [
- "printcraft-cos",
-]
-
-[[package]]
-name = "printcraft-ocr"
-version = "0.2.1"
-dependencies = [
- "ocrs",
- "printcraft-fonts",
- "rten",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-optimize"
-version = "0.2.1"
-dependencies = [
- "image",
- "printcraft-annot",
- "printcraft-content",
- "printcraft-cos",
- "printcraft-model",
- "printcraft-render",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-organize"
-version = "0.2.1"
-dependencies = [
- "hayro-syntax",
- "printcraft-cos",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-preflight"
-version = "0.2.1"
-dependencies = [
- "printcraft-cos",
- "printcraft-model",
-]
-
-[[package]]
-name = "printcraft-print"
-version = "0.2.1"
-dependencies = [
- "printcraft-content",
- "printcraft-cos",
- "printcraft-model",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-redact"
-version = "0.2.1"
-dependencies = [
- "printcraft-annot",
- "printcraft-content",
- "printcraft-cos",
- "printcraft-edit",
- "printcraft-fonts",
- "printcraft-forms",
- "printcraft-model",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-render"
-version = "0.2.1"
-dependencies = [
- "getrandom 0.4.3",
- "hayro",
- "hayro-syntax",
- "kurbo 0.13.1",
- "log",
- "lopdf",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-sign"
-version = "0.2.1"
-dependencies = [
- "aes",
- "aws-lc-rs",
- "cbc",
- "des",
- "getrandom 0.4.3",
- "hmac",
- "p256",
- "p384",
- "pbkdf2",
- "printcraft-annot",
- "printcraft-cos",
- "printcraft-fonts",
- "rc2",
- "rsa",
- "security-framework",
- "sha1",
- "sha2",
- "thiserror 2.0.21",
-]
-
-[[package]]
-name = "printcraft-ui-egui"
-version = "0.2.1"
-dependencies = [
- "arboard",
- "base64 0.22.1",
- "eframe",
- "egui",
- "egui_extras",
- "egui_kittest",
- "getrandom 0.4.3",
- "image",
- "js-sys",
- "log",
- "png 0.18.1",
- "printcraft-cos",
- "printcraft-engine",
- "printcraft-fonts",
- "printcraft-model",
- "printcraft-render",
- "rfd",
- "serde",
- "serde_json",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
-]
-
-[[package]]
-name = "printcraft-web"
-version = "0.2.1"
-dependencies = [
- "eframe",
- "egui",
- "js-sys",
- "printcraft-ui-egui",
- "wasm-bindgen-futures",
- "web-sys",
-]
-
-[[package]]
-name = "printcraft-xfdf"
-version = "0.2.1"
-dependencies = [
- "printcraft-annot",
- "printcraft-cos",
- "printcraft-forms",
- "printcraft-model",
- "roxmltree",
- "thiserror 2.0.21",
-]
-
[[package]]
name = "proc-macro-crate"
version = "3.5.0"
diff --git a/Cargo.toml b/Cargo.toml
index c94309e2..76be6e26 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,44 +2,44 @@
resolver = "3"
members = ["crates/*", "apps/*", "xtask"]
exclude = ["vendor"]
-default-members = ["crates/*", "apps/printcraft", "apps/printcraft-cli", "xtask"]
+default-members = ["crates/*", "apps/pdfcraft", "apps/pdfcraft-cli", "xtask"]
[workspace.package]
version = "0.2.1"
edition = "2024"
license = "MIT OR Apache-2.0"
rust-version = "1.90"
-repository = "https://github.com/storytold/printcraft"
+repository = "https://github.com/storytold/pdfcraft"
[workspace.dependencies]
# internal
-printcraft-geom = { path = "crates/geom", version = "0.2.0" }
-printcraft-filters = { path = "crates/filters", version = "0.2.0" }
-printcraft-cos = { path = "crates/cos", version = "0.2.0" }
-printcraft-crypt = { path = "crates/crypt", version = "0.2.0" }
-printcraft-organize = { path = "crates/organize", version = "0.2.0" }
-printcraft-annot = { path = "crates/annot", version = "0.2.0" }
-printcraft-fonts = { path = "crates/fonts", version = "0.2.0" }
-printcraft-model = { path = "crates/model", version = "0.2.0" }
-printcraft-content = { path = "crates/content", version = "0.2.0" }
-printcraft-redact = { path = "crates/redact", version = "0.2.0" }
-printcraft-print = { path = "crates/print", version = "0.2.0" }
-printcraft-xfdf = { path = "crates/xfdf", version = "0.2.0" }
-printcraft-sign = { path = "crates/sign", version = "0.2.0" }
-printcraft-optimize = { path = "crates/optimize", version = "0.2.0" }
-printcraft-a11y = { path = "crates/a11y", version = "0.2.0" }
-printcraft-ocr = { path = "crates/ocr", version = "0.2.0" }
-printcraft-js = { path = "crates/js", version = "0.2.0" }
-printcraft-compare = { path = "crates/compare", version = "0.2.0" }
-printcraft-preflight = { path = "crates/preflight", version = "0.2.0" }
-printcraft-export = { path = "crates/export", version = "0.2.0" }
-printcraft-edit = { path = "crates/edit", version = "0.2.0" }
-printcraft-create = { path = "crates/create", version = "0.2.0" }
-printcraft-forms = { path = "crates/forms", version = "0.2.0" }
-printcraft-render = { path = "crates/render", version = "0.2.0" }
-printcraft-engine = { path = "crates/engine", version = "0.2.0" }
-printcraft-ui-egui = { path = "crates/ui-egui", version = "0.2.0" }
-printcraft-automation = { path = "crates/automation", version = "0.2.0", default-features = false }
+pdfcraft-geom = { path = "crates/geom", version = "0.2.0" }
+pdfcraft-filters = { path = "crates/filters", version = "0.2.0" }
+pdfcraft-cos = { path = "crates/cos", version = "0.2.0" }
+pdfcraft-crypt = { path = "crates/crypt", version = "0.2.0" }
+pdfcraft-organize = { path = "crates/organize", version = "0.2.0" }
+pdfcraft-annot = { path = "crates/annot", version = "0.2.0" }
+pdfcraft-fonts = { path = "crates/fonts", version = "0.2.0" }
+pdfcraft-model = { path = "crates/model", version = "0.2.0" }
+pdfcraft-content = { path = "crates/content", version = "0.2.0" }
+pdfcraft-redact = { path = "crates/redact", version = "0.2.0" }
+pdfcraft-print = { path = "crates/print", version = "0.2.0" }
+pdfcraft-xfdf = { path = "crates/xfdf", version = "0.2.0" }
+pdfcraft-sign = { path = "crates/sign", version = "0.2.0" }
+pdfcraft-optimize = { path = "crates/optimize", version = "0.2.0" }
+pdfcraft-a11y = { path = "crates/a11y", version = "0.2.0" }
+pdfcraft-ocr = { path = "crates/ocr", version = "0.2.0" }
+pdfcraft-js = { path = "crates/js", version = "0.2.0" }
+pdfcraft-compare = { path = "crates/compare", version = "0.2.0" }
+pdfcraft-preflight = { path = "crates/preflight", version = "0.2.0" }
+pdfcraft-export = { path = "crates/export", version = "0.2.0" }
+pdfcraft-edit = { path = "crates/edit", version = "0.2.0" }
+pdfcraft-create = { path = "crates/create", version = "0.2.0" }
+pdfcraft-forms = { path = "crates/forms", version = "0.2.0" }
+pdfcraft-render = { path = "crates/render", version = "0.2.0" }
+pdfcraft-engine = { path = "crates/engine", version = "0.2.0" }
+pdfcraft-ui-egui = { path = "crates/ui-egui", version = "0.2.0" }
+pdfcraft-automation = { path = "crates/automation", version = "0.2.0", default-features = false }
# pdf
hayro = "0.7.1"
diff --git a/LICENSE-MIT b/LICENSE-MIT
index 8ba1dfe2..d2c0cd3f 100644
--- a/LICENSE-MIT
+++ b/LICENSE-MIT
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2026 ArtCraft Team and the PrintCraft contributors
+Copyright (c) 2026 ArtCraft Team and the PdfCraft contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/NOTICE b/NOTICE
index efe5186a..62e047ec 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
-PrintCraft
-Copyright (c) 2026 ArtCraft Team and the PrintCraft contributors.
+PdfCraft
+Copyright (c) 2026 ArtCraft Team and the PdfCraft contributors.
Licensed under the MIT License or the Apache License, Version 2.0, at your option
(LICENSE-MIT, LICENSE-APACHE).
diff --git a/README.md b/README.md
index 55fdeb4f..8b04e28c 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
-
PrintCraft
+
PdfCraft
The PDF workbench; an open-source, clean-room reimplementation of Adobe Acrobat, rebuilt in pure Rust.
@@ -28,7 +28,7 @@
-
+
- The PrintCraft Showcase, a 13-page specimen PDF, open with the All tools panel and threaded comments.
+ The PdfCraft Showcase, a 13-page specimen PDF, open with the All tools panel and threaded comments.
> [!NOTE]
@@ -65,13 +65,13 @@
## Community
-PrintCraft is part of [ArtCraft](https://getartcraft.com). Come say hello, get help and follow development:
+PdfCraft is part of [ArtCraft](https://getartcraft.com). Come say hello, get help and follow development:
- **Discord: [discord.gg/artcraft](https://discord.gg/artcraft)**. This is the fastest way to get help and share feedback. The app has a Discord button in its title bar.
-- **Web page:** [getartcraft.com/apps/printcraft](https://getartcraft.com/apps/printcraft)
-- **Source:** [github.com/storytold/printcraft](https://github.com/storytold/printcraft)
+- **Web page:** [getartcraft.com/apps/pdfcraft](https://getartcraft.com/apps/pdfcraft)
+- **Source:** [github.com/storytold/pdfcraft](https://github.com/storytold/pdfcraft)
-The ArtCraft name and logos in `docs/brand/` are trademarks of the ArtCraft Team and are not open source. They may be used only unmodified, and only as part of PrintCraft (see `docs/brand/LICENSE-brand.txt`). Forks and modified versions must remove them.
+The ArtCraft name and logos in `docs/brand/` are trademarks of the ArtCraft Team and are not open source. They may be used only unmodified, and only as part of PdfCraft (see `docs/brand/LICENSE-brand.txt`). Forks and modified versions must remove them.
## Highlights
@@ -102,10 +102,10 @@ No account, no telemetry, no cloud. It works offline and opens instantly. The en
## Read anything, beautifully
-PrintCraft renders PDFs with care for the details that make a page feel right: kerning and ligatures, right-to-left and complex scripts, vertical CJK, colour emoji, shadings, blend modes, soft masks and optional content.
+PdfCraft renders PDFs with care for the details that make a page feel right: kerning and ligatures, right-to-left and complex scripts, vertical CJK, colour emoji, shadings, blend modes, soft masks and optional content.
-
+ Twelve writing systems on one page, plus vertical Japanese, at 125%.
@@ -117,8 +117,8 @@ PrintCraft renders PDFs with care for the details that make a page feel right: k
-
-
+
+
Two-up Read mode, ready for long reading
@@ -136,8 +136,8 @@ Bookmarks, page thumbnails and the document's own page labels (i, ii, 1, 2…) k
-
-
+
+
Find as you type: match 10 of 16
@@ -155,7 +155,7 @@ Open **Organize pages** to see every page at once:
- **Undo anything:** ⌘Z, then save.
-
+ Organize pages with three pages selected and the page tools in the toolbar above.
@@ -171,10 +171,10 @@ Open **Organize pages** to see every page at once:
- *Atomic:* the file is written to a temporary copy, then swapped in.
- *Verified:* independently checked with qpdf.
-Unsaved documents carry a dot on their tab, and closing or quitting asks before anything is lost. Changes are autosaved every minute. If PrintCraft ever quits unexpectedly, it offers to recover your work the next time it opens. Encrypted documents stay encrypted on disk.
+Unsaved documents carry a dot on their tab, and closing or quitting asks before anything is lost. Changes are autosaved every minute. If PdfCraft ever quits unexpectedly, it offers to recover your work the next time it opens. Encrypted documents stay encrypted on disk.
-
Split document: one page per file makes 13 files.
+
Split document: one page per file makes 13 files.
@@ -193,25 +193,25 @@ Nothing quietly disappears along the way:
Every page of a combined document renders pixel-identical to its source.
```sh
-printcraft-cli combine report.pdf appendix.pdf --out combined.pdf
-printcraft-cli extract report.pdf --pages 1,3,5 --out highlights.pdf
-printcraft-cli split report.pdf --every 10 --out-dir parts/
+pdfcraft-cli combine report.pdf appendix.pdf --out combined.pdf
+pdfcraft-cli extract report.pdf --pages 1,3,5 --out highlights.pdf
+pdfcraft-cli split report.pdf --every 10 --out-dir parts/
```
---
## Open protected documents and respect their rules
-PrintCraft implements the PDF standard security handler completely:
+PdfCraft implements the PDF standard security handler completely:
- every revision, from 40-bit RC4 to AES-256;
- user and owner passwords, including Unicode passwords normalised with SASLprep;
- crypt filters and attachment-only encryption.
-Documents restricted by their author show a clear notice, and PrintCraft honours their permissions. Enter the owner password and the restrictions lift. Edits to encrypted documents are saved encrypted, under the same keys.
+Documents restricted by their author show a clear notice, and PdfCraft honours their permissions. Enter the owner password and the restrictions lift. Edits to encrypted documents are saved encrypted, under the same keys.
-
Document Properties, Description tab
+
Document Properties, Description tab
**Document Properties** shows:
@@ -228,8 +228,8 @@ Documents restricted by their author show a clear notice, and PrintCraft honours
-
-
+
+
Forms: every field with its current value, field highlighting, and checkboxes, radio buttons, lists and signatures drawn the way their author designed them.
@@ -243,8 +243,8 @@ Press ⌘K to search every tool and command, or browse the **All tool
-
-
+
+
The ⌘K command palette
@@ -259,12 +259,12 @@ Press ⌘K to search every tool and command, or browse the **All tool
- **Native on macOS, Windows, Linux and FreeBSD**, and **in the browser** through WebAssembly, from the same Rust codebase. Windows builds come for x64, x86 and ARM64 (Windows on ARM, no emulation); every ARM64 change is tested on ARM64 hardware in CI.
- **Private by design.** Documents never leave your machine. There's no account, no telemetry and no cloud processing.
- **Engine first.** Parsing, rendering and editing live in reusable library crates. The interface is one swappable layer on top.
-- **Scriptable.** The `printcraft-cli` tool (see [Built for agents, too](#built-for-agents-too)) covers inspecting, rendering, extracting text, editing, combining, extracting pages and splitting. Robustness sweeps run on the same engine as the app.
+- **Scriptable.** The `pdfcraft-cli` tool (see [Built for agents, too](#built-for-agents-too)) covers inspecting, rendering, extracting text, editing, combining, extracting pages and splitting. Robustness sweeps run on the same engine as the app.
```sh
-printcraft-cli info form.pdf # structure as JSON
-printcraft-cli text paper.pdf --page 3 # reading-order text
-printcraft-cli edit in.pdf --rotate 1,2:90 --delete 5 --title "Q3" --out out.pdf
+pdfcraft-cli info form.pdf # structure as JSON
+pdfcraft-cli text paper.pdf --page 3 # reading-order text
+pdfcraft-cli edit in.pdf --rotate 1,2:90 --delete 5 --title "Q3" --out out.pdf
```
---
@@ -273,59 +273,59 @@ printcraft-cli edit in.pdf --rotate 1,2:90 --delete 5 --title "Q3" --out out.pd
Every engine feature is reachable without the GUI, through one table of JSON-Schema-described tools: open, inspect, render pages to PNG, extract and find text, rotate, delete, move and insert pages, edit bookmarks and page labels, add, reply to, restyle and delete comments (highlight a phrase just by naming it), list and fill in form fields, protect with passwords, set metadata, undo and redo, save, combine, extract and split. Three front doors share it:
-- **`printcraft-cli run`**, for one-off calls and JSON scripts:
+- **`pdfcraft-cli run`**, for one-off calls and JSON scripts:
```sh
- printcraft-cli tools # every tool and its JSON Schema
- printcraft-cli run text_find doc=1 query=invoice # key=value; values parse as JSON
- printcraft-cli run --script review.json # e.g. comment_add {"type": "highlight", "find": "total due"}
- printcraft-cli run --script steps.json --root ./work # several steps in one session
+ pdfcraft-cli tools # every tool and its JSON Schema
+ pdfcraft-cli run text_find doc=1 query=invoice # key=value; values parse as JSON
+ pdfcraft-cli run --script review.json # e.g. comment_add {"type": "highlight", "find": "total due"}
+ pdfcraft-cli run --script steps.json --root ./work # several steps in one session
```
-- **An MCP server**, for AI agents such as Claude. **It is opt-in:** PrintCraft never starts it on its own, and it opens no network port. It runs only while an agent launches `printcraft-cli mcp`, talks over stdin/stdout, and stops when the agent disconnects. To enable it, add it to your agent's MCP configuration:
+- **An MCP server**, for AI agents such as Claude. **It is opt-in:** PdfCraft never starts it on its own, and it opens no network port. It runs only while an agent launches `pdfcraft-cli mcp`, talks over stdin/stdout, and stops when the agent disconnects. To enable it, add it to your agent's MCP configuration:
```json
- { "mcpServers": { "printcraft": { "command": "printcraft-cli", "args": ["mcp", "--root", "/path/to/your/pdfs"] } } }
+ { "mcpServers": { "pdfcraft": { "command": "pdfcraft-cli", "args": ["mcp", "--root", "/path/to/your/pdfs"] } } }
```
- `--root` confines every file the agent can read or write to one directory. Builds that should not include the server at all can use `cargo build -p printcraft-cli --no-default-features`.
+ `--root` confines every file the agent can read or write to one directory. Builds that should not include the server at all can use `cargo build -p pdfcraft-cli --no-default-features`.
-- **The Rust API** (`printcraft_automation::Automation::call`), for embedding.
+- **The Rust API** (`pdfcraft_automation::Automation::call`), for embedding.
Edits stay in memory, undoable, until `doc_save`. Saving to the same file appends an incremental update, so the original bytes are preserved, and the write is atomic. Unsaved changes are never discarded silently.
### Driving the app itself
-Start the desktop app with `printcraft --control /tmp/pc.json` and an agent can see and operate the real interface: the widget tree with labels and positions (from the accessibility tree), clicks, typing, keys, commands, view options and screenshots. This is also off by default. It listens only on loopback, and every connection must present the random token written to that file, which only you can read.
+Start the desktop app with `pdfcraft --control /tmp/pc.json` and an agent can see and operate the real interface: the widget tree with labels and positions (from the accessibility tree), clicks, typing, keys, commands, view options and screenshots. This is also off by default. It listens only on loopback, and every connection must present the random token written to that file, which only you can read.
```sh
-printcraft-cli ui --control /tmp/pc.json inspect query=rotate # find widgets
-printcraft-cli ui --control /tmp/pc.json click label="Organize pages"
-printcraft-cli ui --control /tmp/pc.json key key=K modifiers='["command"]'
-printcraft-cli ui --control /tmp/pc.json command id=comment.square # pick a tool, then draw:
-printcraft-cli ui --control /tmp/pc.json drag from='[400,300]' to='[600,420]'
-printcraft-cli ui --control /tmp/pc.json screenshot --out window.png
+pdfcraft-cli ui --control /tmp/pc.json inspect query=rotate # find widgets
+pdfcraft-cli ui --control /tmp/pc.json click label="Organize pages"
+pdfcraft-cli ui --control /tmp/pc.json key key=K modifiers='["command"]'
+pdfcraft-cli ui --control /tmp/pc.json command id=comment.square # pick a tool, then draw:
+pdfcraft-cli ui --control /tmp/pc.json drag from='[400,300]' to='[600,420]'
+pdfcraft-cli ui --control /tmp/pc.json screenshot --out window.png
```
---
## How it's built
-PrintCraft is a Cargo workspace of focused crates, layered so the core never depends on the UI:
+PdfCraft is a Cargo workspace of focused crates, layered so the core never depends on the UI:
| Crate | What it does |
|---|---|
-| `printcraft-filters` | Every PDF stream filter (Flate, LZW, ASCII85, RunLength, predictors), encode and decode, property-tested |
-| `printcraft-crypt` | The standard security handler: RC4, AES-128/256, revisions 2–6, permissions |
-| `printcraft-cos` | The PDF object layer: tolerant parsing, repair, copy-on-write edits, incremental and full writing |
-| `printcraft-organize` | Page operations, combine / extract / split, bookmarks, page labels, document information |
-| `printcraft-fonts` | Font metrics and encodings for generated appearances |
-| `printcraft-annot` | Comments: builders and appearance streams for notes, text markup, shapes, ink and text boxes; replies, status, edits |
-| `printcraft-forms` | Interactive forms: the field model, filling with regenerated appearances, Clear form |
-| `printcraft-render` | Rendering, inspection and text extraction with reading order |
-| `printcraft-engine` | The façade every frontend uses: sessions, edits, undo, saving, the tool catalogue |
-| `printcraft-automation` | Agent control: the headless tool table, `printcraft-cli run`, and the opt-in MCP server |
-| `printcraft-ui-egui` | The desktop and web interface |
+| `pdfcraft-filters` | Every PDF stream filter (Flate, LZW, ASCII85, RunLength, predictors), encode and decode, property-tested |
+| `pdfcraft-crypt` | The standard security handler: RC4, AES-128/256, revisions 2–6, permissions |
+| `pdfcraft-cos` | The PDF object layer: tolerant parsing, repair, copy-on-write edits, incremental and full writing |
+| `pdfcraft-organize` | Page operations, combine / extract / split, bookmarks, page labels, document information |
+| `pdfcraft-fonts` | Font metrics and encodings for generated appearances |
+| `pdfcraft-annot` | Comments: builders and appearance streams for notes, text markup, shapes, ink and text boxes; replies, status, edits |
+| `pdfcraft-forms` | Interactive forms: the field model, filling with regenerated appearances, Clear form |
+| `pdfcraft-render` | Rendering, inspection and text extraction with reading order |
+| `pdfcraft-engine` | The façade every frontend uses: sessions, edits, undo, saving, the tool catalogue |
+| `pdfcraft-automation` | Agent control: the headless tool table, `pdfcraft-cli run`, and the opt-in MCP server |
+| `pdfcraft-ui-egui` | The desktop and web interface |
**Quality gates.** Every change passes the same automated checks:
- formatting, and Clippy with warnings as errors;
@@ -339,14 +339,14 @@ On top of those, two corpus sweeps run over real-world files:
The output is verified with independent tools: hayro, qpdf and poppler.
-PrintCraft is a clean-room implementation. Its behaviour comes from the ISO 32000 specification and black-box observation, never from anyone else's code. Every icon, font and image is openly licensed and listed in [ATTRIBUTION.md](ATTRIBUTION.md).
+PdfCraft is a clean-room implementation. Its behaviour comes from the ISO 32000 specification and black-box observation, never from anyone else's code. Every icon, font and image is openly licensed and listed in [ATTRIBUTION.md](ATTRIBUTION.md).
## Get started
```sh
-git clone https://github.com/storytold/printcraft
-cd printcraft
-cargo run --release -p printcraft -- some.pdf # desktop app
+git clone https://github.com/storytold/pdfcraft
+cd pdfcraft
+cargo run --release -p pdfcraft -- some.pdf # desktop app
cargo xtask demo-pdf # build the showcase PDF used in these screenshots
cargo xtask screenshots # regenerate every screenshot in this README
```
@@ -357,12 +357,12 @@ edited PDFs):
```sh
git clone https://github.com/storytold/craft-fonts ../craft-fonts
-CRAFT_FONTS_DIR=../craft-fonts cargo run --release -p printcraft -- some.pdf
+CRAFT_FONTS_DIR=../craft-fonts cargo run --release -p pdfcraft -- some.pdf
```
## What's next
-PrintCraft is young and moving fast. The aim is a workbench where you can view, organize, annotate, fill, sign and edit PDFs, at parity with Acrobat Pro.
+PdfCraft is young and moving fast. The aim is a workbench where you can view, organize, annotate, fill, sign and edit PDFs, at parity with Acrobat Pro.
**Where it stands (October 2026), honestly:** about half of Acrobat Pro's offline features are in (88% of the must-haves), but that is roughly a third of the work, because the hardest parts are still ahead.
@@ -379,7 +379,7 @@ The honest assessment by area, what's lacking and where we're going are in **[RO
## The Crafting Apps
-PrintCraft is one of the **Crafting Apps**: free, open-source creative tools from the
+PdfCraft is one of the **Crafting Apps**: free, open-source creative tools from the
[ArtCraft](https://getartcraft.com/) team, each written from scratch in Rust and each able to
stand on its own.
@@ -389,7 +389,7 @@ stand on its own.
| | **VectorCraft** | Vector illustration | [GitHub](https://github.com/storytold/vectorcraft) | [Website](https://getartcraft.com/apps/vectorcraft) |
| | **FilmCraft** | Video editing, color and sound | [GitHub](https://github.com/storytold/filmcraft) | [Website](https://getartcraft.com/apps/filmcraft) |
| | **LightCraft** | Photo library and raw development | [GitHub](https://github.com/storytold/lightcraft) | [Website](https://getartcraft.com/apps/lightcraft) |
-| | **PrintCraft** | **Reading, organizing and protecting PDFs · you are here** | [GitHub](https://github.com/storytold/printcraft) | [Website](https://getartcraft.com/apps/printcraft) |
+| | **PdfCraft** | **Reading, organizing and protecting PDFs · you are here** | [GitHub](https://github.com/storytold/pdfcraft) | [Website](https://getartcraft.com/apps/pdfcraft) |
| | **EffectCraft** | Motion graphics and visual effects | [GitHub](https://github.com/storytold/effectcraft) | [Website](https://getartcraft.com/apps/effectcraft) |
| | **DesignCraft** | Page layout and publishing | [GitHub](https://github.com/storytold/designcraft) | [Website](https://getartcraft.com/apps/designcraft) |
@@ -414,15 +414,15 @@ And [**ArtCraft**](https://getartcraft.com/) itself, our AI image and video stud
discord.gg/artcraft ·
getartcraft.com ·
The Crafting Apps ·
- PrintCraft
+ PdfCraft
---
## License and credits
-PrintCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option.
-Copyright (c) 2026 ArtCraft Team and the PrintCraft contributors. Required notices are in [NOTICE](NOTICE).
+PdfCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option.
+Copyright (c) 2026 ArtCraft Team and the PdfCraft contributors. Required notices are in [NOTICE](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](ATTRIBUTION.md). Release builds also embed
@@ -431,10 +431,10 @@ the Japanese fonts of [craft-fonts](https://github.com/storytold/craft-fonts/blo
The ArtCraft name, wordmark and logos in [`docs/brand/`](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 PrintCraft, under [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt).
+part of this repository and PdfCraft, under [`docs/brand/LICENSE-brand.txt`](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. PrintCraft 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.
+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. PdfCraft 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.
diff --git a/ROADMAP.md b/ROADMAP.md
index daa7c7b1..52fc9925 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -1,4 +1,4 @@
-# PrintCraft roadmap
+# PdfCraft roadmap
The milestones, current progress and time estimates to Acrobat Pro feature parity. Keep this up to date:
- **Every session:** update the progress column and add a line to the log.
@@ -6,7 +6,7 @@ The milestones, current progress and time estimates to Acrobat Pro feature parit
Detailed task lists and acceptance tests are in `plan/execution-plan.md` (local-only). This file is the public summary.
-**What "parity" means here:** the offline feature set of Acrobat Pro, milestones M0–M14. It excludes Adobe's cloud services (Document Cloud storage, Adobe Sign, the Adobe AI Assistant). Those have no clean-room equivalent; PrintCraft's alternatives are local-first, plus opt-in providers (M13).
+**What "parity" means here:** the offline feature set of Acrobat Pro, milestones M0–M14. It excludes Adobe's cloud services (Document Cloud storage, Adobe Sign, the Adobe AI Assistant). Those have no clean-room equivalent; PdfCraft's alternatives are local-first, plus opt-in providers (M13).
## Estimate summary
@@ -127,6 +127,7 @@ M0 → M1 → M2 → M3 → M4 must happen in order. After M4, M5–M12 can run
Newest first. One line per session: the date, what moved, and the new overall percentage.
+- **2026-10-07 (session 16):** PrintCraft is renamed PdfCraft: repo `storytold/pdfcraft`, crates and binaries `pdfcraft*`, bundle id `ai.storyteller.pdfcraft`. On first launch the app moves the old PrintCraft settings and crash-recovery folders to the new name, so upgrades keep recent files, preferences and unsaved work. No feature change. ≈ 30–35%.
- **2026-10-07 (session 15):** Five community issues, each with a regression test: in two-page view, Next page moves a whole spread (#77, #70); Export to Word opens in Word again, with control characters dropped and receipt-length pages kept within Word's 22 in, checked in Microsoft Word (#78, #72); macOS opens PDFs from Finder, Open With and the Dock (Apple events through the audited `fmv-macos-events`, PDF declared in the Info.plist), and the packaging no longer describes the image editor it was copied from (#82, #73); Add text keeps the box being typed when you click elsewhere, with Done and Discard beside it, reproduced and checked with real OS input (#86, #74); sharper, higher-contrast text, most visible on Windows, with every text colour at WCAG AA in both themes (#84, #76; the console window was already gone in 0.2.1). Still open: #79 (layered "not verified" signature appearances), #80 (native macOS menu bar), #81 (Homebrew and Scoop). P0 88%, P1 53%; 805 features 50.2% shipped (53.7% weighted). ≈ 30–35%.
- **2026-10-06 (session 14):** Issues: move and resize existing text boxes in Edit text (#59, closes #40); Windows release builds open no console window and the Start Menu shortcut has its icon (#58, #57; rolled out to every Craft app); native Windows ARM64 installers, installed and run on an ARM64 runner in CI (#66, #71; the intermittent ARM64 test crash was a WARP shader-JIT race between parallel GPU-rendering tests, not our code); XFA forms are detected and explained instead of failing silently (#65, #60 stays open for real XFA). Also: squiggly underline tool, comment opacity, Preferences ▸ Identity, drag-and-drop/hover tests; community table export to Word/HTML/RTF (#62, with linear-time detection and a column cap). #63 (timestamps/LTV with outbound network) held for review fixes and an owner decision on network access. ≈ 30–35% (unchanged).
- **2026-10-05 (session 13, later):** FreeBSD: CI builds and tests the workspace in a FreeBSD 14.3 VM (#45) and the release ships a FreeBSD x86_64 tarball, checked in CI (#42); README lists FreeBSD. Fuzzing: the nightly job's 11 hangs fixed (#41: our parser's exponential retries, inline images, Type 3 fan-out), plus a JBIG2 hang (#43, vendored hayro-jbig2) and a Type 1 font stack overflow (#46, skrifa 0.47); a full run now finds 0 crashes. Landed community PRs #36 (text editing, Japanese replacements), #47 (English/Japanese interface) and #48 (XFDF colour crash). Windows launch crash with Intel's Vulkan driver fixed by using Direct3D 12 (#49, issue #37); one copy of the Japanese font instead of two (#51, −8.3 MB); full screen and About get real tests (#50). P0 88%, P1 52%. ≈ 30–35%.
@@ -174,7 +175,7 @@ Newest first. One line per session: the date, what moved, and the new overall pe
- Overall ≈ 9.5%.
- **2026-09-30 (session 5, after a machine crash; no work lost):**
- - Agent control: new `printcraft-automation` crate with 20 JSON-Schema tools, an opt-in MCP server (`printcraft-cli mcp`, stdio only, can be compiled out), and `printcraft-cli run`/`tools`.
+ - Agent control: new `pdfcraft-automation` crate with 20 JSON-Schema tools, an opt-in MCP server (`pdfcraft-cli mcp`, stdio only, can be compiled out), and `pdfcraft-cli run`/`tools`.
- Text on rotated pages now reads along its lines; the pdf.js oracle is unchanged at median 0.980.
- Finding text in 520 pages: 17.9 s → 3.7 s (parallel), about 20 ms when repeated (cached).
- CI: dependency licence audit (`deny.toml`, `xtask deny`) and a GitHub workflow for macOS, Windows, Linux and wasm.
diff --git a/apps/pdfcraft-cli/Cargo.toml b/apps/pdfcraft-cli/Cargo.toml
new file mode 100644
index 00000000..d2add5d7
--- /dev/null
+++ b/apps/pdfcraft-cli/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "pdfcraft-cli"
+description = "PdfCraft command-line tool: inspect, render and robustness-check PDFs"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+
+[[bin]]
+name = "pdfcraft-cli"
+path = "src/main.rs"
+
+[lints]
+workspace = true
+
+[dependencies]
+pdfcraft-render = { workspace = true }
+serde_json = { workspace = true }
+pdfcraft-engine = { workspace = true }
+pdfcraft-cos = { workspace = true }
+pdfcraft-automation = { workspace = true }
+base64 = "0.22"
+
+[features]
+default = ["mcp"]
+# The opt-in MCP server (`pdfcraft-cli mcp`). Build with --no-default-features to leave it out.
+mcp = ["pdfcraft-automation/mcp"]
diff --git a/apps/printcraft-cli/src/main.rs b/apps/pdfcraft-cli/src/main.rs
similarity index 86%
rename from apps/printcraft-cli/src/main.rs
rename to apps/pdfcraft-cli/src/main.rs
index f703f676..6e79ffe3 100644
--- a/apps/printcraft-cli/src/main.rs
+++ b/apps/pdfcraft-cli/src/main.rs
@@ -1,24 +1,24 @@
-//! printcraft-cli — headless PrintCraft.
+//! pdfcraft-cli — headless PdfCraft.
//!
//! ```text
-//! printcraft-cli info [--password PW] document summary as JSON
-//! printcraft-cli render --page N [--dpi 96] --out x.pam
-//! printcraft-cli text [--page N] extracted text (pages separated by form feeds)
-//! printcraft-cli edit --out out.pdf [--rotate 1,3:90] [--delete 2,4] [--move 5:1]
+//! pdfcraft-cli info [--password PW] document summary as JSON
+//! pdfcraft-cli render --page N [--dpi 96] --out x.pam
+//! pdfcraft-cli text [--page N] extracted text (pages separated by form feeds)
+//! pdfcraft-cli edit --out out.pdf [--rotate 1,3:90] [--delete 2,4] [--move 5:1]
//! [--insert-blank 1] [--title T] [--author A] [--full]
-//! printcraft-cli combine … --out combined.pdf
-//! printcraft-cli extract --pages 1,3,5 --out out.pdf
-//! printcraft-cli split (--every N | --before 3,7) [--out-dir DIR]
-//! printcraft-cli check [--timeout 20] [--dpi 36] [--json out.json]
-//! printcraft-cli tools automation tools and their JSON Schemas
-//! printcraft-cli run [key=value …] [--root DIR] [--out image.png]
-//! printcraft-cli run --script steps.json [--root DIR] [{"tool": "doc_open", "args": {…}}, …]
-//! printcraft-cli mcp [--root DIR] MCP server on stdin/stdout (opt-in)
-//! printcraft-cli ui --control FILE [key=value …] [--out shot.png]
+//! pdfcraft-cli combine … --out combined.pdf
+//! pdfcraft-cli extract --pages 1,3,5 --out out.pdf
+//! pdfcraft-cli split (--every N | --before 3,7) [--out-dir DIR]
+//! pdfcraft-cli check [--timeout 20] [--dpi 36] [--json out.json]
+//! pdfcraft-cli tools automation tools and their JSON Schemas
+//! pdfcraft-cli run [key=value …] [--root DIR] [--out image.png]
+//! pdfcraft-cli run --script steps.json [--root DIR] [{"tool": "doc_open", "args": {…}}, …]
+//! pdfcraft-cli mcp [--root DIR] MCP server on stdin/stdout (opt-in)
+//! pdfcraft-cli ui --control FILE [key=value …] [--out shot.png]
//! drive a running app started with --control FILE
//! ```
//!
-//! `run` and `mcp` drive the same tool table (`printcraft-automation`). In `run`, values parse as
+//! `run` and `mcp` drive the same tool table (`pdfcraft-automation`). In `run`, values parse as
//! JSON when they can (`pages=[1,3]`, `degrees=90`) and are strings otherwise. A script runs its
//! steps in one session, so `doc_open` returns id 1, the next document id 2, and so on.
//!
@@ -37,7 +37,7 @@ use std::process::{Command, ExitCode, Stdio};
use std::sync::Arc;
use std::time::{Duration, Instant};
-use printcraft_render::{PageRenderer, RenderConfig, RenderRequest, RequestKind, inspect};
+use pdfcraft_render::{PageRenderer, RenderConfig, RenderRequest, RequestKind, inspect};
fn main() -> ExitCode {
let args: Vec = std::env::args().skip(1).collect();
@@ -58,19 +58,19 @@ fn main() -> ExitCode {
#[cfg(feature = "mcp")]
Some("mcp") => mcp(&args[1..]),
Some("--version") => {
- println!("printcraft-cli {}", env!("CARGO_PKG_VERSION"));
- println!("Discord: {} (help and feedback)", printcraft_engine::links::DISCORD);
- println!("Web: {}", printcraft_engine::links::APP_PAGE);
- println!("Source: {}", printcraft_engine::links::GITHUB);
+ println!("pdfcraft-cli {}", env!("CARGO_PKG_VERSION"));
+ println!("Discord: {} (help and feedback)", pdfcraft_engine::links::DISCORD);
+ println!("Web: {}", pdfcraft_engine::links::APP_PAGE);
+ println!("Source: {}", pdfcraft_engine::links::GITHUB);
Ok(())
}
- _ => Err("usage: printcraft-cli … (see source header for options)\nhelp and feedback: https://discord.gg/artcraft"
+ _ => Err("usage: pdfcraft-cli … (see source header for options)\nhelp and feedback: https://discord.gg/artcraft"
.into()),
};
match result {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
- eprintln!("printcraft-cli: {e}");
+ eprintln!("pdfcraft-cli: {e}");
ExitCode::FAILURE
}
}
@@ -112,7 +112,7 @@ fn info(args: &[String]) -> Result<(), String> {
"first_page_pt": info.pages.first().map(|p| [p.width, p.height]),
"title": info.title, "author": info.author, "producer": info.producer, "creator": info.creator,
"encrypted": info.encrypted, "tagged": info.tagged, "javascript": info.has_javascript,
- "xfa": info.xfa.map(|x| match x { printcraft_render::Xfa::Static => "static", printcraft_render::Xfa::Dynamic => "dynamic" }),
+ "xfa": info.xfa.map(|x| match x { pdfcraft_render::Xfa::Static => "static", pdfcraft_render::Xfa::Dynamic => "dynamic" }),
"bookmarks": info.outline.len(), "annotations": info.annotations.len(), "fields": info.fields.len(),
"links": info.links.len(), "layers": info.layers.len(), "attachments": info.attachments.len(),
"page_labels": info.pages.iter().take(8).map(|p| p.label.clone()).collect::>(),
@@ -150,7 +150,7 @@ fn page_list(s: &str) -> Result, String> {
/// Apply page and metadata edits through the engine and save (incrementally unless `--full`).
fn edit(args: &[String]) -> Result<(), String> {
- use printcraft_engine::{Edit, Session};
+ use pdfcraft_engine::{Edit, Session};
let path = *positional(args).first().ok_or("edit: missing file")?;
let out = flag(args, "--out").ok_or("edit: missing --out")?;
let mut session = Session::new();
@@ -198,7 +198,7 @@ fn combine(args: &[String]) -> Result<(), String> {
return Err("combine: give at least two input files".into());
}
let sources = inputs.iter().map(|p| Ok((file_stem(p), read(p)?))).collect::, String>>()?;
- let bytes = printcraft_engine::Session::new().combine(&sources).map_err(|e| e.to_string())?;
+ let bytes = pdfcraft_engine::Session::new().combine(&sources).map_err(|e| e.to_string())?;
std::fs::write(out, bytes.as_slice()).map_err(|e| format!("{out}: {e}"))
}
@@ -206,14 +206,14 @@ fn extract(args: &[String]) -> Result<(), String> {
let path = *positional(args).first().ok_or("extract: missing file")?;
let out = flag(args, "--out").ok_or("extract: missing --out")?;
let pages = page_list(flag(args, "--pages").ok_or("extract: missing --pages")?)?;
- let mut session = printcraft_engine::Session::new();
+ let mut session = pdfcraft_engine::Session::new();
let id = session.open(path, None, read(path)?, flag(args, "--password")).map_err(|e| e.to_string())?;
let bytes = session.extract(id, &pages).map_err(|e| e.to_string())?;
std::fs::write(out, bytes.as_slice()).map_err(|e| format!("{out}: {e}"))
}
fn split(args: &[String]) -> Result<(), String> {
- use printcraft_engine::SplitBy;
+ use pdfcraft_engine::SplitBy;
let path = *positional(args).first().ok_or("split: missing file")?;
let by = match (flag(args, "--every"), flag(args, "--before")) {
(Some(n), None) => SplitBy::PageCount(n.parse().map_err(|_| "bad --every")?),
@@ -221,7 +221,7 @@ fn split(args: &[String]) -> Result<(), String> {
_ => return Err("split: give either --every N or --before PAGES".into()),
};
let dir = PathBuf::from(flag(args, "--out-dir").unwrap_or("."));
- let mut session = printcraft_engine::Session::new();
+ let mut session = pdfcraft_engine::Session::new();
let id = session.open(path, None, read(path)?, flag(args, "--password")).map_err(|e| e.to_string())?;
let stem = file_stem(path);
for (a, b, bytes) in session.split(id, &by).map_err(|e| e.to_string())? {
@@ -288,7 +288,7 @@ fn check_one(args: &[String]) -> Result<(), String> {
/// Open with cos, touch every object, edit the catalog, save incrementally and in full (both
/// output styles), and reopen each result. Errors are fine; panics, hangs and aborts are bugs.
fn edit_round_trip(bytes: &[u8]) {
- use printcraft_cos::{Document, Object, SaveOptions, write_full, write_incremental};
+ use pdfcraft_cos::{Document, Object, SaveOptions, write_full, write_incremental};
let Ok(mut doc) = Document::open(Arc::new(bytes.to_vec())) else { return };
for num in doc.object_numbers().into_iter().take(20_000) {
if let Ok(o) = doc.try_get(num)
@@ -298,7 +298,7 @@ fn edit_round_trip(bytes: &[u8]) {
}
}
if let Some(root) = doc.root() {
- let _ = doc.update_dict(root, |d| d.set(b"PrintCraftFuzz".to_vec(), Object::Bool(true)));
+ let _ = doc.update_dict(root, |d| d.set(b"PdfCraftFuzz".to_vec(), Object::Bool(true)));
}
let classic = SaveOptions { object_streams: false, ..SaveOptions::default() };
for out in [write_incremental(&doc, &SaveOptions::default()), write_full(&doc, &SaveOptions::default()), write_full(&doc, &classic)]
@@ -397,8 +397,8 @@ fn run_child(exe: &Path, file: &Path, dpi: &str, timeout: Duration) -> serde_jso
// ---- automation --------------------------------------------------------------------------------
-fn automation(args: &[String]) -> Result {
- let a = printcraft_automation::Automation::new();
+fn automation(args: &[String]) -> Result {
+ let a = pdfcraft_automation::Automation::new();
match flag(args, "--root") {
Some(root) => a.with_root(root).map_err(|e| format!("--root {root}: {e}")),
None => Ok(a),
@@ -406,7 +406,7 @@ fn automation(args: &[String]) -> Result Result<(), String> {
- let list: Vec = printcraft_automation::tools()
+ let list: Vec = pdfcraft_automation::tools()
.iter()
.map(|t| serde_json::json!({ "name": t.name, "description": t.description, "read_only": t.read_only, "command": t.command, "input_schema": t.input_schema }))
.collect();
@@ -415,11 +415,11 @@ fn tools() -> Result<(), String> {
}
/// Print a tool's result: JSON as JSON; images go to `--out` (or are summarised).
-fn print_output(content: Vec, out: Option<&str>) -> Result<(), String> {
+fn print_output(content: Vec, out: Option<&str>) -> Result<(), String> {
for c in content {
match c {
- printcraft_automation::Content::Json(v) => println!("{}", serde_json::to_string_pretty(&v).unwrap_or_default()),
- printcraft_automation::Content::Png { data, width, height } => match out {
+ pdfcraft_automation::Content::Json(v) => println!("{}", serde_json::to_string_pretty(&v).unwrap_or_default()),
+ pdfcraft_automation::Content::Png { data, width, height } => match out {
Some(path) => {
std::fs::write(path, &data).map_err(|e| format!("{path}: {e}"))?;
println!("{}", serde_json::json!({ "image": path, "width": width, "height": height }));
@@ -446,7 +446,7 @@ fn run(args: &[String]) -> Result<(), String> {
}
return Ok(());
}
- let tool = *positional(args).first().ok_or("run: missing tool name (see `printcraft-cli tools`)")?;
+ let tool = *positional(args).first().ok_or("run: missing tool name (see `pdfcraft-cli tools`)")?;
let mut obj = serde_json::Map::new();
for kv in positional(args).iter().skip(1) {
let (k, v) = kv.split_once('=').ok_or(format!("run: expected key=value, got {kv:?}"))?;
@@ -459,17 +459,17 @@ fn run(args: &[String]) -> Result<(), String> {
#[cfg(feature = "mcp")]
fn mcp(args: &[String]) -> Result<(), String> {
- let mut server = printcraft_automation::mcp::McpServer::new(automation(args)?);
- eprintln!("printcraft-cli: MCP server on stdio (protocol {}); close stdin to stop", printcraft_automation::mcp::PROTOCOL_VERSIONS[0]);
+ let mut server = pdfcraft_automation::mcp::McpServer::new(automation(args)?);
+ eprintln!("pdfcraft-cli: MCP server on stdio (protocol {}); close stdin to stop", pdfcraft_automation::mcp::PROTOCOL_VERSIONS[0]);
server.serve(std::io::stdin().lock(), std::io::stdout().lock()).map_err(|e| e.to_string())
}
// ---- UI control channel client -----------------------------------------------------------------
-/// One request to a running app's control channel (`printcraft --control FILE`).
+/// One request to a running app's control channel (`pdfcraft --control FILE`).
fn ui(args: &[String]) -> Result<(), String> {
use std::io::{BufRead, BufReader, Write as _};
- let file = flag(args, "--control").ok_or("ui: missing --control FILE (start the app with `printcraft --control FILE`)")?;
+ let file = flag(args, "--control").ok_or("ui: missing --control FILE (start the app with `pdfcraft --control FILE`)")?;
let info: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(file).map_err(|e| format!("{file}: {e}"))?).map_err(|e| format!("{file}: {e}"))?;
let port = info["port"].as_u64().ok_or(format!("{file}: no port"))?;
diff --git a/apps/printcraft-web/Cargo.toml b/apps/pdfcraft-web/Cargo.toml
similarity index 75%
rename from apps/printcraft-web/Cargo.toml
rename to apps/pdfcraft-web/Cargo.toml
index dc7ad99c..a8d472d4 100644
--- a/apps/printcraft-web/Cargo.toml
+++ b/apps/pdfcraft-web/Cargo.toml
@@ -1,6 +1,6 @@
[package]
-name = "printcraft-web"
-description = "PrintCraft in the browser (wasm32; build with `trunk build --release` in this directory)"
+name = "pdfcraft-web"
+description = "PdfCraft in the browser (wasm32; build with `trunk build --release` in this directory)"
version.workspace = true
edition.workspace = true
license.workspace = true
@@ -10,7 +10,7 @@ publish = false
workspace = true
[dependencies]
-printcraft-ui-egui = { workspace = true }
+pdfcraft-ui-egui = { workspace = true }
eframe = { workspace = true, features = ["default_fonts", "glow", "persistence", "accesskit"] }
egui = { workspace = true }
diff --git a/apps/printcraft-web/Trunk.toml b/apps/pdfcraft-web/Trunk.toml
similarity index 77%
rename from apps/printcraft-web/Trunk.toml
rename to apps/pdfcraft-web/Trunk.toml
index 7a307477..563c2267 100644
--- a/apps/printcraft-web/Trunk.toml
+++ b/apps/pdfcraft-web/Trunk.toml
@@ -1,4 +1,4 @@
-# Build with: trunk build --release (from apps/printcraft-web)
+# Build with: trunk build --release (from apps/pdfcraft-web)
# The release zip (packaging/web/package.sh) expects the site in dist/web with relative URLs.
[build]
target = "index.html"
diff --git a/apps/printcraft-web/index.html b/apps/pdfcraft-web/index.html
similarity index 88%
rename from apps/printcraft-web/index.html
rename to apps/pdfcraft-web/index.html
index 5980e367..46b3a25e 100644
--- a/apps/printcraft-web/index.html
+++ b/apps/pdfcraft-web/index.html
@@ -3,7 +3,7 @@
- PrintCraft
+ PdfCraft
-
+