Commit Graph

23 Commits

Author SHA1 Message Date
BFlat e0200acbae
M6: autosave checkpoints in version history (#38)
Every 30 minutes, each open document with unsaved changes since its last
version gets an automatic "Autosave" version (flagged `auto` in the file).
The newest 20 autosaves are kept; older ones make room and user versions
are never dropped for them. Runs of autosaves fold into one line in the
Version history panel. New command version.autosave.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:48:21 +07:00
BFlat ce317cdf42
M6: view a version on the canvas before restoring it (#36)
Clicking a version in Version history shows it in place of the document,
read-only, with a banner to restore it or go back to the current version
(clicking Current version or closing the panel goes back too). Edits,
undo and gestures are refused while a version is shown; saving, closing
and restoring end the preview first, so the document and its unsaved
state are never touched by it.

New commands version.preview and version.exitPreview; version.list marks
the shown version.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:34:06 +07:00
BFlat 360b6df206
M4: local libraries: publish, enable, place and apply, updates with overrides kept (#32)
- Publish (`library.publish {description?, include?, exclude?}`, Libraries > Publish library…):
  the file's components, component sets and styles (by default all but names starting with `.` or
  `_`, or what the last publish offered) and every component and style they use go into a snapshot
  with a manifest (library id, version, per-asset version stamps). An asset keeps the version it
  last changed in; publishing without changes is refused.
- .figcraft: `library/manifest.json`, `library/document.json` (the snapshot) and
  `library/images/<sha256>` for images only the library still uses. Older files and readers are
  unaffected (extra members); a damaged library is skipped and reported when the author's file
  opens. Files using a library read only these members (size-limited), never unpublished edits.
- Version history: the library entries are written and read alongside the versions (a library
  survives saving with versions and reopening); restoring a version keeps what the file published.
- Enable: `library.add {path}` / `library.remove {id}` / `library.list {assets?}`; the document
  keeps its enabled libraries (id, name, path, last seen version) in its data. The session caches
  each library file and reads it again when it changes on disk; in the browser these commands
  return a clear error (no file system).
- Use: `library.place {library, component, x?, y?}` / `library.import` copy the component (with
  the components and styles it uses) into a hidden library store (a page-like root outside the
  page list) as read-only main components and place an instance; instances behave like any other
  (overrides, properties, variants, swap, reset, detach). `library.applyStyle` copies a style in as
  a linked remote style. Editing the copies or library styles is refused; Go to main component
  names the library. Importing a file's pages brings its library copies along (shared with copies
  the document already has).
- Updates: `library.updates` and `library.acceptUpdates {ids?}` re-import changed copies in place
  (layer ids kept, so instance overrides survive, also when layers are added); unused copies are
  dropped when a library is removed or updated.
- Assets panel: each enabled library's components (thumbnails, search, click or drag to place,
  shared with the local tile code) and styles (click to apply, paint swatches), collapsible per
  library; "Library updates available" banner with Update; a libraries view (book button,
  Libraries menu) to publish this file (choose assets, description) and add or remove library
  files. Local styles in the panels list only this file's styles.
- Tests: manifest round trip and versions, add/place/update keeping overrides (incl. a structural
  update), variants/swap/undo, library styles and importing pages, missing/corrupt/truncated/
  oversized/never-published files; format tests for damaged and oversized members.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:24:46 +07:00
