Render R2: persist named render setups without re-evaluating geometry (#667)

render.settings.set saves validated named render setups (camera, output size, exposure, environment) as one undo step, and render.settings.get reads them back without applying a camera. When validated render settings are the only change, the engine keeps the evaluated model instead of rebuilding it. Setups are saved under design format 21; format-20 designs read as having none. Fixes #658; refs #620.

Contributed by @0xlillith.

Co-authored-by: lillith <[email protected]>
This commit is contained in:
selune authored and GitHub committed 2026-10-14 17:11:39 -04:00
1 parent 771a11feab
commit 289b521a65
22 files changed
+641 -16

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@ self-contained input/output format. `io::write_design` keeps its JSON contract;
`io::write_design_container` is the fallible container writer.
Packages have `container.json` with `{"format":"solidcraft-container/1"}` and
`document.json` with the versioned parametric document (currently `solidcraft/20`).
`document.json` with the versioned parametric document (currently `solidcraft/21`).
The independent versions let document migrations evolve without changing blob encodings.
Existing serialized document fields are retained automatically, without a second copy
of the document schema or a deep clone of embedded payloads.
+6 -3
View File
@@ -1,6 +1,6 @@
# Features
SolidCraft's commands by area, generated by `cargo xtask features` from the command registry (`solidcraft-cli commands`). **350 commands.** Planned (registered, not built yet): 6. Every command runs the same way from the toolbar, a script, `solidcraft-cli exec <id> '<json>'`, the control channel and MCP; parameters are in the [command reference](book/src/reference/commands.md) (`cargo xtask book`). Status and plans: [ROADMAP](../ROADMAP.md).
SolidCraft's commands by area, generated by `cargo xtask features` from the command registry (`solidcraft-cli commands`). **353 commands.** Planned (registered, not built yet): 6. Every command runs the same way from the toolbar, a script, `solidcraft-cli exec <id> '<json>'`, the control channel and MCP; parameters are in the [command reference](book/src/reference/commands.md) (`cargo xtask book`). Status and plans: [ROADMAP](../ROADMAP.md).
## Sketch (99)
@@ -192,11 +192,12 @@ SolidCraft's commands by area, generated by `cargo xtask features` from the comm
| Plane Along Path | `construct.plane.along_path` | SOLID › CONSTRUCT |
| Perpendicular Plane | `construct.plane.perpendicular` | SOLID › CONSTRUCT |
## Sheet metal (11)
## Sheet metal (12)
| Command | Id | Toolbar |
|---|---|---|
| Flange | `sheet.flange` | SHEET METAL › CREATE |
| Perforate | `sheet.perforate` | SHEET METAL › CREATE |
| Hem | `sheet.hem` | SHEET METAL › CREATE |
| Fold | `sheet.fold` | SHEET METAL › CREATE |
| Unfold | `sheet.unfold` | SHEET METAL › MODIFY |
@@ -513,11 +514,13 @@ SolidCraft's commands by area, generated by `cargo xtask features` from the comm
| Insert Part | `parts.insert` | – |
| Change Part Size | `parts.resize` | – |
## `render.*` (1)
## `render.*` (3)
| Command | Id | Toolbar |
|---|---|---|
| Render Backends | `render.backends` | – |
| Render Settings | `render.settings.get` | – |
| Save Render Settings | `render.settings.set` | – |
## `select.*` (2)
+68
View File
@@ -0,0 +1,68 @@
# Persistent render settings (R2)
Named setups save common render intent in the document. They do not start a render,
apply the navigation camera or make a currently unavailable backend available.
The Render workspace, scene extraction, assets, PBR materials and jobs are later slices
of [#620](https://github.com/bherbruck/solidcraft/issues/620).
## Commands
```json
{"command":"render.settings.set","params":{"name":"Studio","set":{"width":1600,"height":900,"exposure_ev":1.5}}}
{"command":"render.settings.get","params":{"name":"Studio"}}
{"command":"render.settings.get","params":{}}
```
`set` creates a named setup from defaults or replaces supplied top-level fields in an
existing setup. A supplied `camera` replaces the whole camera; it is not a recursive
patch. Omitted fields retain their values. Unknown fields (including camera fields),
invalid types and invalid values fail before document mutation. A new empty `set`
saves the defaults; setting an existing setup to identical values is a no-op,
preserving redo history and revision.
Each effective edit is one undo step and marks the document dirty. There is no delete
or rename command in this slice.
Named `get` returns `{name, setup}` or an error for a missing name. Without a name,
it returns `{setups, defaults}`. Reads do not evaluate the model or change history.
| Field | Default | Saved contract |
|---|---|---|
| `backend` | `builtin` | Valid R1 backend ID, at most 64 ASCII bytes; unavailable IDs survive reopen |
| `mode` | `preview` | R1 `preview` / `final` mode; availability checked by a future render request |
| `camera` | Existing `Camera::default()` | Snapshot of target, yaw, pitch, roll, distance, fov and up; mm/radians, existing Z-up default |
| `width`, `height` | 1024, 768 | Positive, each at most 4096; product at most 4,194,304 pixels |
| `format` | `png` | R1 output format (`png` / `exr`); saving EXR does not add an encoder |
| `exposure_ev` | 0 | Finite, -32 through 32 |
| `environment_rotation` | 0 | Finite radians, magnitude at most 1,000,000 |
| `environment_intensity` | 1 | Finite, 0 through 100 |
| `background` | [236, 240, 245] | Three sRGB byte values, independent of future illumination |
Camera target coordinates and positive distance are bounded to magnitude 1e9 mm;
angles to 1e6 radians. FOV is finite, `0 <= fov < pi`; zero means orthographic in
the existing camera model. Both existing camera up axes are retained. Setup names
are trimmed, nonempty, at most 128 UTF-8 bytes, without control characters. A document
has at most 32 setups. Validation also runs during document deserialization.
## Persistence and evaluation
Document format 21 adds `render: {setups: {name: setup}}`. Format-20 and older designs migrate with
an empty map; empty render state is omitted when saved. Existing geometry, appearances,
opacity and physical materials are untouched. Plain JSON, design containers and crash
journal replay use the same document/command representation. Older builds (0.11.0 reads up to 20) reject format
21 instead of silently losing setups. This slice adds only render intent. No runtime capability, job, texture or device is saved.
The engine avoids geometry evaluation only after proving that the document differs
solely in validated render settings, with unchanged active sketch and pending moves.
The proof compares the complete document after normalizing the render field, so mixed
geometry/appearance/placement edits take the usual conservative refresh path. It uses
a document clone/comparison, not a constant-time or whole-application speedup claim.
Unchanged render pointers short-circuit the check for normal modelling commands.
Render-only edits, undo/redo and checkpoint restore preserve model state, its stale
marker, cached tessellation and the prepared world state. A stale live-drag result never
becomes authoritative through a settings edit; the next model-reading command still
settles it normally. Revision advances to let future consumers invalidate shading work.
Actual render accumulation and resource invalidation are not implemented in R2.
No new third-party dependency or asset is introduced. `doc` depends on the existing
pure `render` crate for its shared camera and R1 identifiers, within the L2 → L1 rule.