The settings folder comes from craft-settings' rules: FIGCRAFT_CONFIG_DIR,
a `portable` file next to the executable (config/ beside it), then the
platform folder every earlier version used. The Windows portable zip ships
the marker, and a portable folder without preferences starts with a copy
of the platform folder's.
Direct3D 12 compiles with FXC and no device compiles wgpu's indirect-call
validation shaders, the two causes of "Parent device is lost" at start.
When the graphics still fail before the first frame, the app starts again
with the next of a fixed list of attempts (Windows: Vulkan, OpenGL; Linux
and FreeBSD: OpenGL; then lower requirements on the power-saving GPU), and
the last failure's message names what was tried.
Session::execute_as records the agent's presence: its name, the file, and the innermost layers its last edit changed or the selection it set, for 8 seconds after its last command. The app shows it as an avatar in the people row and an outline with a name tag on the canvas, in its own colour. Display only: no undo step, never saved, never synced to a live session.
While the interaction editor has an Open overlay action with Manual position open, the overlay frame shows dimmed and outlined where it opens, from the top-left of the layer that opens it. Dragging it sets the action's offset through proto.action.set in one gesture: the X/Y fields follow live and the drag is one undo step.
* M9: one name for comments and live sessions, shown in the Join dialog, kept in the browser, renamed live (#1380)
* M9: a reconnecting session's reset is its own helper (#1380)
* M9: a per-address budget for server admin requests, and join codes found by hash (#1075)
* M9: the server tests share one snapshot and address helper (#1075)
These scripts write no spaces between words, so a paragraph was one word
that only broke where it overflowed, mid-word (พัฒนาซอ|ฟต์แวร์).
breaks::word_breaks finds the word starts inside each run of them with
ICU4X's line segmenter (icu_segmenter 2.3, matching the icu_* crates in
the lock), and break_lines may break there when the next glyph starts a
new cluster. Where a run meets other text the UAX #14 subset decides as
before; a word wider than its box keeps #1400's emergency break.
Desktop uses the segmenter's dictionaries; the browser uses its LSTM
models (about 0.39 MB of wasm instead of 1.86 MB, which the 24 MiB web
gate can't take). ICU4X breaks between stray marks are filtered through
safe_emergency_break, so junk input never splits a cluster.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6DyK6i9Nvvsp3tp77UP
* M4: a letter and its combining marks shape with one font (#1478)
* M4: the stacked-mark test checks positions only in fonts whose anchors stack them (#1478)
* M4: the cluster face rule is tested with stand-in faces, so it runs without system fonts (#1478)
* M4: the #1478 tests use stand-in faces only, so they run everywhere
Every message (the first and each reply) gets `mentions`: {name, known,
you} for each @mention, by the rule the thread view highlights with
(figcraft_doc::mentions, now shared with mention_ranges). Names resolve
against the file's people and you; unknown names are kept with
known: false; a@b.com mentions nobody.
The board canvas's background grid is now a preference (`board.grid`): dots
(the default), lines, graph paper (a strong line every 2-12 cells over fainter
ones, like Japanese section paper) or none, with spacing (4-512), mark size and
contrast. Preferences gets a Board grid section; right-clicking an empty board
offers Board grid settings. Zoomed out the grid still thins out (by halves, or
down to graph paper's strong lines), and dots no longer shrink to a single
pixel, so the grid stays visible at low zoom.
The renderer draws lines as well as dots, with a configurable strong-mark
rhythm; a crossing of two lines is blended once, in the stronger colour. A
hand-edited preferences file falls back to the default grid instead of losing
the other preferences.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEkCVd8n1eC6xTHebmHMDR
A mask group's pixmaps cover only where its mask or content can paint within the view, rounded out to whole pixels, drawing the same pixels (a 40x40 mask on a 3000x2000 view: 96 MB -> 61.5 kB). Isolated layers share a 2 GiB per-thread budget; a layer past it is left out with a warning.
From the review of #1496: three background blurs stacked on each other across the band
boundaries draw the same in bands as in one piece (within anti-aliasing), so the bands'
overlap, the reach of the largest blur, is enough, as it is for the desktop's parallel bands;
pinned by a test. The docs and the `MAX_BANDS` comment no longer put the longest frame at "an
eighth of the render": a frame draws at least a band, a part of the render rather than the
whole, and the numbers measured for #1496 are cited instead.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M2: components can't contain their own instances (#1084)
Edits that would make a component hold an instance of itself, directly, through other components or through another variant of its set, are refused with the loop named. Files holding such a loop open with one instance per loop detached and a note; a rebuild never expands an instance inside a copy of itself, so a loop merged in a live session stops growing.
* M2: a variant may hold a sibling variant's instance; only true loops are refused (#1084)
Each variant counts as its own component: refusals and open-time repairs apply only to a component leading back to itself through instances (an instance-swap value included), so files with nested sibling variants open unchanged. sync_instance_depth is split into match_layers and copy_layers.
Once a zoom had paused, the browser drew its full render in one frame. On a heavy page that
frame took seconds, and no input was handled meanwhile: the wheel steps and drags that came
were seen only when it was over.
The renderer's `Retained::begin` hands a full render back as `Steps`, drawn `band_h` rows at a
time with the same `render_band` and `put_band` the desktop's parallel bands use (bands overlap
by what background blurs read and keep their own rows; a blur reaching past a band makes the
bands taller rather than one piece), and `finish` keeps the image as a full render. A render
that is reused or patched is done at once, as before.
The browser's `Inline` worker refines through `Renders::refine_for`, which draws at least a
band a frame, more while they fit in `STEP_MS` (24 ms), and asks for the next frame while bands
remain, so input is handled between them; a view has at most eight bands, so on a page whose
render takes seconds the longest frame is about an eighth of it. A render drawn for the very
request is done once drawn. A pan or an edit meanwhile at the same zoom keeps the render going
and is patched in once it is drawn; a pan too far to patch or an edit the patch can't take draws
it again in steps, the image just drawn showing till then (`Refined::Shown`); a zoom, another
page or file, another size or other render options drop the render for one of the new view,
and what its bands took stands as the measure the next zoom's preview and wait go by. A render
in steps counts as one render (glass keeps the shapes a later render asks for again). The
desktop, with its render thread, is unchanged.
Measured in Chrome on two synthetic pages (20 images and 60 shadowed rectangles, with and
without two background-blur panels) whose full render takes 3.6–4.0 s at a deep zoom: the
longest frame while that render runs went from 3.7–4.0 s to 0.9–1.4 s (blur) and 0.69–0.80 s
(no blur); the bands together take longer than one render (the refined image comes after
6.7–8.1 s and 5.3–5.5 s instead of 3.8–4.1 s), each band rendering its overlap again and
repeating some per-band work, shadows mostly. The zoom steps are as before.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>