BFlat a5d5c265fd
M7: performance: retained canvas renders, virtual layers panel, shared text layouts, cargo xtask bench (#35)
Large documents stay interactive: the canvas re-renders only what a pan uncovers or an edit
touches, the layers panel lays out only the rows in view, and per-frame work no longer walks the
whole page.

- Benchmark: `cargo xtask bench [SIZES]` builds synthetic pages (`figcraft_engine::synthetic`:
  screens with an auto layout header, a card group, button instances and shapes/text) at
  1k/10k/50k layers and prints engine/render timings (`figcraft-cli perf --layers 1000,10000`) and
  headless whole-UI frame timings (an ignored ui-egui test).
- Retained canvas rendering (`figcraft_render::Retained`, used by the render worker): views snap
  to whole device pixels, so a pan shifts the previous image in place and renders only the
  uncovered strips; an edit renders only where changed layers were and are
  (`Document::changed_ids` diffs the two versions skipping shared structure; ancestors that paint
  from their children's pixels - booleans, effects, masks - count whole; background blur reach
  and noise are allowed for). Zoom, page, options, font or page-level changes, or large changes,
  render the whole view as before. `ui.inspect` reports `canvas.renderWork`.
- The texture image is converted on the render thread, not the UI thread.
- Layers panel: only visible rows are laid out (stable ids while scrolling); rows are cached per
  document version, page, expanded set and filter.
- Frame labels and layout grids of off-screen top-level frames are skipped; the Prototype tab's
  connection sources are cached per document version.
- Text: the layout cache keys by a cheap fingerprint confirmed by `TextData` equality (no Debug
  formatting per lookup, 32k entries) and hands out shared layouts; a layout generation marks
  renders stale when fonts arrive. Overflowing text is culled by its glyphs, so it no longer
  vanishes while its box is off screen.

Before -> after (release, Windows, 1440x900 view, ms; 10k / 50k layers):
- move one layer, re-render @100%:     7.65 / 6.49  -> 0.18 / 0.81
- move one layer, re-render zoomed out: 11.95 / 24.10 -> 0.16 / 0.77
- pan 40 px @100%:                     7.53 / 6.82  -> 0.69 / 0.81
- pan 40 px zoomed out:                12.07 / 24.30 -> 1.62 / 4.17
- full render @100% / zoomed to fit:   7.78 / 44.22 -> 6.56 / 38.83 (10k @100%, 50k fit)
- UI frame, every screen expanded in layers: 6.16 / 39.07 -> 0.24 / 0.57
- UI frame, scrolling that panel:      6.11 / 40.18 -> 0.43 / 0.40
- UI frame, layers filtered by name:   1.03 / 6.92  -> 0.17 / 0.36
- UI frame, Prototype tab:             0.89 / 6.45  -> 0.18 / 0.80
- UI frame, idle:                      0.31 / 1.43  -> 0.11 / 0.39
Unchanged and within budget: single-layer edits through the engine ~0.01 ms, normalize after a
one-node edit < 0.01 ms, hit test 26 / 93 us. Left: save/load at 50k (~0.7 s each), zoomed-out
renders at 50k (~40 ms).

Tests: retained renders match full renders after pans, moves, recolours, hide/remove/add, undo,
masks, overflowing text, edits under a background blur and an inner-shadow/noise layer, a drop-
shadowed group, and a blur panned in from the view's edge; zoom/page/options/page background
render full; junk views don't panic. Layer-row and prototype-source caches follow edits, undo,
page switches, expansion and the filter. `changed_ids`, the text cache, and the perf CLI.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:19:05 +07:00
BFlat 1c6f04bf62
M3: Variables editor with aliases, scopes, and rename/delete for variables, modes and collections (#33)
The Local variables window becomes a table editor: collections in a
sidebar, variables grouped by name with one value column per mode, typed
value cells (colour swatch + hex + alpha, number, string, boolean), alias
chips with a variable picker and detach, double-click rename, context
menus, and an Edit variable window for description and scopes.

New commands: variable.update (name, description, scopes),
variable.duplicate, variable.renameMode, variable.removeMode,
variable.renameCollection, variable.deleteCollection. variable.set
validates aliases (same type, no loops) and stores them by id; addMode
always picks a fresh mode id. Pickers offer only variables scoped to the
property. ui.set {variables} opens the editor on a collection.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:12:08 +07:00
BFlat bf3a45d938
M1: sections and frames: resize to fit, section colours, ready-for-dev status (#23)
- Object ▸ Resize to fit (Alt+Shift+Cmd+R, `object.resizeToFit`): frames, sections and
  components shrink or grow to their visible contents without moving them on the page; auto
  layout frames switch to hug instead.
- Sections get colour swatches (light tints) in the Design panel.
- Frames and sections get a handoff status (`devStatus`: ready for dev / completed) set from
  the panel and shown as a badge next to their name on the canvas; `node.get` reports it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 04:20:23 +07:00
BFlat aa0e8b4a7c
M4: vector eraser in edit mode (#25)
- Eraser tool (Shift+E) in the vector edit toolbar: drag a brush over paths to remove the parts
  it covers; segments are cut exactly where the brush enters and leaves (curves stay curves),
  fully covered segments and orphaned points go, and closed shapes open while keeping their
  implied fill. A stroke is one undo step; the brush shows under the pointer.
- `vector.edit.erase {points, radius?}` for the CLI, control channel and MCP.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 04:16:35 +07:00
BFlat 72b8c5d154
M6: version history: versions saved in the .figcraft file, version commands and panel (#21)
- Versions now belong to the document (DocState.versions) instead of a process-global map keyed by
  document uid, so they survive closing the file. A new, renamed or deleted version marks the file
  as changed.
- .figcraft: `versions/index.json` (id, name, description, time, image hashes) plus one deflated
  `versions/<id>.json` snapshot per version; images only versions use are stored once and kept with
  them. Snapshots read from a file are parsed on first use (and written back as-is). Readers that
  don't know versions ignore the entries; files without versions load unchanged. Damaged, missing,
  oversized or duplicate entries are skipped and reported, never failing the load. At most 100
  versions per file; names and descriptions are clipped.
- Commands: `file.saveVersion {name?, description?}` returns the version; `version.list`;
  `version.restore {id | index}` (one undo step, keeps the file name, stays on the current page);
  `version.rename {id | index, name, description?}`; `version.delete`; `version.duplicate` (opens
  the snapshot in a new tab). Indexes are validated: a negative index used to restore version 0.
  `req_index` param helper shared with the guide commands.
- Version history panel in the left sidebar in place of Pages and Layers (File > Show version
  history; Save to version history opens it with the form): save form (title, description),
  "Current version" on top and the versions newest first on a timeline with name, relative time and
  description; per-version menu (also right-click): Restore, Rename (title and description inline),
  Duplicate, Delete (confirmed inline). New shared `widgets::button`.
- `figcraft-cli run --out x.figcraft` keeps the version history.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 04:16:18 +07:00
BFlat ff0f5a40d7
M4: expose nested instances' properties on instances (#22)
- A nested instance inside a main component can be exposed (`component.exposeInstance`, an
  "Expose properties to instances" toggle in its panel); the main's instances then list it by
  name with its variant and component property controls, recursively for exposed instances
  inside it. Values set there are nested overrides and survive main edits.
- `instance.exposed {id}` lists an instance's exposed nested copies (for the CLI and MCP).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 04:08:48 +07:00
BFlat c54509a574
Roadmap: recompute totals after day 2 (feature depth ~58%, time to parity, next steps) (#20)
- Feature depth from the weighted table (~59%, graded down to ~58%), parity incl. fidelity,
  menu breadth 97%, remaining hours from the table's rows, next/then priorities, command and
  test counts; parity report regenerated.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 04:00:27 +07:00
BFlat 840d3ac5d2
M1: mask types: alpha, vector outline and luminance masks (#17)
- Layers gain `maskType` (alpha by default, so files are unchanged): a vector mask clips by the
  mask layer's outline whatever its fills and opacity; a luminance mask shows content where the
  mask is bright and hides it where it is dark.
- `node.set {maskType}` (validated), `node.get` reports it, and the Appearance section shows a
  Mask dropdown when the selection is masks.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:45:45 +07:00
BFlat 076c25f6df
M6: Inspect code in CSS, SwiftUI and Jetpack Compose (#15)
- Code generation moves from the UI into the engine (`codegen.rs`): CSS for the layer as before,
  plus SwiftUI and Compose for its subtree (stacks with spacing and padding for auto layout,
  offsets inside a ZStack/Box otherwise, text with font and colour, shapes, fills, strokes,
  shadows, opacity; other layers become image-asset placeholders). String literals are escaped
  per language; deep trees are capped.
- New command `inspect.code {id?, language?}` for the CLI, control channel and MCP.
- Inspect tab: a language picker and Copy for the shown code; Copy as CSS uses the same code.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:45:29 +07:00
BFlat e718518a08
M6: import REST API file JSON: pages, layers, paints, text runs, vectors, auto layout, components (#13)
- New `figcraft_format::rest`: imports the public REST API file JSON (`GET /v1/files/:key`, and
  the nodes endpoint's response) using the published reference only. Pages (name, background,
  flow starting points), the layer tree, names, visibility, lock, opacity, blend mode, masks.
- Geometry from `relativeTransform` (children of groups/booleans checked against
  `absoluteBoundingBox` to settle their space), else absolute bounds + rotation; sizes, corner
  radii (uniform and per corner), smoothing, clip content, constraints, export settings, layout
  grids.
- Paints: solid, linear/radial/angular/diamond gradients (handles map 1:1), image fills (fill,
  fit, tile, stretch, rotation, filters) with bytes from a resolver or a grey placeholder keyed by
  the imageRef; paint opacity, visibility and blend. Strokes: weight, per-side weights, align,
  caps, join, dashes, miter angle. Effects: drop/inner shadow (offset, radius, spread, show behind),
  layer and background blur.
- Vectors from `fillGeometry` (stroke-only vectors use the `strokeGeometry` outline), ellipse arc
  data, stars/polygons, boolean operations. Text: characters, type style (family, style or weight
  + italic, size, line height px/%/auto, letter spacing, case, decoration, alignment, auto resize,
  truncation, paragraph spacing/indent, OpenType flags, links), per-character overrides → styled
  runs (UTF-16 aware), list type.
- Auto layout: direction incl. grid, alignment, padding, gaps, wrap, hug/fixed/fill sizing (legacy
  and per-axis fields), absolute positioning, min/max, grid cells.
- Components and sets with descriptions and property definitions (names lose their `#id`
  suffix); instances of components in the file become instances with their property values and
  listed overrides; outside components and component cycles stay frames. Shared styles are created
  from the layers that use them, named from the metadata.
- Unknown types and fields are skipped with a counted warning list; sizes, depth (256), layer count
  (200,000), path length and list lengths are capped; nothing panics on junk.
- Engine: `file.open` / `file.import` / CLI detect the JSON by content, link imported instances to
  their mains (sources and overrides), read image fills from an `images` folder next to the file,
  never save over the JSON, and return `warnings`. `file.import` now remaps ids across all
  imported pages at once (instances keep their main and layer sources) and brings styles and page
  backgrounds along. `figcraft-cli info` prints load notes.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:36:30 +07:00
BFlat b7910c81f8
M4: text depth: inline IME composition, variable font axes, range-aware typography polish (#8)
- Inline IME composition: egui Preedit events become a composition held in the text edit
  session (`TextEdit.preedit`), shown inline at the caret with an underline and the IME cursor,
  reflowing the text; the document only gets the committed text (`text.edit.insert`). Composing
  over a selection replaces it; moving the caret or ending the edit drops an uncommitted
  composition. The IME candidate window follows the cursor inside the composition.
  New command `text.edit.preedit {text, cursor?}`; `text.edit.selection` reports it.
- Variable fonts: faces read their fvar axes (tag, name, range, default, hidden) and named
  instances. Named instances are offered as styles and resolve in `find`; a style name with no
  instance implies weight/italic/slant on the axes and optical size follows the font size.
  Per-run custom axis values (`TextStyle.variations`, serde default, omitted when empty) are applied
  in HarfRust shaping (ShaperInstance) and skrifa outlines/advances (cached per coordinates).
  PDF export outlines non-default instances instead of embedding the default one.
- Commands/props: `fontVariations` / `variationSettings` props (whole layer or start..end),
  `text.setVariations {variations, replace?}` (merges; edited range while editing),
  `text.fonts {family, style?, axes: true}`; `node.get` and copy/paste properties carry the axes.
  Picking a named style (Bold/Italic toggles, weight steps, fontStyle/fontWeight) drops custom
  wght/ital/slnt values and keeps the others.
- Type settings ▸ Variable tab for variable fonts: a slider (default tick, double-click to reset)
  and a field per visible axis, "Mixed" across differing styles, live drag as one undo step,
  "Reset to style". Long style/family names stay on one line with an ellipsis and a tooltip.
- Tests: variable font shaping/outlines/clamping/instances (skipped without a variable font),
  serde backward compatibility, preedit lifecycle and undo, variation commands/props/undo/junk;
  junk sweeps extended with variation and preedit params.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:07:41 +07:00
BFlat d30ee21566
M1: paint depth: gradient stops on the canvas, colour models, colours on this page (#7)
- Gradient stops on the canvas: drag a stop along the gradient line, click the line to add a
  stop (sampled colour), the selected stop is ringed and shared with the picker; Delete removes
  it (two always stay).
- Colour picker value row: a model dropdown (Hex, RGB, HSL, HSB, CSS) with its fields and the
  alpha field; scrubbing works on the numeric fields.
- "On this page" swatches: the page's most used solid colours (cached per document snapshot);
  swatches set a solid colour or the selected gradient stop.
- New command `paint.documentColors {page?, limit?}`; control channel `ui.set {colorPicker}`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:57:40 +07:00
BFlat 14435acb63
M1: keyboard transforms: arrows reorder auto layout children, Cmd+arrows resize (#6)
- Arrow keys on children of an auto layout frame move them one place along the flow (Left/Up
  earlier, Right/Down later; grids step by a row vertically); selected neighbours move as a
  block and stop at the ends. Free layers still nudge.
- Cmd/Ctrl+arrows resize the selection by the nudge amount (Shift: big nudge), top-left fixed;
  only the changed axis becomes Fixed. New command `transform.nudgeSize {dw, dh, big?}`.
- Control channel `ui.key` arrows with `cmd` resize too.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:42:17 +07:00
BFlat 51fada8d8f
M4: Assets panel: thumbnails, search, drag components onto the canvas into frames and auto layout (#5)
- Assets tab rebuilt as its own module: local components as two-column tiles with live
  thumbnails (re-rendered when a component's content changes, throttled), a search field that
  filters components and styles, and the local styles list.
- Drag a tile onto the canvas: a ghost follows the pointer, the frame under it highlights and auto
  layout frames show the insertion line; releasing drops an instance there, centred on the
  pointer. Clicking a tile places one in the middle of the view.
- New command `instance.place {component, x, y}` (page point; drops into the frame or auto layout
  slot under it; never inside its own main) for the CLI, control channel and MCP.
- The auto layout drop slot is shared with moving layers (`drop::auto_layout_slot`).
- Creating a component from a single shape names it after the shape.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:41:59 +07:00
BFlat 6610966921
M1: layers panel depth: search, shift-click ranges, sticky collapse, reveal selection, Tab rename (#4)
- Search toggle in the Layers header: a live filter that lists matching layers across the page.
- Shift-click selects the visible rows from the anchor to the clicked row (Cmd adds them to the
  selection); Cmd-click toggles.
- The tree reveals a new selection once (expands its ancestors and scrolls its row into view),
  so Collapse layers (Alt+L) and manual collapsing stick.
- Alt-click a disclosure triangle expands or collapses everything inside.
- Tab / Shift+Tab while renaming commits and renames the next / previous layer.
- Control channel: `ui.set {layerFilter, collapseLayers}`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:34:55 +07:00
BFlat 4286a3b74b
M2: auto layout depth: min/max UI, ignore auto layout toggle, text baseline alignment, grid tracks and cells (#3)
- Min/max width/height: the W/H sizing menus add min/max (at the current size) and remove them;
  limit rows edit or add the missing bound. The layout clamps Fixed, Hug and Fill children and
  the frame itself; a hugging text wider than its max width wraps at the max. min > max is kept
  ordered by node.set (the other bound follows); in the layout min wins.
- Ignore auto layout (absolute position): a toggle in the Position section; the child stays
  where it is, can't Fill, shows constraints and follows them when the auto layout frame resizes
  (by hugging, filling or a direct resize).
- Text baseline alignment for horizontal layouts ("Align text baselines"; crossAlign baseline):
  first-line baselines line up, other layers align to the top, nested auto layout frames use
  their first child's baseline. Measure gains text_baseline.
- Grid auto layout: column/row tracks (fixed px, hug, fr fill) via columnTracks / rowTracks or
  layout.setTrack, cells anchored by gridColumn / gridRow with gridColumnSpan / gridRowSpan,
  auto placement in reading order, rows grow to fit, hugging grids size to their tracks.
  Panel: column/row gap, track size rows, a child's cell and spans. Old files load unchanged
  (serde defaults; missing tracks are 1fr).
- Canvas handles: wrapped-row gaps and grid column/row gaps are draggable; a selected grid's
  tracks are outlined.
- The layout section moved from right.rs to layout_panel.rs; inspect reports min/max and a
  grid child's resolved gridCell; docs list the new props.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:23:43 +07:00
BFlat 94e689fad6
M4: vector edit mode tools: pen branching, bend, paint bucket, lasso, cut, mirroring, point panel (#2)
- Edit-mode toolbar (Move V, Pen P, Bend hold Cmd, Paint bucket Shift+B, Lasso Q, Cut X, Done)
  replaces the tools while a vector is edited.
- Pen in edit mode continues open ends, branches from any point (vector networks), adds points on
  segments and closes paths into fill regions; dragging pulls out mirrored handles.
- Paint bucket fills or unfills any closed area: faces of the network (half-edge walk, nested
  pieces become holes), with a hatched preview of the area under the pointer.
- Bend tool / Cmd: bend segments, pull handles out of a point, click a smooth point to sharpen it.
- Lasso and marquee point selection, segment selection (shift adds), cut at a segment or a point.
- Per-point handle mirroring (none / angle / angle and length, inferred for existing files),
  Alt-drag breaks it; smooth/sharp points; join and merge selected points (Cmd+J, Shift+Cmd+J).
- Delete opens the path, Shift+Delete heals it; arrows nudge points; Cmd+A selects all points.
- Design panel shows the selected points' position, corner radius and mirroring.
- Every gesture is one undo step; edit mode ends when its layer is undone away.
- Paths that end on their start without a ClosePath (ellipse outlines) stay closed and filled.
- New commands (vector.edit.tool/pen/paint/cut/lasso/mirroring/smooth/position/nudge/connect/...)
  for the CLI, control channel and MCP; docs updated.
- Clippy: simplify a few boolean expressions flagged by the current toolchain.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:16:04 +07:00
Brandon Thomas b36fd771ab M0.9: MCP server + figcraft-cli, PDF export, web app, release/CI packaging, vector edit mode, workspace lint cleanup
- crates/mcp: JSON-RPC MCP server (18 tools, resources, prompts), headless and attached backends, end-to-end agent tests
- apps/figcraft-cli: info/export/convert/render/run/commands/mcp/perf
- crates/pdf: vector PDF export via krilla with embedded text; file.exportFramesPdf
- apps/figcraft-web + packaging/{macos,windows,linux,freebsd,web} + release/ci workflows
- engine vectoredit: edit points/handles/bend/add/delete-heal; canvas overlay and edit strip

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:31:53 -04:00
Brandon Thomas 09a7082887 M0.8: AGENTS.md/CLAUDE.md, ATTRIBUTION.md, parity report, wasm compatibility
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:05:34 -04:00
Brandon Thomas f7a68c864b M0.1-M0.3: workspace, licences, geom/color/doc crates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:01:57 -04:00