Commit Graph
541 Commits
Author SHA1 Message Date
bflatastic dc0ce6c176 Merge #1181: Refuse text.loadFont path for plugins (@Silvertree2010) 2026-10-24 09:18:13 +07:00
bflatastic 2a20a4de0a Merge #1190: Refuse non-local library paths in the library Cache (@Silvertree2010) 2026-10-24 09:18:10 +07:00
bflatastic e3c9d3f644 Merge #1191: Deny library.publishToServer to plugins (@Silvertree2010) 2026-10-24 09:18:07 +07:00
bflatastic f3782e6bc4 Merge #1023: fix(engine): show the Pen's Shift 45° step in its preview line (#970) (@vxMacDev) 2026-10-24 09:17:11 +07:00
bflatastic eada8b0ff3 Merge #1042: M3: style links given in a call apply after its values (@MortenHusted)
# Conflicts:
#	crates/engine/src/cmd/props.rs
2026-10-24 09:16:54 +07:00
bflatastic 90e5e03b23 Merge #1160: M0.9: figcraft-cli export names files as the app's export does (#1154) (@switch87) 2026-10-24 09:16:12 +07:00
bflatastic 15321a56ff Merge #1198: fill/stroke props: accept 'none' and null as no paint (@lileeei)
# Conflicts:
#	ROADMAP.md
2026-10-24 09:16:04 +07:00
bflatastic 6063d3e9a9 Merge #1189: M4: vector edit transform box around points of several layers (@marcoarnulfo)
# Conflicts:
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-24 09:15:11 +07:00
bflatastic 8eb5624460 Merge #986: fix: = zooms in, matching - zooming out (#973) (@Ridzzz0Alam) 2026-10-24 09:13:43 +07:00
bflatastic f31199d4ca Merge #1018: M1: a selected unfilled shape drags from inside its box (#910) (@muamerETS) 2026-10-24 09:13:38 +07:00
bflatastic 370faa52da Merge #1033: M3: a variant switch takes the new variant's resizing unless the instance set its own (@MortenHusted) 2026-10-24 09:13:33 +07:00
bflatastic 98040b48a5 Merge #1037: M3: a variable mode set on a layer inside an instance is an override (@MortenHusted) 2026-10-24 09:13:23 +07:00
bflatastic 83f840f802 Merge #1043: M3: a swapped nested instance keeps its outer main's overrides (@MortenHusted) 2026-10-24 09:13:18 +07:00
bflatastic 2053098e8e Merge #1200: The colour picker's eyedropper applies the colour to the paint the picker edits (Reported in storytold/vectorcraft#3342) (@marcoarnulfo)
# Conflicts:
#	crates/engine/src/tools.rs
2026-10-24 09:12:42 +07:00
BFlat 8167f13a6a M12: Boards: a collaborative whiteboard file kind (#1229)
Board files (File > New board) with sticky notes, shapes with text, connectors that follow what they join (straight or elbow, arrowheads, labels), marker, highlighter and eraser, and stamps; a board toolbar and a contextual bar; the Design panel hidden on boards, Prototype and Dev Mode refused there. Boards are ordinary FigCraft files built from ordinary layers, so saving, undo, export, MCP and live sessions work unchanged. File tabs, recent files and Open files show a pen nib for design files and a note for boards (original icons drawn in code).
2026-10-24 04:18:55 +07:00
BFlat 17ed21d128 M6: Dev Mode tail: imports in layer trees, compare with versions, an inspect-only canvas (#538)
Import lines for connected components inside generated layer trees; Compare changes against any saved version; a Dev Mode behaviour suite with an inspect-only canvas (menus, shortcuts, paste and Revert to saved refuse design edits; a drag under way is dropped on entering), Changed in the ready list, statuses only on top-level frames and sections; read-only plugins' panels from the Inspect tab.
2026-10-24 02:56:55 +07:00
aiongg 6ba0223636 Tests: the paragraph indent test loads system fonts and skips only without glyphs (#1227) 2026-10-23 13:50:42 -04:00
Marco Arnulfo 2a6e460a7b Let the box of another layer's points win over a region of the active one
With points selected only on another edited layer, a press inside the
combined box over an unselected filled region of the active layer picked
the region instead of dragging the box. Other layers' selections now count
in the same priority check; a press on an already selected region still
drags the regions.
2026-10-23 10:17:56 +02:00
Marco Arnulfo 410c1f10e2 The colour picker's eyedropper applies the colour to the paint the picker edits (Reported in storytold/vectorcraft#3342) 2026-10-23 04:08:48 +02:00
NetterSilverandClaude Haiku 5.5 b57c67782f Deny library.publishToServer to plugins
Fixes #1055

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 23:54:59 +02:00
NetterSilverandClaude Haiku 5.5 b3e65c89f9 Refuse non-local library paths in the library Cache
Fixes #1056

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 23:46:52 +02:00
Marco Arnulfo 1f2a8104bf M4: vector edit transform box around points of several layers
With points selected in more than one edited layer the transform box now
wraps them all, in the page's axes since the layers can be turned
differently. Its corners and edges scale them, outside a corner rotates
them and inside drags them; each layer's points are mapped in its own
coordinates and the whole drag is one undo step. A click inside clears
every layer's points.
2026-10-22 23:37:49 +02:00
NetterSilverandClaude Haiku 5.5 b8741162cd Refuse text.loadFont path for plugins
Fixes #1071

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 22:57:58 +02:00
Gert Pellin eb07717783 M0.9: trim mixed edge spaces and dots, document the name limits (#1154)
Review: " . .name. . " kept inner dots at the edges; trim spaces and dots
in one pass. docs/cli.md and safe_file_name's comment give the 100 and
200 character limits.
2026-10-22 21:43:52 +02:00
Gert Pellin ca30791fd7 M0.9: figcraft-cli export names files as the app's export does (#1154)
export into a folder replaced every character outside letters, digits,
'-', '_', space and '.' with '_', so a frame called
"Homepage - desktop (live + verbeteringen)" became
"Homepage - desktop _live _ verbeteringen_.png". The app's
file.exportLayers keeps those names and only replaces what file systems
refuse. The CLI now uses the engine's safe_file_name, and docs/cli.md
says which characters are replaced.

Also adds my own entry to contributors/people.toml.
2026-10-22 21:22:20 +02:00
lileeei 2437a65d1b M1: fill/stroke props accept "none" and null (#1036)
node.create, node.set and the other prop appliers map fill/stroke
"none" (either case) and null to an empty fills/strokes list, as
fills: [] already did (undocumented), so an outline-only shape is one
call - agents write "none" for no paint. KEYS and docs/mcp.md
document it; the error names the accepted forms. fill_none_tests
covers create, set, undo, text and the error.
2026-10-22 23:04:57 +08:00
MortenHusted f1c206509f M3: files from before the modes override keep the modes set inside their instances
A file or library saved before "modes" was an override group has a mode
chosen on a layer inside an instance without its marker, so the next
rebuild or library import still put the main's mode back.

Copies follow their main layer's modes when the main changes them, so a
layer inside an instance on other modes chose them itself.
mark_layer_modes marks those when a file opens and when a published
library is read from a file or a server. Layers on their main's modes
and top-level instances stay unmarked.
2026-10-22 13:41:56 +02:00
MortenHusted 6394e96005 M3: a variable mode set on a layer inside an instance is an override
A variable mode chosen on a layer inside an instance (the icon inside a
Close button, recoloured through an icon colour collection) wasn't an
override group. A full rebuild of the instance starts each layer over
from its main and carries only override groups, so the mode fell back
to the main's. Library import always rebuilds, as do main edits such as
a new auto layout direction, so a modal's recoloured close icon came
into other files in its default colour.

"modes" is now an override group: setting a mode inside an instance
records it, rebuilds carry it, rebasing a nested instance finds it, the
component panel lists it, and resetting it brings back the main's mode.
A top-level instance's own modes stay its own and record no override,
like its resizing.
2026-10-22 13:41:56 +02:00
MortenHusted c141dee771 M3: a swapped nested instance keeps its outer main's overrides
A Button main's override on its icon instance's glyph (a red fill) was
lost when an instance swapped the icon: the outer rebuild re-copies the
glyph from the main's layer with no overrides of its own, so the nested
rebuild matched it by name and carried nothing. Before that rebuild, each
old layer of the swapped instance now takes the overrides held along the
source chain it had before this rebuild, through layers inside instances
in the mains that place the swapped instance. Geometry, slot content and
groups the layer overrides itself are left out. Matched by name, the
values carry onto the new main's layer as the instance's own: inherited
at the swap, frozen after, and back to the icon main's value on reset.
An icon main's own overrides stay with it.
2026-10-22 11:26:04 +02:00
MortenHusted 24a5855cab M3: style links given in a call apply after its values
apply_order gave fillStyle, strokeStyle, effectStyle, gridStyle and
textStyle the rank of plain values, so the JSON map's byte order decided:
fills, strokes, effects, grids, layoutGrids and variationSettings sort
after their link and overrode it (node.set then unlinked the style;
node.create kept a link its values contradicted). Style links now apply
after the values and x/y, just before boundVariables. A deviation set in a
later call still unlinks.
2026-10-22 11:11:59 +02:00
MortenHusted 8ee0218d19 M3: a variant switch takes the new variant's resizing unless the instance set its own
Switching an instance to another variant copied the old root's sizing
and min/max back over the new variant's on the rebuild, so an instance
switched from a hugging variant to a fixed-width one whose children
fill kept hugging at the old width. The next edit then turned those
children Fixed, as a child can't fill an axis its parent hugs.

Resizing still equal to the old variant's was never the instance's own,
so on a sibling-variant switch it now follows the new variant; sizing or
min/max the instance set itself stays.
2026-10-22 09:33:12 +02:00
vxMacDev 3d41302f23 fix(engine): show the Pen's Shift 45° step in its preview line (#970)
A Shift-click with the Pen already put the next point at a 45° step
from the last one, but the line drawn to the pointer while moving
ignored Shift and followed the pointer, so holding Shift looked like it
did nothing. The line now ends where the click will put the point. Both
use one helper, at_45_degrees.
2026-10-21 19:47:01 -05:00
Muamer MustaficandCursor 84b48bc797 M1: the drag-from-inside fallback tests the selection's turned box (#910)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 00:19:13 +02:00
Muamer MustaficandCursor 795567f016 M1: a selected unfilled shape drags from inside its box (#910)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:37:09 +02:00
Ridzzz0Alam f619dca716 M1: = zooms in as - zooms out (#973)
Plain `-` zoomed out but plain `=` (the `+` key without Shift) did nothing,
so a canvas zoomed out with `-` couldn't be zoomed back in the same way;
held down, `-` reaches the 2% floor and `=` leaves you there. Ctrl+Shift+=
zoomed in while Ctrl+Shift+- did nothing either.

Found with a trace of the input on GNOME Wayland: Ctrl+wheel, Ctrl+=,
Ctrl+-, Ctrl+Shift+= and `-` all reach the canvas and zoom; `=` and
Ctrl+Shift+- arrive too but no binding takes them.

`view.zoomIn` gains `=` and `view.zoomOut` gains `Shift+Cmd+-`, pinned in
the shortcut parity table; neither key was bound elsewhere and the menus
still show Ctrl/Cmd and `+`/`-`. A keymap test checks each zoom-in key
has its zoom-out twin on both platforms.
2026-10-21 17:41:30 +02:00
BFlat 123e46550f Merge pull request #909 from RiceDee/fix/component-set-name
#903 follow-up: name new component sets from the variant path, not the first property
2026-10-21 16:31:04 +07:00
BFlat bb532a5790 Merge pull request #908 from RiceDee/feat/903-variants-discoverability
#903: Combine as variants in the context menu and Design panel; Add variant on a lone component
2026-10-21 16:01:25 +07:00
BFlat f143260c3a Merge pull request #935 from YarilaFox/fix/saved-document-title
M7: show the chosen filename for saved documents
2026-10-21 15:47:09 +07:00
NetterSilverandClaude Haiku 5.5 8b198ea364 Strip default port in same_server when the address has a path
Found while testing crates/engine/src/online.rs:118

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 15:41:47 +00:00
YarilaFox 23463f719b M7: keep saved document titles in sync with filenames 2026-10-20 17:56:30 +05:00
RiceDee b5a315a748 #903: name a new component set from its variants' path, not their first property
A component set took its name from the first variant's name up to the first '/' or '=',
so variants named "State=Default, Size=Small" made a set called "State". The set now
takes the path before the last '/' ("Button/State=Hover" -> "Button",
"Icons/Arrow/Dir=Up" -> "Icons/Arrow"), keeps a plain name as is ("Button"), and
otherwise gets the next numbered default ("Component 1"), as a new component does.
2026-10-20 16:32:16 +11:00
RiceDee bcd5b6e632 #903: Combine as variants in the context menu and Design panel; Add variant on a lone component 2026-10-20 16:18:13 +11:00
bflatastic f979878d9e Merge main into fix/issue-892
# Conflicts:
#	ROADMAP.md
2026-10-20 06:09:17 +07:00
bflatastic 8a46478e81 Merge main into fix/issue-879
# Conflicts:
#	ROADMAP.md
2026-10-20 05:46:30 +07:00
bflatastic b82369201d M3: duplicating a main component makes an instance (#892)
Duplicate and Alt-drag copied a main component as a second main. Within
its file the copy is now an instance of it (components::copy_in_file,
shared by edit.duplicate and the Alt-drag copy), as Copy then Paste
already was. A variant duplicated in its set stays a new variant.
2026-10-20 05:44:46 +07:00
bflatastic 05da6b2125 M1: node.get reports layer data (pluginData) (#879)
Layer data written with node.set {props: {pluginData}} was saved but no
command read it back. node.get (the command, the control method and MCP
get_node) and document.inspect now report pluginData as {key: value}
when a layer or page has any, so a tool keeping state in a file can
read it on its next run. Widget keys are included: the plugin rules
only stop plugins writing them, and widget.list already reports that
state.
2026-10-20 04:58:32 +07:00
bflatastic cc4799061e #889: say a join is too large in words for people (native and web), translated; keep one test 2026-10-20 04:38:28 +07:00
bflatastic 4b030f027a Merge main into #872 2026-10-20 03:20:30 +07:00
BFlat 1abb9083c7 Merge pull request #821 from attisvalentin/fix/rescan-and-load-fonts
M4: fonts installed while the app runs: text.rescanFonts, text.loadFont, text.refit
2026-10-20 03:04:29 +07:00
BFlat 4788c6b819 Merge pull request #870 from MortenHusted/fix/component-paste-instance
M3: copied components paste as instances within their file
2026-10-20 03:04:03 +07:00