Commit Graph
4092 Commits
Author SHA1 Message Date
Trevor BrownandClaude Opus 5.5 8e1a2ff262 M10: Docs: the hardware-parity row keeps its three cells (#1343)
A bare pipe inside the code span `WS_CAPTION | WS_BORDER` split the table row; the two style
names are separate code spans now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
2026-11-11 00:35:51 -05:00
Trevor BrownandClaude Opus 5.5 19c8e01811 M10: Design panel: 24 pt icon buttons draw 16 pt glyphs, as a fill row does (#2227)
A live check showed the header's eye still smaller than a fill row's: `icons::button`, which
draws the fill rows, paints the icons' native 16 px glyph in a 24 pt button, while the shared
inset gave 14. The inset is now 4, so section headers, `icon_button_at` and the panels' Close and
Swap buttons draw 16 pt glyphs like the rest. The test compares the header's eye with both
`icon_button_at` and `icons::button`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
2026-11-11 00:08:06 -05:00
Denis GomesandClaude Opus 5.5 503823f958 M8: hardware-parity names the copy an image draws from
The canvas takes the smallest copy that holds the size an image shows in
device pixels, whatever the canvas zoom, as #1483 did for images over
4096 px. The canvas row said the copy was no larger than the image shows,
and both changelog rows said views at 100% and closer draw from the image
itself; a 3000 px image fitted into a 600 px layer draws from a 1024 px
copy at 100%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 20:56:35 -05:00
Trevor BrownandClaude Sonnet 5.5 97ceeca35e M10: Windows: the window no longer draws below a hidden caption (#1343)
FigCraft draws its own title bar on Windows and opens undecorated windows, but winit 0.30 still gives them WS_CAPTION | WS_BORDER. On some systems the desktop compositor reserves that caption, so the content is drawn about 30 px low (a black band above it) while clicks keep the client coordinates and land above what is drawn. Fixes #1343; the same report as #1422 and #2233.

A per-frame step (apps/figcraft/src/window_frame.rs, run from raw_input_hook) clears WS_CAPTION and WS_BORDER from every winit window of the process (the main window and the other windows alike), keeps WS_THICKFRAME and the window buttons so edge resizing and snap work, and calls SetWindowPos(SWP_FRAMECHANGED) only when a style changed. It uses safe winsafe calls (no unsafe), Windows only; other platforms and the browser are unchanged. The maximize-to-work-area trim of DesignCraft's fix is left for a later change.

Ports the fix of DesignCraft #2139 and PhotoCraft #2401. Tests: the style arithmetic (caption and border cleared, thick frame and buttons kept, a clean style unchanged) and the per-frame hook (runs every frame, a no-op when unset).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-10 20:55:23 -05:00
ljkx 0ad70b9501 M1: a programmatic paste after a property copy whose engine copy is gone pastes no stale layers (#1494)
A row's fill copied through the control channel, then a stroke copied by
a command, left the fill off the engine clipboard; a programmatic paste
then fell through to the layers copied before the fill. It now does
nothing, as a user's paste already did.

Tests: the programmatic case above, an effect paste replacing the
highlighted effect above the bottom one (index 1), and a property copied
in one window pasting in another while the highlight stays in its window.
2026-11-10 23:31:31 +01:00
Trevor BrownandClaude Sonnet 5.5 ebcaa58c4f M10: Design panel: section header icons draw at the panel's icon size (#2227)
Section header buttons painted their glyph in a 12 pt box inside the 24 pt button while icon_button_at used 14 pt. Both now use icon_glyph_rect (ICON_BUTTON_INSET 5 pt), as do the 24 pt Close and Swap buttons in the assets and prototype panels. Test compares the painted Eye bounds of a header and an icon button.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-10 15:55:41 -05:00
Trevor BrownandClaude Opus 5.5 4c91f9084b M4: round_corners: each contour's own size sets its weld tolerance (#2222)
The tolerance that drops the sweep's slivers came from the whole path's bounding box, so a
contour a million units wide welded away the real half-unit edges of a separate small contour.
Each closed subpath now sets its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
2026-11-10 15:39:09 -05:00
Trevor BrownandClaude Opus 5.5 ec105d0f56 M4: The radius field shows what a one-radius layer draws (#2222)
A boolean group, polygon, star or vector draws its first radius. Per-corner values a script or a
file left behind made its field read Mixed, and a relative edit started from the largest. The field
now shows radii[0] for those kinds, and a relative edit starts from it; rectangles and frames are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
2026-11-10 14:44:12 -05:00
Trevor BrownandClaude Opus 5.5 bae366ba51 M4: Boolean groups: test the one-radius panel through corner smoothing (#2222)
The field test's "no field per corner" check passed for any shape, since corner fields are built
only while the individual-corners popover is open. A boolean group's button now has its own test
beside the polygons' (shared helper): it is named Corner smoothing, opens no corner fields, and
sets the smoothing in one undo step. ROADMAP's status line reads minor, as the other docs do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote; Fable 5.1 reviewed
2026-11-10 13:53:13 -05:00
Trevor BrownandClaude Sonnet 5.5 529134b850 M4: a boolean group's corner radius rounds its result (#2222)
A boolean group takes a corner radius (and corner smoothing): the Design panel shows the field for it, `node.set cornerRadius` writes it, and the renderer rounds every sharp corner of the group's result after the fold, convex and concave alike. Layers inside keep their own radius and do not stack with it, a radius larger than the edges allow shrinks to fit while the field keeps the typed value, Flatten bakes the arcs, and a mixed selection reads Mixed. Measured in Figma's web app on 2026-11-10.

The rounded result is cached apart from the fold (keyed by the folded path, radius and smoothing), so scrubbing the radius never redoes the boolean steps. The .fig and REST importers and the .fig exporter now carry the radius and smoothing of a boolean group, and paste properties and radius variables reach it. Docs: ui-parity, target-app-parity, gaps, file-format-parity, ROADMAP, mcp.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 designed; Sonnet 5.5 wrote at medium
2026-11-10 13:36:10 -05:00
Trevor BrownandClaude Sonnet 5.5 c48d844d22 M4: round the sharp corners of a closed path (pathops, #2222)
Add figcraft_pathops::round_corners(path, radius, smoothing): every vertex of a closed subpath that is still sharp rounds with a circular arc, convex and concave alike. The sweep's noise is cleaned first (short pieces welded, straight runs merged), smooth joins are not corners, and a corner shrinks to what the edges beside it can hold (half an edge when both ends round, the whole piece beside a smooth join). Corners between straight edges use smoothed_corner; corners beside a curve cut both sides and join them with one cubic. A subpath with nothing to round comes back unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 designed; Sonnet 5.5 wrote at medium
2026-11-10 13:11:56 -05:00
Trevor BrownandClaude Sonnet 5.5 281918e2f2 M7: Text styles: a face name bound after a weight clears the axis; review fixes (#2174)
A style's fontStyle binding now goes through set_font_style, so it drops the stale wght axis a weight binding left behind. Also: a test and doc line for the token_roles weight role, the apply-order comment, the weight chip opening the weight picker, junk weight values pinned, fixture assertions fixed, and the ROADMAP and parity status lines.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 reviewed; Sonnet 5.5 wrote at medium
2026-11-10 13:09:35 -05:00
FredApps be991533b0 Merge pull request #2207 from storytold/sonar/format-mandated-sha1
sonar: SHA-1 image names in .fig export are the format's, not a choice
2026-11-10 18:45:47 +01:00
Trevor BrownandClaude Sonnet 5.5 ccb33e0bbc M7: Text styles: bind a number variable to the weight (#2174)
A text style takes a Number variable on `fontWeight` (`style.bind`): the style gets the face nearest the number and sets the `wght` axis, so static and variable fonts both follow. A bound weight and a bound face name replace each other, and the weight wins in a file carrying both. The style editor's weight menu offers number variables beside string ones, and a variable bound to a weight is Unitless in the CSS export. A number bound to a line height stays pixels, as the reference tool applies it; a test pins that.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 designed; Sonnet 5.5 wrote at medium
2026-11-10 12:43:24 -05:00
FredApps e92d5cbd56 Merge branch 'main' into sonar/format-mandated-sha1 2026-11-10 18:23:29 +01:00
amorSoftLabsandbflatastic 2af535c132 fix(ui): access preferences from home screen via shortcut and sidebar (#956) (#962)
* fix(ui): access preferences from home screen via shortcut and sidebar (#956)

* fix(ui): handle preferences shortcut before popup guard

* docs: add docstrings for modified functions to satisfy coverage check

---------

Co-authored-by: bflatastic <bombayapirat@gmail.com>
2026-11-10 17:58:20 +01:00
Trevor BrownandClaude Opus 5.5 a1de7dcd26 M10: Export: test a blurred pane inside a frame (#2213)
The reporter's case: the pane sits in a frame over another layer. Exported on its own it keeps
the blurred layer beneath it and the frame's fill behind it, opaque, as on the canvas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
2026-11-10 11:04:49 -05:00
Trevor BrownandClaude Sonnet 5.5 020388cf1f M10: Export: a background blur or glass exported on its own keeps the content behind it (#2213)
An export of a layer draws only that layer, so a background blur or glass in it read an empty
backdrop. The export now renders the page's layers below the first exported layer, with the margin
the effects reach, as the backdrop (render_area_over), clipped to the export area; only the exported
layers are drawn on top. Layers without those effects, and every other export path, are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-10 10:31:10 -05:00
Trevor BrownandClaude Opus 5.5 a415598e11 .jam import: board items only on frames, authors without control characters, board items in the dump (#1808)
From the pre-ready review: a sticky or shape item on a non-frame layer is ignored with the warning; the author drops control characters as board.sticky does; dump_samples writes a whiteboard's board items; a doc link made plain text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote; Fable 5.1 reviewed
2026-11-10 09:43:30 -05:00
Trevor BrownandClaude Sonnet 5.5 4201fed27d M9: .jam import: stickies come in as native board stickies (#1808)
On a FigJam whiteboard the mapper builds a sticky with complete generated records as a native board sticky: the saved colour, size, place, opacity and shadows, the note and the author line as text layers, no background vector. It writes a board field on the REST JSON, which the REST importer reads (junk values are ignored with a warning). Damaged stickies and stickies in a .fig keep the generated layers.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 briefed; Sonnet 5.5 wrote at medium
2026-11-10 09:17:19 -05:00
Carbocode 67c232eab2 M1: strengthen page transparency and sidebar review tests 2026-11-10 12:50:16 +01:00
FredApps 73e3720083 sonar: SHA-1 image names in .fig export are the format's, not a choice 2026-11-10 11:22:16 +01:00
impulsado a66946d13e M3: strengthen inherited slot property regression coverage
Cover inherited Boolean bindings and independent same-component slot content. Strengthen text, HTML and stored-property assertions, split default and own-content cases, and document ownership-based binding resolution.
2026-11-10 09:34:17 +01:00
Trevor BrownandClaude Sonnet 5.5 6d128d3377 Cursors: the crosshair is drawn dark with a white edge, so it shows on a white frame (#2198)
Cursor::Crosshair was the system's crosshair, whose colour follows the pointer style and
was white on Windows, lost on the default white frame. It is now Glyph::Crosshair, painted
from lines like the pen: a plus with 2 px open at the centre, a 3 px white edge under 1 px
dark lines. Prototype connections still set the system crosshair directly.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-10 02:48:54 -05:00
Denis GomesandClaude Opus 5.5 c82986b26c M8: zoomed-out images draw from small copies that stay decoded
The canvas drew an image shown smaller than its pixels from a 4096 or 8192 px
copy, and an image of 4096 px or less from itself, whatever its size on screen.
A page of a few hundred photos zoomed out then asks the decoded-image cache
(512 MB) for several GB: every render decoded them again, and a zoom out took
seconds with the canvas empty around the old frame.

The copies now also come at 256, 512, 1024 and 2048 px, the smallest that holds
the size shown. Measured on a file with 237 images (median 5.8 MP), canvas
options, 2352 x 2090 view, M4 Max:

| zoom | before | after, first | after, again |
|---|---|---|---|
| 10% | 0.25 s | 0.12 s | 6 ms |
| 4%  | 0.88 s | 0.46 s | 7 ms |
| 1%  | 3.4 s  | 0.9 s  | 4 ms |

Peak memory over the run went from 3.9 GB to 2.3 GB. Exports and views at
100% and closer still draw from the image itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 02:39:52 -05:00
Trevor BrownandClaude Opus 5.5 da81d55a64 Transform: Shift-rotating inside a rotated frame lands the page rotation on multiples of 15
Measured in Figma: a layer's rotation field shows its rotation on the page, also inside a rotated frame or group, and Shift snaps that value. A test pins it; the doc comment on shared_rotation_degrees says so. Review item on #2096.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote; Sonnet 5.5 measured in Figma
2026-11-10 02:14:17 -05:00
Trevor BrownandClaude Opus 5.5 30767bd2b2 M3: the eyedropper picks a magnified image's pixel under the pointer (#2189)
The eyedropper rendered its 1x1 sample with default render options, without the canvas's
magnified-image pixels, so on an image shown past 2x it took a bicubic blend of a 1 px line and
its neighbours: the reporter's #3D444D border beside a darker background came out darker. The
sample also began at the pointer instead of being centred on it, half a screen pixel off. It now
renders as the canvas does (magnified_image_pixels) and centres the pixel on the pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 found the cause from the reporter's values and wrote; Sonnet 5.5 investigated the flat cases at medium
2026-11-09 18:53:03 -05:00
Trevor BrownandClaude Opus 5.5 21d0594614 M3: the Selection colors rows agree on library styles and qualify the one-colour case (#2191 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 checked the findings and wrote
2026-11-09 18:38:13 -05:00
Trevor BrownandClaude Sonnet 5.5 dadd4dfc69 M3: Selection colors shows for a layer with children from one colour (#2188)
Measured in Figma web app 2026-11-09: a selection holding a layer with children (frame, group, component, instance) shows Selection colors from one distinct colour; layers without children need two. The section now shows when there are two colours, or one colour and a selected layer with children. Tests in selection_colors_tests; ui-parity updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and briefed; Sonnet 5.5 measured in Figma and wrote at medium
2026-11-09 16:50:45 -05:00
ljkx 61389cdd5f M4: test the simplified stroke by how far it strays, at more accuracies and inputs (#1741)
Review follow-ups, tests only.

- The Pencil test and the `vector.simplify` test measure how far the result
  strays from the samples (at most 1.5), not only its box.
- The Pencil test also draws with the Marker and the Highlighter, each stroke
  in a fresh session, and takes the layer that stroke made.
- The `vector.simplify` test runs on an open stroke, a filled shape, a region
  with its own fill, and a stroke beside a filled shape.
- The geom tests run at accuracies 0.1, 0.75 and 8.0, on quadratic and cubic
  inputs as well as lines, and check both ways round how far the result and
  the input are apart.
- A path that turns straight back is checked to be kurbo's fit of each side on
  its own, with a point at the turn.
- Empty paths, lone moves and segments after a close are covered.
2026-11-09 21:51:37 +01:00
ljkx 33ac1d14fc M1: Cmd/Ctrl+C and Cmd/Ctrl+V copy and paste the highlighted fill, stroke or effect (#1494)
With a fill, stroke or effect row highlighted, Cmd/Ctrl+C (or Edit ▸
Copy) copies that paint or effect instead of the layers, through the
same `fill.copy`, `stroke.copy` and `effect.copy` the row's menu runs.
Cmd/Ctrl+V then pastes it onto every selected layer with `fill.paste`,
`stroke.paste` or `effect.paste`, one undo step: on top of each layer's
list, or in place of the highlighted row when it is of the same kind.

- A copy keeps its kind. A stroke goes to the strokes and an effect to
  the effects whatever row is highlighted, and the last row copied is
  the one pasted.
- A solid colour goes to the system clipboard as its hex code, anything
  else as a marker. A paste takes the property only while the system
  clipboard still holds that copy and no layers were copied since, so
  text or an image from another app, or a later layer copy, pastes as
  before. The row menus' Copy writes the same, so Cmd/Ctrl+V pastes it.
- A programmatic copy never writes the system clipboard, and forgets a
  property mirror it replaced. A mirror whose engine copy is gone pastes
  nothing rather than the layers copied before it.
- The copy is shared by every window, as the layer copy is.

Tests: property_rows_tests (15 more, 22 in all); the replace index and
the Escape key were each removed once to check the tests fail.
2026-11-09 20:34:32 +00:00
ljkx 375a7b8abb M1: a click on a fill, stroke or effect row highlights it (#1494)
Fill, stroke and effect rows in the Design panel couldn't be selected.
A click on a row's reorder grip (the strip left of its fields) or on its
background between its controls now highlights it in the selected-row
colour, one row at a time, as the help center's "Copy and paste
properties between layers" describes ("Click to highlight the property
on the right sidebar").

- The row is a click target under its controls (`row_target`), and the
  grip of these lists also takes a click (`ListDrag::row_clicked`).
  Neither is focusable, so Tab still goes from control to control.
- The highlight belongs to the selection, file and Design tab it was made
  on. Escape lets it go before it deselects; so does a press on the
  canvas or elsewhere in the Design panel, or a frame its row isn't
  drawn in (an undo took its paint away). It follows its paint or effect
  when rows are reordered or removed.

Tests: property_rows_tests (7).
2026-11-09 20:30:25 +00:00
ljkx 938f8b2ad9 M8: test that .. after a link is taken by name on Windows (#1094)
A junction, which any account can make, leads out of the root; the path
through it and back with `..` is the file in the root, to the check and to
Windows when it opens it.
2026-11-09 21:29:18 +01:00
ljkx 966aa7b263 M8: automation roots refuse a path they can't look at, and review follow-ups (#1094)
Review of the fix for #1094:

- A path that can't be made absolute is refused instead of going on to be
  resolved.
- A name on the way that can't be looked at for a reason other than nothing
  being there (no permission, for one) is refused: it may be a link that
  resolving would follow. Only "not found", "not a directory" and "invalid
  filename" count as nothing there.
- Tests: the link part of the Windows test is its own test, so the spelling
  and device checks no longer share a test with a part that is skipped where
  links can't be made; the timing assertion is gone (the messages tell the
  cases apart); link chains of 39, 40 and 41 links; a root on a share against
  every network spelling, in both of the root's spellings; devices for read
  and write; `..` after a link; paths that aren't UTF-8.
- Docs brought in line with the code.
2026-11-09 21:23:20 +01:00
Trevor BrownandClaude Sonnet 5.5 e415a3a0fb M2: pin the leading-edge drag reorder at its boundaries, zero delta and several layers (#2142 review)
Tests for the -129 leftward boundary, the vertical boundaries both ways, a drag with no move along the flow, and several moving layers using their combined box. Doc comments say whose edge is "leading" and what the caller passes; the parity row names the unchanged cases and the web-app measurement source.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 triaged and briefed; Sonnet 5.5 verified and wrote at medium
2026-11-09 15:16:36 -05:00
Trevor BrownandClaude Sonnet 5.5 1ef0c16fdf M8: invert zoom direction tests: Ctrl wheel, panning unchanged, pinch both ways, off persists (#2147 review)
Tests only. Ctrl+wheel joins Cmd+wheel; panning (plain wheel, Cmd/Ctrl+wheel and Shift+wheel with Scroll wheel zoom on) is compared between invert on and off; the pinch runs with Scroll wheel zoom on and off and with factors above and below 1; the pref's off value is saved and reloaded.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 triaged and briefed; Sonnet 5.5 verified and wrote at medium
2026-11-09 15:11:14 -05:00
Trevor BrownandClaude Sonnet 5.5 ff7305266c M8: the Annotation tool checks its target first, tool.set asks for the note too, one Developer Mode tool list (#2143 review)
tool.annotation validates a named id or ids before changing the tool: a page or unknown layer is an error, and a named layer is always selected. Choosing the tool with tool.set (the toolbar) asks for the selected layer's note like Shift+T. annotation.new only sets the focus request for a selected, non-page layer, so it cannot wait and take the keyboard later. ToolId::works_in_dev_mode is the single list behind the pointer routing, the command allowlist and the toolbar. The press never picks the page. Tests for the invalid targets, the toolbar path, a drag, the re-focus, and a request for an unselected layer.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 triaged and briefed; Sonnet 5.5 verified and wrote at medium
2026-11-09 14:59:32 -05:00
Trevor BrownandClaude Sonnet 5.5 7a8d422dec M8: the Scale field only takes the keyboard when the tool is chosen or the panel returns, and Ctrl/Alt+Enter keep the tool (#2148 review)
A stale "field had the keyboard" flag no longer ends the tool on the first frame back from another tab. A selection appearing after K with nothing selected no longer moves the keyboard from the canvas to the Scale field. Ctrl+Enter and Alt+Enter are not the tool's exit. Tests pin the full text selection, the 2x and 1.5 factors, the field letting go after Enter and Escape, idle frames after Tab, and a leftover edit dropped on return.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 triaged and briefed; Sonnet 5.5 verified and wrote at medium
2026-11-09 14:47:06 -05:00
Trevor BrownandClaude Opus 5.5 499717d6a0 M7: the variant connection docs name the grouped-set case and target_at's None cases (#2161 review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 checked and wrote
2026-11-09 14:32:49 -05:00
ljkx a54eafc0fc M1: test that picker Crop only sets the mode where Crop image doesn't apply (#2150)
Choosing Crop in the colour picker starts crop mode only for one layer's
own image fill. The new test chooses Crop for a stroke, for two layers'
fills at once, and for a region's fill in vector edit mode (the layer's
own fill an image too). In each case it checks that the paint takes the
Crop mode, crop mode does not start, and the picker stays open. It also
checks that crop_on_canvas gives nothing for a solid fill, an index with
no fill, the page background and a style.
2026-11-09 20:08:46 +01:00
Trevor BrownandClaude Sonnet 5.5 bb6d1c35ee M12: a board table's height change goes into its rows (#2172)
Resizing a board table by its bottom edge, a corner or a height command left it at a fixed height, so its rows stayed at 40 with blank space below them (or were clipped when shrunk) and typing in a cell no longer grew the table. Measured in FigJam's web app (2026-11-09): a table has no lock-proportions control and never scales proportionally; a bottom edge grows only the last row, a corner drag shares the change equally over every row and column, text keeps its size, and a cell has a minimum size.

board_table::settle_resize runs first in the normalize pass (so a drag, node.set, transform.resize, MCP and live-session peers all agree): a table left at a fixed height gets the change in its rows' minimum height (the last row, or every row when both axes changed), is kept at least columns x 40 wide, and hugs its rows again. New cells get a minimum width of 40. FigJam's floor is about 52 and FigCraft's is 40; there are no per-column widths yet.

Docs: boards-parity Tables row, revision history and status line; the board_table module doc.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and briefed; Fable 5.1 (work seat) scoped; Sonnet 5.5 measured in FigJam and wrote at medium
2026-11-09 14:02:07 -05:00
Ragulsundaram 6108efd4d2 i18n(ta): shorten Min W to match the other size labels 2026-11-10 00:11:02 +05:30
skylar taylor-barrick a2e87433d8 Naming: Developer Mode follow-ups (#2165)
* Naming: record Developer Mode in the feature-names doc and the stage paragraph

docs/feature-names.md gains the entry for the rename: the old label, the new one, Figma's
US registration for DEV MODE (7574348) as the reason with its TSDR record, the identifiers
that keep their names, and the translations that moved from a generic "dev mode" to the
developer mode. The stage paragraph in ROADMAP.md listed the mode as Dev Mode.

* Actions palette: put each search doc comment back on its function

search_text had grown a second doc line under matches's, so the sentence about the query sat
above a function that takes none. search_text now says what it reads and matches keeps its own.
2026-11-09 15:44:02 +01:00
Trevor BrownandClaude Opus 5.5 ff3e4e6010 M12: sticky growth checked with a measured font; the normalize note drops sticky size (#2164 review)
The growth test scans the system fonts, as the other text-measuring engine tests do (#333), and
asserts the note grows taller unconditionally instead of only when text happened to measure.
docs/boards-parity.md no longer lists a sticky's text size among what the normalize pass derives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 checked the findings and wrote
2026-11-09 09:38:56 -05:00
Trevor BrownandClaude Opus 5.5 36cd59dada M7: a grouped component set's background takes no connection either (#2161 review)
A set in a group has no top-level frame, so a drop on its background fell through to frame_at
and made a Navigate to the section around it. target_at now returns nothing for any point
inside the source's set that misses a sibling variant, as Figma does; red-first UI test with the
set in a group in a section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 checked the finding and wrote
2026-11-09 09:38:54 -05:00
Trevor BrownandClaude Sonnet 5.5 1ee3087bc9 M12: a sticky's text keeps its size and the note grows taller (#2157)
FigJam's sticky text is 18 (Small) and never changes as the note fills; the note keeps its width and grows taller (measured in the web app, 2026-11-09). A new sticky's text is STICKY_TEXT_SIZE (18) and the normalize pass no longer resets a sticky's text size by its length, so saved stickies keep the size they have. No size menu yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and briefed; Sonnet 5.5 measured in Figma and wrote at medium
2026-11-09 08:46:12 -05:00
Trevor BrownandClaude Sonnet 5.5 5c50025270 M7: a connection dropped on a sibling variant creates Change to (#2158)
A connection dragged from a variant (or a layer in it) onto a sibling variant of its set now creates Change to that variant (On click, Instant) and outlines the sibling while dragging, as measured in Figma. The set background and the variant itself add nothing; a frame outside the set still gets Navigate to.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and briefed; Sonnet 5.5 measured in Figma and wrote at medium
2026-11-09 08:37:11 -05:00
Ragulsundaram 50a76d0914 i18n: Tamil (ta) interface catalog (#2159)
Adds ta.toml with every UI string, command label and menu wording, marked draft.
Desktop draws Tamil with an installed face (#2018); the web picker leaves Tamil out
until craft-fonts has Noto Sans Tamil, like Georgian and Arabic, with a test.
docs/translating.md gains Tamil's entry, typography notes and a Tamil draft section.
2026-11-09 18:45:27 +05:30
Dylan M. Taylor 79c363466a fix(web): allow up to Cloudflare 25 MiB cap in package.sh (#2155) 2026-11-09 06:59:31 -05:00
ljkx 91a76c72c4 M1: the picker-Crop test drags the picture's corner outside the layer too (#2150) 2026-11-09 12:53:10 +01:00