16 Commits
Author SHA1 Message Date
dotCooCoo 3374d0778d Scripts: Check Script… reports what a .jsx script needs and does, without running it
VectorCraft does not run scripts written for the reference app, and
File › Scripts held only the disabled Other Script…. File › Scripts ›
Check Script… picks a .jsx, .jsxinc or .jsxbin file, reads it without
running any of it, and shows a report: what the script needs (the
script language's own objects, the document model, files, menu
commands, dialogs, or features only the reference app has), what it
would do outside the document, the menu-command strings it passes, the
document-model member chains and type names it uses, its directives,
the files it includes, and the problems that would stop it loading.
Copy Report copies the report as JSON. File › Open and drag-and-drop
show the report for those files too.

- vectorcraft-scriptcheck, a new Standalone crate with no
  dependencies, holds the checker: a lexer for ECMAScript 3 with E4X
  literals and the #name and //@name directive lines, and an analysis
  of the tokens that follows variables, function scopes and the files
  a script includes. It never recurses: open brackets, the levels of
  an XML literal and the function bodies being read are kept on stacks
  capped at 4,096. It reads at most 8 MiB of a file and 32 MiB with the
  included files, follows 64 included files 16 deep, looks up at most
  1,024 paths for them, keeps 1,000 entries in a list, tracks 1,000
  variables holding member chains and 1,000 holding File objects, and
  cuts echoed text to 120 characters. A compiled script is reported as
  compiled and isn't read.
- script.check (engine, a query) takes path, data or dataBase64. With a
  path and includes: true, it reads the files the #include lines name
  from inside the script's folder, through the automation read root,
  and when the script or one of those files assigns a member chain or a
  File object to a variable, the check treats the variable as holding
  it in every file. It doesn't follow absolute names, names, folders or
  links that lead out of the folder, names or folders longer than 4,096
  bytes, or JSINCLUDE, and it reads only regular files.
- ui.checkScript shows the report (dialog scriptCheck). File › Open
  lists Scripts (.jsx, .jsxinc, .jsxbin) and sends a script's path to
  script.check, which reads at most 8 MiB of it.

The language rules come from ECMA-262 3rd edition and ECMA-357 2nd
edition. The directive, platform and document-model root names come
from the public JavaScript Tools Guide and scripting guide pages that
catalog.rs cites by URL, and executeMenuCommand, doScript, loadAction,
unloadAction and selectTool come from the public forum posts cited
there; only names are used. Every script in the tests is written from
scratch with invented names.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-13 13:36:41 +07:00
Matthew FarrowandClaude Sonnet 5.5 ec43ac5a1e Read Illustrator EPS and .ai layers from their editing data
An Illustrator EPS is a flattened page plus, after %%EOF, an editing copy of
the document; a PDF-compatible .ai carries the same in its private data.
Importing only the page lost layer names, order, visibility, hidden layers
and hidden objects and hidden text.

- eps: read the editing copy (Zstandard %AI24_DataStream, older zlib
  %AI9_DataStream) into layers, sublayers, groups, compound paths, clip
  groups and hidden objects, run by the existing PostScript interpreter.
  Falls back to the page, with a warning, when a shown layer uses an
  operator that isn't read or the art differs from the page by over 5%.
- eps: read the text document (ate.rs) to place type on hidden layers and
  objects; the page's type is matched to the file's text objects by
  position (pieces of a line included) and kept with the nearest one when
  none claims it. Area type and type on a path are left out with a note.
- pdf/engine: .ai files go through the same reader.
- engine/cli: a file whose import left things out isn't overwritten unless
  asked (acknowledgeLoss, --replace-lossy).
- eps: font names re-encoded with a *<n> suffix resolve to their family.
- i18n: es/it/ru for the new import messages; ROADMAP updated.

Container and text-document formats were inferred from user-owned files; the
Adobe file format specification was not read.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-09 03:49:49 -04:00
callmeBallochandClaude Opus 5.5 297a01b6aa AF.3: native Affinity import with artboards, vectors, text and images
Open and Place read Affinity documents natively (.af from Affinity 3,
.afdesign/.afphoto/.afpub from Affinity 1 and 2): layers and sublayers,
groups, artboards with their names and backgrounds, Publisher pages side
by side, curves with live corners, parametric shapes, compound shapes,
clipping by nesting, vector and pixel masks, solid and gradient fills,
strokes, fill layers, artistic and frame text, placed images (their
original JPEG/PNG), pixel layers, embedded documents as their cached
picture, opacity, visibility, locking and blend modes, at the document's
resolution in points. Unsupported content (effects, adjustments, brushes,
master pages, special shapes, Affinity-only blend modes...) is listed in
the import warning, one line per kind. A file whose native data can't be
read opens as its embedded preview with the reason, and that preview
cannot be placed or used as a template or library. Save never writes back
over the Affinity file and there is no Affinity export.

