Commit Graph
246 Commits
Author SHA1 Message Date
FredApps 39af86e9f4 Merge pull request #2929 from vangel76/perf/aux-footage-hint-474
perf(media): tell the media pool which EXR footage effects read (#474)
2026-11-06 00:12:06 +01:00
4a89e68f9f Content-Aware Fill: spill the range and stream the output (#2570 phases 2-4) (#3079)
* Content-Aware Fill: bit-pack holes, spill frames to disk, stream outputs (#2570 phases 2-4)

* Content-Aware Fill phases 2-4: bit-pack holes, spill frames, stream outputs (clippy clean)

* Address CodeRabbit review: spill safety, streaming correctness, perf, memory guard (#2570)

* Address the remaining CodeRabbit review findings on Content-Aware Fill (#2570)

A non-streaming fill returned empty frames, progress could jump backwards between
the sink and the fill, the memory guard ignored the membrane frames still resident
for the flow pass (and wasm's in-RAM copies), and the GPU fill stages ran outside
an error scope, so an OOM retired the shared context instead of falling back to
the CPU for that frame.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Content-Aware Fill: sample spilled frames without decoding them, check spill errors (#2570)

Tracing sampled spilled frames by decoding whole frames under the shared cache lock, so
parallel traces across neighbouring frames evicted each other and mostly paid a full-frame
read while every other thread waited. Sample only the 2x2 bilinear support with positioned
reads on an open handle instead, and report a failed spill read in the no-hole branch
rather than streaming black frames as a successful fill.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Content-Aware Fill: spill membrane/propagated frames, unquantized input, surface scratch errors (#2570)

Flow and propagation now write their intermediate frames to scratch spills beside
the output instead of holding the whole range as float RGBA, and the input spill
uses 32-bit floats whatever the project depth so the fill sees the same values as
the old in-memory path. Spill reads/writes and scratch creation report through a
shared error slot that run_plan surfaces instead of masking disk failures as a
cancellation. Sampling uses positioned reads; the guard models the packed masks
plus per-thread scratch.

* Content-Aware Fill: report a membrane-spill write failure instead of cancelling (#2570)

* Content-Aware Fill: include the flow fields in the memory guard (#2570)

* Content-Aware Fill: scale the memory guard with workers and check scratch space (#2570)

The guard's scratch term was a fixed 8 frames, which under-counted a wide
machine with Lighting Correction by several times. It now models the sequential
synthesis stage plus a few frames per worker (from available parallelism) and
takes Lighting Correction into account.

Native fills write three f32 copies of the range to scratch beside the output,
so a range that cannot fit on that volume is now refused up front with the
free space in the message, before any frame is rendered.

Tests cover the worker/lighting budget, the scratch formula, a shared error slot
between the input and secondary spills, an uncreatable spill folder, and the
engine surfacing a spill failure as an error instead of a cancellation.

* Content-Aware Fill: resolve a relative output folder for the scratch check (#2570)

A bare relative output name has an empty parent, so the walk-up found no
existing ancestor and skipped the free-space check. Resolve it against the
process directory first, and cover that in the test.

* Do not reformat the GPU fill tests in the spill branch (#2570)

The file was already not rustfmt-clean upstream, so the formatter only added
noise to a file this PR no longer needs to touch: phase 1's call-site changes
are already on the base branch.

* Content-Aware Fill: measure peak RSS and correct the per-worker scratch model (#2570)

The ignored measure_peak_rss_of_a_fill test fills a spilled 640x360 range and
reports VmHWM. On this 18-worker machine 90 frames peak at 340-470 MB across
runs (35 MB with RAYON_NUM_THREADS=1) and 600 frames at 582 MB, so the scratch
slope is ~7 frames a worker, not the 2 the first guard revision assumed.
Scaling the summary down showed a clean linear slope at 8 and 4 workers, and
Lighting Correction stayed below the flow stage's peak.

Budget 8 frames a worker (9 with Lighting Correction), just above the measured
top of the range, and adjust the guard test to the real numbers. At 600 frames
the measured peak is 582 MB against ~11.1 GB for the old five-copies model, a
19x reduction.

* Contributors: credit Madhav Agarwal in the About window

Adds the self-chosen real and display name for @gmrmad1. The generated
contributors.json picks it up once the PR is merged.

* Address CodeRabbit: size the guard from the rayon pool; migrate GPU tests (#2570)

fill_workers used available_parallelism, but the parallel fill stages run on
the rayon pool, which RAYON_NUM_THREADS can size larger. Use
rayon::current_num_threads so the scratch budget follows the threads that
actually run; wasm keeps rayon's single-thread fallback.

The GPU inpaint tests still used the pre-spill FillInput API. The earlier
'do not reformat' revert dropped their API migration along with the
formatting, leaving cargo test -p effectcraft-gpu uncompilable. Restore the
Frames::Memory / HoleMask / sink migration and verify the 15 inpaint tests.

* Fix gate: flatten the wasm prop lookup and keep the budget wrapper test-only (#2570)

* Address CodeRabbit review: spill error check, global-pool preflight, docs (#2570)

* Include RAM-backed spill in the preflight and guard streaming reads (#2570)

* Resolve relative spill paths, prefer stacked mounts, guard the Edge Blend sink (#2570)

* Make the fill spill anonymous and test the streaming claims (#2570)

The spill was a named file in the output folder that only Drop removed, so
an out-of-memory kill or a force-quit left a multi-gigabyte
effectcraft-fill-* file in the user's project folder, and a failed set_len
after keep() leaked it too. The spill is now an anonymous temporary file
(tempfile_in), which the system reclaims when its last handle closes; every
read and write is positioned on that one handle (pwrite/seek_write join the
existing pread/seek_read), and the folder is kept only so the propagated
frames spill beside the input.

Also:
- Edge Blend checks for a failed read before handing a frame to the sink,
  so a black fallback frame never streams.
- The propagation workers stop as soon as the spill records an error.
- HoleMask::get/set use get()/get_mut(), so a mask whose public words are
  shorter than len cannot panic.

New tests cover the PR's headline claims: a spilled range fills
bit-identically to the same frames in RAM (returned and streamed), the sink
sees frames strictly in order, a truncated spill fails with a recorded
error and streams nothing, a failure mid-stream stops before the next frame,
propagation stops after a failure, the spill has no name in its folder, and
HoleMask round-trips at word boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Content-Aware Fill: clean up a stopped fill and count two scratch copies (#2570)

- A fill that fails or is cancelled after frames started streaming deletes
  the PNGs it wrote, and the output folder when the fill made it and it is
  left empty (OutputFiles, dropped after the spill so Windows can remove
  the folder).
- After a successful fill, run_plan checks that every frame has a file, and
  apply_plan/add_fill_layer return an error on an empty range or file list
  (a job worker's reply) instead of indexing [0].
- scratch_need charges two f32 copies (32 B/px): flow_pairs drops the
  membrane spill before the propagated one is created, so the third copy
  never coexists.
- The spill-creation error carries a stable "spill: cannot make the scratch
  file" marker; the panel test asserted on the OS wording, which on Windows
  is "Cannot create a file when that file already exists".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Content-Aware Fill: a stopped fill leaves files it didn't create (#2570)

A fill into a given outputDir that already holds an earlier sequence
overwrites its frames as it goes (as before). The cleanup of a failed or
stopped fill deleted every path it wrote, including those earlier frames, so
a layer still using that sequence lost them. It now deletes only the files
the fill created (CodeRabbit on #3079).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:51:11 +01:00
611a282bea Plug-ins: external effect helpers (safe, out-of-process native effects) + plug-in API 2 (#889)
* Plug-ins: API 2 (PluginHost, padding, layer_span)

Split out of the OpenFX work so it can be reviewed on its own. Additive; the WebAssembly ABI
stays at 1.

- point3 / layer / text / hidden parameters, integer sliders, parameter groups.
- EffectPlugin::padding (transparent pixels around the buffer, at most 4096 per side).
- EffectPlugin::render_v2 with a PluginHost: the input at other times, other layers, parameters
  at other times, frame rate, per-instance key, the layer's source range.
- EffectEnv::layer_span from the renderer; MAX_PLUGINS 1024.
- plugin_error: a plug-in effect's last render error, for the UI.

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

* Plug-ins: external effect helpers (crates/helper-host)

Native plug-in formats run in separate helper programs, never in EffectCraft's process
(docs/adr/0001-external-effect-helpers.md). New safe-Rust crate effectcraft-helper-host (L3,
native only, unsafe forbidden): it finds helper programs, starts each as a child process and
registers its effects through plug-in API 2, so the UI and command surface need nothing new.

- Protocol v1 (docs/external-helpers.md): JSON lines over stdin / stdout (helper replies are
  prefixed so plug-in chatter is ignored); pixels go through a frame exchange file (/dev/shm on
  Linux), never through the pipe. Render-time callbacks for the input at other times, other layers
  and parameters at other times, with nested renders through the same helper.
- A helper that exits, hangs past its timeout or breaks the protocol is stopped. The render fails
  with a message, the frame is left as it was, and the helper restarts for the next render. An
  effect that stops its helper 3 times is turned off (helper_blocklist.txt).
- Opt-in: nothing starts helpers unless the user asks (Effect > Scan for Effect Helpers), or opts
  in to starting them at launch with EFFECTCRAFT_HELPERS=1, an environment variable, so writing
  to the settings folder alone can't run code. effect.helpers.scan / load are refused for
  confined agent sessions (confine.rs), like file.executeFile.
- Discovery: helpers/ next to the app (Contents/Helpers on macOS), helpers/ in the settings
  folder, EFFECTCRAFT_HELPER_PATH.
- Commands effect.helpers.list / scan / load; Effect menu entries (translated); the last render
  error of an effect shows as a warning sign after its name in Effect Controls.
- serve(): the helper side for Rust helpers. tests/it/main.rs runs the whole protocol (render,
  padding, callbacks, nesting, threads, crash, restart, block list, hang) against a fake helper,
  with nothing to install.

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

* Effect helpers: address review (start failures, frame file mode, nextest listing)

- A helper that can't start (not installed any more, restarting too often, no frame exchange
  file) is reported but no longer charged to the effect being rendered: it is Failure::Refused,
  not Failure::Broken, so it never counts toward turning that effect off. New check in
  tests/it: once the helper is out of restarts, renders of an effect fail without blocking it
  (fails without the fix: the effect was turned off after 3 such renders).
- The frame exchange file is created owner-only (0o600) on Unix: it holds the user's frames and
  /dev/shm is shared. Asserted in the frames unit test.
- tests/it (harness = false) speaks the libtest listing protocol cargo-nextest uses:
  `--list --format terse` prints `helper_protocol: test` (nothing with `--ignored`), and
  `helper_protocol --exact` runs the checks.

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

* Effect helpers: bound writes to a helper, drain stderr, keep callbacks in step

- Writes to a helper go through a writer thread with the request timeout: a
  helper that stops reading its stdin (hung with a large callback answer or
  render request pending) no longer blocks the render thread forever while
  holding the helper.
- stderr is drained as bytes (lossy, in 64 KiB pieces) to the end: output that
  isn't UTF-8 stopped the reader, closing the pipe under the helper (EPIPE /
  SIGPIPE on its next write); lines were unbounded.
- Callback images that can't be written are answered with `null` instead of
  failing the render while the helper waits (which left the protocol out of
  step); a frame that can't be written before the request is sent is not
  charged to the effect.
- Mid-render calls use the render's own process: no respawn or heartbeat ping
  while the helper is waiting for an answer.
- Waiting for a busy helper is bounded (load timeout) instead of forever;
  status() no longer blocks on a running render.
- Reap the child when start-up fails after spawning; cap the block list read.
- Scripts start helpers only with Allow Scripts to Write Files and Access
  Network on (they run native code), as for File.execute().
- helper-host declares the workspace's no-panic crate lints; the desktop
  main() keeps its doc comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Effect helpers: rustfmt the fake provider, build the test session in its initializer (clippy)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Plug-in Library: offer WebAssembly API 1 releases only; a helper already stopped mid-render isn't charged again

- WasmPlugin loads only modules at the WebAssembly ABI version, which stays 1 while
  PLUGIN_API_VERSION is 2: share it as effects::plugin::WASM_API_VERSION and have the
  library's compatibility check use it, so it never installs an API 2 release that
  can't load.
- with_running: a process that is already gone was stopped by what broke it (a nested
  render, charged there), so this render fails without charging its own effect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* frames: plug-in effects count as reading other frames (plug-in API 2)

With main's narrowed frame invalidation (#2795), an edit inside a precomp under an
effect that reads its layer at other times must reach the layer's whole span.
Plug-in API 2 gives every plug-in effect the input at other times, so any effect
outside ec. counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-05 11:11:57 +01:00
Valentin Klein bb78d55825 After Effects project import (.aep / .aepx); export follows (#2558)
Add After Effects project import with bounded parsing, explicit loss reports, and regression coverage.

Fetch the cleaned external test corpus at commit 97262276f625afdeeb61787e4cbb74b3f17af510 and verify each fixture against the pinned SHA-256 manifest.
2026-11-04 12:06:08 +01:00
Dylan M. Taylor 2f31c22a09 fix(prefs): when recovering from a bad value, try only the settings' own pages one by one (#3010) 2026-11-03 14:10:24 -05:00
vangel76 e3ab397a7e Merge remote-tracking branch 'origin/perf/exr-decode-cache-474' into m2929-merge 2026-11-03 19:20:26 +01:00
Brandon Thomas 859808e062 Merge PR #2979 2026-11-03 09:30:23 -05:00
Brandon Thomas f5e81cd1f9 Merge PR #2957 2026-11-03 09:08:08 -05:00
Brandon Thomas 5dc64bb227 Merge PR #2885 2026-11-03 09:04:55 -05:00
Brandon Thomas 3072f009bf Merge PR #2891 2026-11-03 09:04:54 -05:00
Brandon Thomas 0e3d54f982 Merge PR #2909 2026-11-03 09:04:45 -05:00
Brandon Thomas 2fb7003643 Merge PR #2924 2026-11-03 09:04:45 -05:00
Claude a5e0da657e Pre-compose: layers left behind drop links to moved layers, default names are numbered
Unselected layers parented to, or track-matted by, a layer that moved into the
new composition kept ids that no longer exist in the outer comp. The command's
default name was always "Pre-comp 1"; it now picks the lowest unused number.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-11-03 13:58:54 +00:00
Matej Kozlovský 6b1f91ffb8 Cryptomatte: read an ID's coverage from the kept probe (#473)
Session::crypto_coverage returns the coverage of one Cryptomatte ID over the layer, read from
the probe Session::crypto_probe_job keeps: at most max_side samples on the long side, each at
the centre of its cell, or None until the probe is built. It is what the Cryptomatte
eyedropper's hover highlight will draw.

Tests cover the coverage of an ID from the kept probe and the cost of a highlight with six
ranks.
2026-11-03 07:22:46 +01:00
Bar BorerandClaude Opus 5.5 8a37ff6b43 Tests: trim the midpoint snap tests to what #2855 changes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 05:07:59 +02:00
vangel76andClaude Opus 5.5 0d2153e259 test(media): review follow-ups for the aux footage set (#474)
- A watch-folder render gives the host session's set back after its own
  project replaced it on the shared footage source.
- Guard gpu fx_depth::IDS against reads_aux drifting apart.
- Count picture and channel decodes per thread instead of reading the
  shared channel cache, so parallel tests can't make the checks flaky.
- The engine test fails when no set was ever sent.
- Docs: Media Replacement items are learned at their first frame.

Refs #474

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 03:27:25 +01:00
vangel76andClaude Opus 5.5 5b31b96cde perf(media): tell the media pool which EXR footage effects read (#474)
The pool learned that an effect reads a footage item's channels only at the
first aux() call, so the first frame was decoded twice (picture, then in
full), and the hint was never cleared after the effect was removed.

The session now gives the footage source the whole set of files read by
enabled 3D Channel effects (FootageSource::set_aux_footage) with every
project change (Session::bump: edits, undo, redo, history jumps, rollbacks,
project open), sending it only when it changed. The pool keeps that set and,
as a safety net, what aux() learns; a new set drops what was learned.

Refs #474

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 03:21:40 +01:00
JonRC 583ba084b6 Fix #2917: material.set names the Material Options a layer doesn't have
A 3D model layer keeps its file's materials, so it has no Base Color,
Metallic, Roughness or Emissive. material.set refused them with "no
Material Options property matched (..., baseColor, metallic, roughness,
...)", naming the parameters it had just refused, and next to a
parameter the layer has it dropped them and reported success.

A parameter that none of the given layers has now fails the command
(nothing is set), naming it and the properties the first layer has. A
value of the wrong type is its own error. The parameter list says which
layer kinds take which.
2026-11-02 23:13:02 -03:00
Bar BorerandClaude Opus 5.5 fa0c260630 Puppet: refuse only a mesh that repeats one already there (#2865)
Cut the fix down: a click off every mesh makes nothing only when the art it resolves to
already has a mesh with that outline. The nearest-art fallback in `region` stays, so a
near miss beside separate art still meshes it. `mesh::outline` is as it was and the
`newMesh` option of puppet.addPin is back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 04:00:19 +02:00
JonRC 0b59d2b8c4 Follow-up to #2907: say that a uid wins over an index for animator
animator_uid matches a uid before an index, so an animator whose uid
equals an index is picked over the one at that position. The four
commands that take `animator` (layer.addTextAnimatorProperty,
layer.addTextSelector, text.addSelector, text.animatorFontAxes) now say
so; text.addSelector also said only `uid|index` before. The test gives a
second animator uid 1 and checks that `animator: 1` picks it.
2026-11-02 21:14:22 -03:00
JonRC 5643f39769 Fix #2907: say that text animator indexes count from 1
layer.addTextAnimatorProperty, layer.addTextSelector and
text.animatorFontAxes take `animator: uid|index`, counted from 1 as the
code and `#n` references do, but the parameters didn't say so and
`animator: 0` failed with only "no animator 0". The parameters now say
1-based, and the error says what the value can be.
2026-11-02 20:32:48 -03:00
Bar BorerandClaude Opus 5.5 f20dd38f94 Puppet: a click on deformed-away space creates nothing (#2865)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 20:39:17 +02:00
Bar BorerandClaude Opus 5.5 39119ff9ce Viewer: dragged layers snap to other layers' midpoints and center lines (#2855)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 20:36:57 +02:00
JonRC a2f6cd3ed5 3D Camera Tracker: a partial solve is not reported as solved (#2822)
camera.solveStatus said `solved: true` for any stored solve, but the solver
keeps the frames it cannot resect as unsolved and interpolates the camera
there. `solved` now needs every frame, the same check camera.exportBlender
makes, and `partial` marks a solve with gaps, next to `solvedFrames`.
2026-11-02 09:15:05 -03:00
Brandon Thomas a658ec736a Merge PR #1266 2026-11-01 21:50:53 -05:00
pravdomilandClaude Opus 5.5 aa149d7bbc Shortcuts: deterministic dispatch between panels, physical and logical ranked together
- shortcuts::pick chooses the binding for a key press: narrowest scope, then a
  physical-key binding, then the first. When two other panels (or two active
  contexts) claim the chord at the same rank, neither runs and the status bar
  says which panels own it.
- Physical and logical bindings compete by scope rank in one pass, so a
  narrower logical binding beats a physical one of an unrelated panel.
- An additional viewer (PanelKind::Viewer) ranks as the Composition panel.
- Two contexts on the same keys are reported as a conflict.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:35:33 +01:00
Brandon ThomasandClaude Opus 5.5 2a7888d2c0 Follow-up to #2716: addItem applies in before out; anchor takes exactly [x, y]
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 11:02:15 -04:00
Brandon ThomasandClaude Opus 5.5 917f312bc2 Follow-up to #2169: keep layer.deleteAllMarkers layer-only
An empty layers list cleared the composition's markers too (CodeRabbit);
the composition-marker menu uses comp.deleteAllMarkers instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 10:56:36 -04:00
Brandon Thomas e89683c5b5 Merge PR #2712 2026-10-31 10:54:52 -04:00
Brandon Thomas 659cfcd1d0 Merge PR #2716 2026-10-31 10:54:51 -04:00
Brandon Thomas 738f9a3055 Merge PR #1541 2026-10-31 10:54:51 -04:00
marshiyar 38ed20f569 feat(layer): layer.addItem takes in, out and anchor (#2026) 2026-10-30 20:30:34 -07:00
marshiyar 508a2241e9 Help: Expression Reference opens a page that exists (#2696) 2026-10-30 20:07:14 -07:00
maxaeexe b30c644c77 comp.deleteAllMarkers: add Delete All Markers for composition markers 2026-10-31 00:45:35 +03:00
bflatastic 334bf0f785 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/engine/Cargo.toml
2026-10-30 17:22:12 +07:00
BFlat 3d285116d8 Merge pull request #1539 from nanox333/feat/sam2-roto-tracker
Roto Brush: follow the object with SAM 2.1 (Tiny, Small, Base+, Large; optional models)
2026-10-30 17:02:45 +07:00
pravdomilandClaude Opus 5.5 189f31d6d1 Shortcuts: panel and context scopes, one chord per scope
A shortcut belongs to the application, a panel or a context (editing text, a paint or
camera tool active, a mask selected). The narrowest active scope runs a chord: an active
context, the focused panel, the panel sharing its shortcuts (Timeline and Composition),
the application. A context's shortcuts never run outside it.

- shortcuts.rs: scope table for engine commands and menu entries, scope_rank,
  scope_label; UiCommand can state its scope.
- Conflicts: the same chord in two scopes is an override (both keep working), reported
  with overrides: true; shortcuts.conflicts lists same-scope pairs only.
- Scoped now, keys unchanged: Remember / Apply Interpretation and Delete Without
  Confirmation (Project), Duplicate Render Item (Render Queue).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:57:09 +01:00
bflatastic 2a72f03872 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	apps/effectcraft-cli/tests/it/cli.rs
#	crates/engine/src/output_guard.rs
#	docs/agents.md
2026-10-30 16:38:01 +07:00
bflatastic 672c49ab4a Merge remote-tracking branch 'refs/remotes/pr/1829' into HEAD 2026-10-30 16:37:00 +07:00
BFlat 7174c81b2f Merge pull request #1830 from nanox333/fix/1743-duplicate-outputs
#1743, part 3: two Render Queue outputs never write the same file, and default names avoid the queue's other outputs
2026-10-30 16:36:32 +07:00
Patrik LermonandClaude Opus 5.5 46881e0d5f Swedish interface translation (sv)
Adds Swedish (Svenska) as an interface language in the menu, panel and
effect catalogs, written from the English source. The effect rows are
partial like Japanese and Georgian: an effect without a Swedish row draws
its English name, so a new effect does not block other PRs (#2244).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:35:36 +01:00
Kristian Myram 2112e553ec #1743: choose default names around protected overflow paths 2026-10-30 10:13:38 +01:00
Kristian Myram a4f5c516ed #1539: validate benchmark inputs and preserve shared refinement strokes 2026-10-30 10:00:33 +01:00
Kristian Myram b7d97c20e9 #1743: check final storage overflow destinations for queued outputs 2026-10-30 09:55:49 +01:00
bflatastic f558305795 Merge remote-tracking branch 'refs/remotes/pr/1830' into HEAD 2026-10-30 15:42:23 +07:00
Kristian Myram 41148e9b72 #1743: validate background and bridged exports in their owning session 2026-10-30 09:41:38 +01:00
bflatastic 18b6308225 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-30 15:00:44 +07:00
bflatastic 279b0ab4e3 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-30 15:00:43 +07:00
bflatastic eed23ffa48 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-30 15:00:42 +07:00
bflatastic 14011b4405 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-30 15:00:41 +07:00