Commit Graph
15 Commits
Author SHA1 Message Date
bflatastic c895f64063 Format: rustfmt after the batch 2026-10-21 23:38:03 +07:00
nrq6993-a11yandCursor ab0ddf0eae G1: Live Corners relative rounding (#1144)
Store corner radii as fractions of each corner's max so rounding scales with the shape; expose via Corners dialog and object.setLiveShape relativeRadii.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
dotCooCoo 68d8a9c755 Export: area type that Shrink Text to Fit scales down is written at the size it draws at
Shrink Text to Fit scales area type down at layout time, and the canvas,
PDF export and the exports that write type as outlines draw it at that
size. SVG export wrote the live text at its stored font size, letter
spacing and baseline shift, so a viewer drew it larger than the canvas
does. Legacy .ai saves wrote the stored size, leading and baseline shift
into the text objects, DXF export took the TEXT heights from the stored
size, and the CSS Properties panel gave the stored font size, letter
spacing and line height.

The text crate's scaled, which the layout scales shrunk text with, is
now public. SVG export, legacy .ai saves and the CSS Properties panel
take the type's styles from it at the layout's fit scale, and DXF
export multiplies the TEXT heights by that scale. Positions and
textLength in SVG still come from the layout.

Docs: docs/target-app-parity.md.
2026-10-21 16:55:16 +07:00
bflatastic 04139ad0b6 fmt (#3157) 2026-10-20 03:42:11 +07:00
MarekSpodBiedry 0f855be77f Add a generic family to the font-family of SVG export and CSS (#3135) 2026-10-20 03:41:17 +07:00
dotCooCoo 24b6486ebd Artboards: the doc comment names the shared corner the first artboard holds
On an edge two artboards share, the artboard to the right of it or below
it holds a point, except at the end of the edge that lies on that
artboard's bottom or right edge, such as where both artboards' bottom
edges meet. There the first artboard holds it, or the last when
topmost. The doc comment and the test comments now say so, and the test
asserts that corner.
2026-10-17 17:13:02 +07:00
dotCooCoo 8f87ad53dd Artboards: art centered on an artboard's right or bottom edge is on that artboard
Rearrange All Artboards, Select › All on Active Artboard (for objects
with no area), Copy's source artboard for Paste in Place, Align to
Artboard without an index, Crop Image, the Crop Image tool, Place with
`at`, CSS positions and a filter plug-in's artboard decided whether a
point or an object's center is on an artboard with Rect::contains,
which leaves out the right and bottom edges. A line along an artboard's right or
bottom edge was on no artboard: Rearrange left it behind, and All on
Active Artboard did not select it. Document::art_on_artboard counts
art flush with those edges (#890).

They now count the edges as art_on_artboard does, within a millionth
of a point. On an edge two artboards share, the artboard to the right
of it or below it still holds the point. All on Active Artboard
selects a line on a shared edge from either artboard. A press exactly
on a right or bottom edge now picks that artboard, and the Artboard
tool's cursor shows Move there.
2026-10-17 16:38:43 +07:00
NetterSilverandClaude Haiku 5.5 a631a0df6c Escape quotes and backslashes in exported CSS font-family
Found while testing crates/svg/src/css.rs:84 (font_props)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 16:38:42 +07:00
vangel76andClaude Opus 5.5 8875b3fbca Live Corners: a corner rounds until its cut reaches its neighbours (#2332)
A corner's radius was capped at half its shorter side whatever its neighbours did, so one corner of a 100 pt square rounded alone stopped at 50 pt. Each corner now rounds until its cut reaches the cuts its neighbours ask for: the whole side when the neighbour is square, halfway when both ask for more. The corner widget drag, the red limit outline and CSS border-radius export follow the same limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:20:26 +07:00
dotCooCoo 720ce5ed73 Effects: Drop Shadow has Darkness, the object's own colors with black added
The reference app's Drop Shadow has a Color and a Darkness, the
percentage of black added to the object's own colors. Drop Shadow had
only a Color, so every shadow was one color. Choosing one or the other,
and the defaults, are VectorCraft's own.

Drop Shadow now takes `shade` ("color" or "darkness", default "color")
and `darkness` (%, default 100). Its dialog and the Appearance panel's
inline editor show Color and Darkness as radio buttons. With Darkness
d, a CMYK document keeps the object's cyan, magenta and yellow and
raises its black from K to K + d × (1 − K), and an RGB document
multiplies each channel by 1 − d, so in RGB 0% gives the object's
color and 100% gives black. A shadow saved without these keys draws as
before. SVG export writes a Darkness shadow with feComponentTransfer
and SVG import reads it back; CSS export leaves it out.

Docs: docs/target-app-parity.md.
2026-10-16 02:25:58 +07:00
arhammusheer 5beac4f122 #1244: smaller objects: Node 352 -> 152 bytes, NodeKind 200 -> 80, and a cheaper undo estimate
Rarely set fields move into one optional boxed NodeExtras, and large NodeKind payloads (images,
live shapes, blends, envelopes) are boxed. Every object, and every undo step that copies it,
shrinks: a 50k-path move keeps ~24.5 MB per step instead of ~40 MB. Files stay byte-identical
(Node keeps its flat JSON through a borrowed Serialize and a from-wire Deserialize, no flatten),
and loading is slightly faster. Undo and redo reuse their step's size estimate instead of
walking the document again (8.3 -> 5.6 ms for a 50k-path move).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc

# Conflicts:
#	crates/engine/src/cmd/graph.rs
#	crates/svg/src/export.rs
2026-10-12 11:02:32 +07:00
arhammusheerandClaude Opus 5.5 0724aafbb6 #1172: share an object's appearance with its undo history until it changes
Every edit of an object copied its whole appearance (its fills, strokes and effects, about
540 bytes for a basic object) into the new node, though a move leaves it as it is. Over 45
whole-selection moves of 10,000 paths, undo history grew by 589 MB; now 349 MB (41 % less), and
a nudge or a drag of the selection takes 12 ms instead of 15.

- Node::appearance is a vectorcraft_doc::Shared<Appearance>: copy-on-write. A clone shares it,
  and the first change through DerefMut copies it (Arc::make_mut). Reads, writes, equality (also
  against a plain Appearance) and the saved form are those of the Appearance itself, so call
  sites read and change it as before. Sites that build or assign a whole appearance add .into(),
  and the few that need a plain copy take (*n.appearance).clone().
- Node::transform changes the appearance only when it has gradients to transform, and pattern
  paints are transformed only when there are some: a move no longer copies an appearance it
  doesn't change.

The workspace suite (5,301 tests) and clippy pass with the change; the doc and engine suites
pass again after the transform guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc
2026-10-11 23:27:21 +07:00
bflatasticandClaude Opus 5.5 44c7e64e1b Fix #442: alike circular corners on rectangles that aren't square
Live rectangles drew elliptical corners after an uneven scale in v0.4.0;
inconsistent on a rectangle that isn't square:

- doc: LiveShape::fold_scale moves an uneven scale left in `xf` (files
  saved before #291) into the size and radii; `transform` uses it, and
  `folded()`/`corner_style` give Live Corners document units.
- engine: object.setLiveShape folds that scale first, so setting a radius
  or kind (fields, dialog, widgets, MCP) gives circular corners on such
  shapes instead of keeping the ellipses.
- geom: max_corner_radius/fitted_corner_radius are the one limit every
  corner shares (half the shorter side).
- tools: corner widgets sit at the centres of the corners as drawn (a
  radius past the limit put them off the arc, further in along the long
  side), drag in document units on stretched shapes, and outline the
  edited corners in red at the limit, as the reference app does.
- svg: CSS export writes the drawn radii (CSS would draw a radius past the
  limit when its neighbours leave room).
- docs: mcp.md Live Corners, ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:34:37 +07:00
bflatasticandClaude Opus 5.5 b05c14f8eb Fix #381: round single corners with Direct Selection (per-corner Live Corners)
A live rectangle stored four corner radii but drew them all with the largest,
and the corner widgets always rounded all four corners, so one corner could not
be rounded on its own.

- geom: rectangle_with_corners draws each corner with its own radius and kind
  (Round, Inverted Round, Chamfer); a sharp corner is one anchor, a cut one two.
  Uniform corners keep the exact rounded-rectangle anchors.
- doc: LiveShape::Rectangle gains `kinds` (saved only when a corner isn't round;
  older files read as round), plus helpers mapping anchors to corners.
- engine: object.setLiveShape takes `corners` and `kind`; without `corners` it
  edits the Direct-Selected corners, else all four, and keeps the selected
  corners selected as their anchors change.
- tools: with Direct Selection, only the selected corners show widgets and a
  drag rounds just those; Alt-click cycles the corner kind; double-click opens
  the new Corners dialog (also `ui.corners`).
- ui: Properties/Transform radius fields show and set the selected corners;
  CSS export keeps per-corner radii and skips cut-in corners.
- docs: mcp.md (Live Corners), control-protocol.md (Corners dialog), ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 06:56:32 +07:00
bflatasticandClaude Opus 5.5 ed4eceb837 M4.96: Window › CSS Properties shows, copies and exports the CSS of the selection
The svg crate's new CSS writer (css_rules) gives the CSS web pages style objects
with: rectangles and ellipses as background-color / linear-/radial-gradient(),
border and border-radius; type as font, color, spacing and alignment; shadows,
glows and blur as box-shadow, text-shadow and filter. It shares SVG export's
declarations (transparency, fonts, type spacing, colours, gradient stops), which
moved into svg/src/css.rs. Options: units, absolute position, width and height,
unnamed objects, rasterize unsupported art (as a PNG background-image).

Commands css.selection, css.generate and css.export; UI commands css.copy and
css.exportFile; the CSS Properties panel with a highlighted code view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 16:03:11 +07:00