The document semantics were fitted to the thumbnails Affinity embeds in
176 public documents. `cargo xtask corpus --affinity` fetches 22 public
CC0/MIT/Apache-2.0 documents at pinned commits, sha256-verified; the new
engine test renders each and compares it with Affinity's own thumbnail
(0-4.4 of 255 mean difference, per-file ceilings). import_fuzz mutates a
synthetic native document's stream and container through open, render
and export; the fuzz crate gains a stream target.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-08 17:58:11 +00:00
callmeBalloch 3c7bdfe6a3 AF.1: import bounded Affinity previews with explicit fidelity warnings
Read only the indexed PNG thumbnail observed in version-12 Affinity containers. Bound and validate the PNG before decoding, warn about omitted native content, clear the source save target, and reject auxiliary imports that cannot display that warning. Add malformed-input, lifecycle, property and optional native-oracle tests plus a fuzz target. Editable native layers and Affinity export remain unsupported.
2026-10-08 17:19:18 +02:00
bflatasticandClaude Opus 5.5 811ad1efd8 Fix #121: sandboxed WebAssembly plug-ins: object filters and live effects
VectorCraft had an Additional Plug-ins Folder preference but nothing loaded from it. Port
PhotoCraft's wasmi plug-in host (same sandbox, manifest and parameter schema) as the new
vectorcraft-plugins crate (L2), extended for vector documents:

- Object filters read the selected paths and compound paths as JSON (native PathData and
  Paint forms: geometry, fills, strokes, gradients, opacity) and return the objects to keep,
  change, add or delete; the output is validated in full and applied as one undo step
  (plugin.run). A failing plug-in leaves the document untouched.
- Live-effect plug-ins are geometry effects in the appearance stack (effect id
  plugin.<id>), re-evaluated (and cached) when the object or parameters change, editable,
  exported and baked by Expand Appearance; a missing plug-in leaves the geometry as is.
- plugin.list / info / run / install / remove / reload; the preference folder installs
  every *.wasm at startup and when it changes; File > Open of a .wasm installs it (web).
- Object > Plug-ins and Effect > Plug-ins menus with dialogs generated from the parameter
  schema (live preview), the Appearance panel's fx menu, docs/plugins.md, an original
  example plug-in (Desaturate, a Rust crate outside the workspace) and fuzzing of the
  plug-in boundary (engine/tests/plugin_fuzz.rs).

Tool plug-ins and paint-changing live effects are left for later (docs/plugins.md).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 00:19:41 +07:00
bflatasticandClaude Opus 5.5 ab1c6b0516 M4.94: EMF and WMF export from Export As and document.export
New crates/metafile (L3, pure Rust): hand-written EMF and WMF writers over
one shared document walk. EMF keeps Bezier paths, solid brushes, geometric
pens (width, caps, joins, miter limit, user-style dashes), clipping masks as
path clips, images (StretchDIBits, or AlphaBlend with transparency) placed by
a world transform, type as outlines; gradients become images clipped to their
shape and pattern fills their tiles clipped to it. The header's frame is the
artboard in 0.01 mm on a 100 px/mm reference device. WMF flattens curves into
polygons in 16-bit units behind a placeable header (with its checksum),
numbers objects as players do, and reports what it leaves out (clipping,
transparency, gradients, rotated images).

