Commit Graph
957 Commits
Author SHA1 Message Date
BFlat 0e0c3c7be4 Merge pull request #869 from Silvertree2010/fix/h565-server-address-parser-accepts-a
Reject server addresses whose port is not all ASCII digits
2026-10-20 00:47:23 +07:00
BFlat 3ed4578112 Merge pull request #851 from MortenHusted/fix/effect-unknown-keys
M3: effects refuse keys they don't read instead of dropping them
2026-10-20 00:46:45 +07:00
BFlat f3c211eca5 Merge pull request #850 from MortenHusted/fix/make-slot-errors
M3: a refused slot names component.makeSlot
2026-10-20 00:46:07 +07:00
BFlat ab5a508538 Merge pull request #849 from MortenHusted/fix/css-stroke-sides
M7: CSS borders follow individual stroke sides
2026-10-20 00:45:39 +07:00
bflatastic b29e17f5c0 Merge main into #842
# Conflicts:
#	crates/engine/src/variables_behaviour_tests.rs
2026-10-20 00:25:18 +07:00
BFlat 458cd5b141 Merge pull request #817 from muamerETS/fix/copy-text-as-plain-text
M1: copying text layers puts their text on the clipboard (#808)
2026-10-20 00:24:07 +07:00
BFlat 7ca8c80a8f Merge pull request #814 from muamerETS/fix/layout-remove-gap-binding
M3: removing auto layout drops its gap and padding bindings (#810)
2026-10-20 00:23:28 +07:00
BFlat 409de1a762 Merge pull request #871 from justinjohn0306/fix/809-scalar-bound-edits
M3: explicit edits of bound scalar fields detach their variable (#809)
2026-10-20 00:10:09 +07:00
BFlat ba496eddca Merge pull request #811 from MortenHusted/fix/bound-paint-edits-detach
M3: an explicit paint edit detaches the variable bound to what it changed
2026-10-19 23:59:18 +07:00
BFlat ec512a7767 Merge pull request #807 from MortenHusted/fix/wrap-error-command
M1: wrap errors name the command that was run
2026-10-19 23:58:39 +07:00
bflatastic e1da3f36bb Merge fix/830 2026-10-19 22:49:46 +07:00
bflatastic 80c8c7fa87 #830: "Couldn't read {name}." in every full catalog 2026-10-19 22:39:25 +07:00
bflatastic b744ff3e14 #830: cap files read in the browser at 512 MiB, and say why a file isn't opened 2026-10-19 22:39:23 +07:00
bflatastic 479313bf67 Merge main into #830 2026-10-19 22:13:15 +07:00
bflatastic 25899735a8 Merge main into #819 2026-10-19 22:12:58 +07:00
bflatastic 09427e72be #871: text style shortcuts and text.set detach the bound field they change 2026-10-19 22:09:05 +07:00
bflatastic 1e1b59280d Merge main into #849 2026-10-19 22:07:53 +07:00
bflatastic 97cd06fd14 Merge main into #842 2026-10-19 22:07:50 +07:00
bflatastic ee99a89e08 Merge main into #817 2026-10-19 22:07:49 +07:00
bflatastic 9c7b315301 Merge main into #814 2026-10-19 22:07:48 +07:00
bflatastic b55f009198 Merge main into #811 2026-10-19 22:07:45 +07:00
bflatastic ca3832c0d9 Merge main into #807 2026-10-19 22:07:44 +07:00
justinjohn0306andClaude Opus 5.5 6a163721dc M3: explicit edits of bound scalar fields detach their variable (#809)
An explicit edit of a bound width, height, opacity, gap, padding, corner
radius, stroke weight, arc or text field reported ok, but normalize wrote
the variable's value straight back. Now the edit sticks and that field's
binding is dropped, as paint edits already do.

- `styles::bound_before` / `detach_edited`: compare each layer-level
  bound field's stored value before and after the edit (`bound_field`),
  so keys written unchanged keep their bindings and fields moved along
  with another (proportions, min/max) lose theirs. A binding the edit
  itself made (`boundVariables`) stays. List and component property
  bindings are left to their own rules.
- Hooked into node.set, transform.resize, object.opacityKeys, text.style
  and `Session::preview` (canvas drags of the selected layers).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:33:29 +05:30
NetterSilverandClaude Haiku 5.5 b7c9c712b1 Reject server addresses whose port is not all ASCII digits
Found while testing crates/collab-net/src/invite.rs:valid_host (around line 205)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 11:21:34 +00:00
MortenHustedandClaude Opus 5.5 6f90717e71 M3: effects refuse keys they don't read instead of dropping them
node.set refuses unknown properties, but the effects inside it were read
by serde, which drops keys it doesn't know. A drop shadow given
offsetX/offsetY (the names variable bindings use for its offset) was
stored with the default offset [0, 4] and the call said ok. effect.add
and effect.set dropped them the same way.

The three now refuse what the effect doesn't read and say what it
takes: "effects[0]: unknown properties: offsetX, offsetY (a dropShadow
takes blend, color, offset, radius, showBehind, spread, type, visible)".
A key counts as read when setting it to null makes the effect fail to
parse or come out different, so serde's aliases count as read without a
list of them here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:53:05 +02:00
MortenHustedandClaude Opus 5.5 147a374350 M3: a refused slot names component.makeSlot
component.makeSlot adds its slot property through add_prop, which named
itself in every error: making a second slot called "Content" said
"invalid parameters for `component.addProperty`: a property named
`Content` already exists", a command the caller never ran. add_prop now
takes the command errors name, the fix #807 makes for wrap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:53:04 +02:00
MortenHustedandClaude Opus 5.5 f97789ade1 M7: CSS borders follow individual stroke sides
A layer with individual stroke sides (a header with only a bottom divider,
strokeSides [0, 0, 1, 0]) came out of the CSS, HTML, React and Leptos
code as `border: 1px solid ...` on all four sides, because the border
was written from the stroke weight alone. With individual sides it is now
a border-top/right/bottom/left for each side that has a weight, and a
side bound to a variable names it (border-top: var(--border-top, 3px)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:53:04 +02:00
MortenHustedandClaude Opus 5.5 544b2455c9 M8: a path in a root reached through a link is told why it is refused
When a path can't be resolved (a link that leads nowhere, `..` below a
missing folder), the reason is given only for paths inside a root.
That check compared the path as typed with the roots resolved, so a
root reached through a link (`/tmp/work` on macOS is
`/private/tmp/work`) called its own dangling links "outside the folders
that may be written: /private/tmp/work", and a link out of a root still
had its reason told. The existing part of the path is now resolved
before the comparison, as the roots were.

This is also why `links_that_lead_out_of_a_root_are_outside` and
`outside_paths_are_refused_alike_whatever_exists_there` failed on
macOS, where the temp folder is under `/var` -> `/private/var`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:53:03 +02:00
Muamer MustaficandCursor 79ac16a256 M3: doc comments for the structure commands and binding re-apply (#810)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 23:40:35 +02:00
Muamer MustaficandCursor 85c5286d39 M1: doc comments for the menu invoke and SVG clipboard export (#808)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 23:40:33 +02:00
skylar taylor-barrick a0d1162976 Desktop: refuse unknown command-line options instead of ignoring them (#836) (#844)
A mistyped or unsupported flag (e.g. --automation-write-roots) used to be
dropped silently, so the app started unconfined. It now exits 2 with
'unknown option', like a bad automation root. A bare -- ends the options.

Adds a desktop control-channel test that file.save / file.saveAs outside the
write root are refused and create nothing, while saves inside succeed, and
documents that the root flags arrived in 0.7.0 (0.6.0 ignores them).
2026-10-18 15:20:15 -06:00
NetterSilverandClaude Haiku 5.5 39f30d63c8 Refuse empty mode lists and blank names in variable.createCollection
Found while testing crates/engine/src/cmd/styles.rs:119-124

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 21:27:31 +02:00
Muamer MustaficandCursor 309bac6185 M7: the web build opens files: File ▸ Open, Import and dropped files (#759)
File ▸ Open, Import and Place image did nothing in the browser (the pickers
return a path, which a browser never has) and dropped files were ignored
(eframe hands their contents over asynchronously).

- Services::pick_open_contents: a platform can pick a file's name and
  contents; the web build uses an <input type="file">. Open and Import pass
  them to file.open / file.import as data + name.
- A dropped file without a path waits behind the opening card until its
  contents are read (bytes_async on wasm), or says it couldn't be read.
- Canvas drops still import, as on the desktop.

Closes #759.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 19:32:46 +02:00
Muamer MustaficandCursor b778ba17cd M1: copying text layers puts their text on the clipboard (#808)
edit.copy and edit.cut mirror a selection made only of text layers to the system clipboard as plain text, one layer per line, instead of SVG. Other selections stay SVG; pasting back into FigCraft still pastes the copied layers.

Closes #808

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 16:08:12 +02:00
Muamer MustaficandCursor 4506f49ad4 M3: removing auto layout drops its gap and padding bindings (#810)
layout.remove and node.set {layout: null|"none"} now drop the bindings of auto layout fields (gap, crossGap, padding...), as frame-to-section already did for some of them (it now drops all of them). Re-applying a binding no longer creates an auto layout on a frame without one: the binding waits for the next auto layout.

Closes #810

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 15:21:28 +02:00
MortenHustedandClaude Opus 5.5 d71f24741a #807: test the object.mask and vector.outlineStroke refusals too
Both reach wrap() (a page in a mask, a section outlined into a group)
and named `object.group` before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:18:25 +02:00
MortenHustedandClaude Opus 5.5 c7261cb907 M3: an explicit paint edit detaches the variable bound to what it changed
fill.set, stroke.set and node.set fill/fills/stroke/strokes reported ok
while normalize put the bound colour straight back, and node.set
{fills: []} brought the bound paint back. They now drop a paint's
colour, opacity or stop binding where the edit changed that value, as
selection.setPaint already did (its comparison moves to
lists::rebind_edited_paint, which also lets stop bindings follow a
removed stop). boundVariables applies last in props::apply, so a
binding given with the paints in one call stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:14:38 +02:00
MortenHustedandClaude Opus 5.5 4707cb1579 M1: wrap errors name the command that was run
Grouping, framing, auto layout, masks, outline stroke and the boolean
commands share wrap(), which named `object.group` in every refusal
(`layout.add` on a page: "invalid parameters for `object.group`").
wrap() now takes the calling command's id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 13:58:13 +02:00
BFlat 018b8166b2 M3: a bound colour variable's alpha applies once, not squared (#802) (#804)
Fixes #802.

Fixes #802.
2026-10-18 18:50:19 +07:00
bflatastic 057bf9a289 #801: create_node and mcp.md say width/height scale a vector's path 2026-10-18 17:54:25 +07:00
bflatastic f1d336249a #801: vector.create accepts 0 on an axis the geometry has none of and refuses a flattening size; points scaling tests 2026-10-18 17:54:24 +07:00
bflatastic 55aa0165fd #801: keep a component set's outline as its real stroke (reverts the export change) 2026-10-18 17:41:11 +07:00
bflatastic 836d6f2fa6 Merge main into #801 2026-10-18 17:40:54 +07:00
phonedu aff3c4f18b M1: gate the outline migration on a marker and refuse impossible vector sizes
Review follow-up. A file written by this version carries editorOutlines, so a stroke someone chose is kept even when it matches the old decoration; only files without the marker get the one-time legacy cleanup. vector.create now errors when a requested side cannot scale the geometry or when both axes would collapse, instead of creating an invisible layer.
2026-10-18 18:22:48 +08:00
bflatastic 53c8308b66 #798: test layout grids, code links and interactions (add, change, delete, conflicts) 2026-10-18 17:01:03 +07:00
bflatastic a4c7e259ab #798: layout grids merge item by item, code links merge whole (keyed by language); fix stale doc comments 2026-10-18 17:01:02 +07:00
bflatastic 34b08ac8bf Merge main into #798 2026-10-18 16:57:23 +07:00
phonedu 911831fb89 M1: vector.create scales its path to width/height
A path's intrinsic box replaced the width and height asked for, so an icon imported at 24 stayed on its source grid. Scale the geometry to the requested size; with one side the other keeps its proportion. A path or point set that draws nothing is an error now, not an invisible 0x0 layer.
2026-10-18 17:24:50 +08:00
phonedu be47f99534 M1: component sets keep the dashed canvas outline out of the document
Node::new gave every component set a purple dashed stroke, so export and screenshot drew the editor frame into the image. Sets now start with no paint; the canvas draws the dashed frame itself, and files written by earlier versions lose exactly that stored decoration when opened. A stroke someone chose is kept.
2026-10-18 17:24:49 +08:00
bflatastic d1125130f6 #794: translate the slot-layers import note added on main 2026-10-18 16:14:45 +07:00