document.export {format: emf|wmf} (and serialize, export) writes one artboard,
or one file per artboard with useArtboards (false: the art's bounds); raster
effects are rendered to images first, as for PDF. Export As lists EMF and WMF.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 15:24:24 +07:00
bflatasticandClaude Opus 5.5 4c4850e745 M4.76: EPS export (PostScript Level 2 and 3) with EPS Options, TIFF previews and the document embedded
New crates/eps (L3): a hand-written EPS writer. A DSC header with
%%BoundingBox and %%HiResBoundingBox (y up from the origin), %%LanguageLevel
and spot colours; paths filled and stroked with caps, joins, miter limits
and dashes (strokes a plain line can't draw as filled outlines, brushes as
their art), clipping groups, linear and radial gradients as smooth
shadings at Level 3 and stepped fills at Level 2 or with compatible
gradient printing, patterns as tiles, freeform gradients and placed images
as images (Flate with masked transparent pixels at Level 3, run-length at
Level 2), type as glyph outlines, spot colours as Separation spaces and
overprints when preserved; RGB written as CMYK on request. A TIFF preview
(1-bit or colour, transparent or opaque) behind the binary header, a PNG
thumbnail and the native document in comments (eps::native and
eps::thumbnail read them back for a later import).

document.export {format: eps} and document.exportEps: transparency is
flattened first with a flattener preset (built-in or saved) and options;
the visible art's bounds, or with useArtboards one file per artboard named
{stem}_{artboard}.eps. Export As lists EPS, then EPS Options
(ui.epsOptionsDialog for agents, remembered between exports).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 13:50:50 +07:00
bflatasticandClaude Opus 5.5 a17cc428d1 M4.77: DXF export (R12 to 2018) with DXF Options; DWG and PICT say what to use instead
New crates/cad (L3): a hand-written ASCII DXF writer. Layers become DXF
layers (hidden: off, locked, non-printing: not plotted), straight paths
LWPOLYLINE (POLYLINE before R14), curves cubic SPLINEs through every
anchor, fills solid HATCHes (outlines in R12), strokes lines with a
lineweight and a linetype per dash pattern, type TEXT or glyph outlines,
placed images IMAGE entities linked to PNG or JPEG files. Units and
scale ($INSUNITS), scaled lineweights, 8/16/256 indexed or true colour
(420), transparency (440), Preserve Appearance / Maximize Editability,
Alter Paths for Appearance, Outline Text.

document.export {format: dxf} and document.exportDxf; useArtboards
writes one drawing per artboard; selectedOnly (any export) writes the
selection in its layers. Export As lists DXF (then DXF Options,
ui.dxfOptionsDialog for agents, remembered between exports) and DWG
greyed out; document.formats lists DWG and PICT as unsupported with a
hint, and exporting or opening them answers with it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 12:00:17 +07:00
bflatasticandClaude Opus 5.5 20e0935116 M4.24: File > Place as an engine command: images at their physical size, SVG/PDF/native as one group
file.place {path | name+dataBase64, link, template, replace, at, rect, page, crop} places a
file as one undo step without touching the clipboard. Raster images come in at 100% of the
resolution their file declares (PNG pHYs, JFIF/EXIF, TIFF, BMP; 72 ppi otherwise), linked to
their path by default; SVG becomes one group with its embedded images; a PDF/.ai page or a
native document's artboard becomes one clipped group. The images, symbols, patterns and
swatches the art uses join the document (renamed on conflict). Replace keeps the replaced
object's stacking place and transform; Template puts the art on a new locked template layer
below the current one. file.place.info and image.info report size, ppi and colour mode.

File > Place picks a file and opens the Place dialog (Link, Template, Replace); the web picks
through the inbox. The Control bar shows Linked File/Embedded, the file name, colour mode and
ppi of the selected image.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 08:42:30 +07:00
bflatasticandClaude Opus 5.5 96aba71759 M4.30: SVGZ read and write
svgz is a writable format with the SVG options (document.export,
serialize, save, Export for Screens): exactly the SVG export, gzipped.
SVGZ is recognised by its extension or the gzip magic bytes and opens,
places and pastes like SVG (clipboard.importSvg takes dataBase64 of SVG
or SVGZ); Export As SVG or Save As to a .svgz name writes it
compressed. Gzip lives in the svg crate (pure-Rust flate2, builds for
wasm) and unpacking stops at 512 MB.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 07:58:10 +07:00
bflatasticandClaude Opus 5.5 4d503c0327 M4.12: one loader and encoder for every frontend — engine fileio (load/encode/export/save, append-only FORMATS table, OPEN_EXTS, document.formats query, typed per-format options, parse_range); document.open reads native/legacy, SVG/SVGZ, PDF/.ai, .ait (opens untitled like native templates) and PNG/JPEG/GIF/WebP/TIFF/BMP; desktop, web, control channel, headless MCP and the CLI open and encode through it; open dialogs list "All readable files" plus one filter per format
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-04 11:36:51 +07:00
Brandon ThomasandClaude Opus 5.5 4878f1c5dd Rename DrawCraft → VectorCraft: crates (vectorcraft-*), apps, binaries, types, env vars, docs, examples (.vectorcraft); old .drawcraft files and preferences still load. Fix: text bounds exact after opening a file; selection no longer marks a document modified (dirty = content differs from the saved document). Screenshots and renders regenerated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 14:30:09 -04:00
Brandon ThomasandClaude Opus 5.5 f8136f1e35 Live Blends/Envelopes/Gradient Mesh, Shape Builder, Live Paint, Image Trace (drawcraft-trace), Recolor Artwork, Export for Screens, Actions panel, prefs persistence, real layer thumbnails; menus bound
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 11:02:16 -04:00
Brandon ThomasandClaude Opus 5.5 42df20ca7f Panels to Illustrator parity (19 panels), ~70 menu commands, generic param dialogs, view rotation, property/model-based tests + MCP e2e; fix arrange overflow, compound grouping, double journaling, float round-trip, coordinate sanity, simplify growth, batch rollback of session state
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 09:32:20 -04:00
Brandon ThomasandClaude Opus 5.5 60c562c956 M5.2/M5.4: render geometry cache (Arc identity), opacity folding, LOD, multithreaded rasterizer (20k objects: 187→21 ms); native macOS menu bar; Effect menu + live-preview dialogs; PDF open/save; bench example
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 07:07:59 -04:00
Brandon ThomasandClaude Opus 5.5 bfee80a22c M0: workspace skeleton — geom, color, doc, render, text, pathops, svg, tools, engine
Engine-first Cargo workspace for DrawCraft (clean-room Illustrator):
- geom: anchor-based path model, shapes, hit testing, snapping
- color: colours, paints, gradients, swatches, blend modes, harmonies
- doc: persistent Arc document tree, appearance stacks, text model, selection
- render: vello_cpu renderer (appearance, gradients, clip groups, blend modes)
- text: font DB, harfrust shaping, point/area/path layout
- pathops: curve booleans (linesweeper), Pathfinder, offset, simplify
- svg: import (usvg) and export
- tools: selection/direct/pen/shape tools emitting commands
- engine: Session, history with interactions, ~110 commands

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 05:53:29 -04:00