Files
solvecraft/docs/render-workspace.md
T
selune 9e6e0b8df1 Render workspace: complete experimental ribbon, resources and effects integration (#5493) (#5494)
* wip(render): reconcile completed material and image pipeline source with 0.20 (#5493)

Source-only integration reference for staged review, not a merge-ready aggregate.
Donor: 0xlillith/solidcraft@aea20b0115.
Upstream: 858e5995d6.

Retain original CPU/material contracts and explicit GPU donor provenance in
docs/render-materials-lab.md (#2067, #2191, #2780, #3306). Preserve released
format migrations and current navigation/startup/shell behavior. New saved
records use pending descriptors. The physical-card descriptor follows the
maintainer's material-engineering-cards naming request, with a legacy-lab
format-29 regression. Replace raw new panel hosts with shared containers.

Repository checks, complete workspace/all-target Clippy, and the independent
physical/resource authoring checks pass for this source. The fresh full local
CI invocation has reached test compilation and is not yet complete. Do not
transfer donor native output or prior test totals to this integration.

Generated review screenshots, video, package ZIP and machine logs remain at
the immutable personal evidence pin. Uncommitted geometric displacement is
backed up separately, not silently included. No kernel/vendor change, direct
main write, release or independent contributor-branch rewrite.

Co-authored-by: Christian Svensson <blue@cmd.nu>

* test(cli): pin the Compact camera-sample admission diagnostic (#5493)

The bounded request still refuses 1024x1024x64 samples before host initialization and writes no output. Update only the stale expected diagnostic to the existing Compact budget wording; production limits and code are unchanged. Exact-tree CLI regression suite: 14 passed, 0 failed. The full repository gate has been invoked separately and is not yet complete.

* Normalize UI container violation paths across platforms

Report repository-relative paths with forward slashes so diagnostics and the existing nested-package regression assertions agree on Windows and Unix. Keep the container detection rules unchanged.

Validation: official ui-containers gate and all seven focused xtask tests passed; rustfmt and diff checks passed. Only xtask/dependencies were compiled; no application build or heavy tests.
(cherry picked from commit 44b58d8e10)

* fix(render): preserve camera contracts and correct acceptance regressions (#5493)

Preserve Design view.apply semantics with a separate strict Render camera command. Retain existing translations when English-only aliases collide; add material-axis entries and camera-specific pitch labels. Compare complete validated engineering cards and retain job handles before cancellation.

Focused and native acceptance is pinned to tree f8a423b21f. Full CI has been invoked separately and is not claimed green. Landing follows the render integration policy in #5493.

* fix(render): resolve showcase licence and upstream resource hygiene (#5493)

Record SychPL's explicit MIT OR Apache-2.0 grant, retaining source/model bytes and the Ubuntu lettering notice. Remove 80 absent attribution rows, personal fork records, dead delivery attributes and three fork/resource-only workflows. Existing xtask assets now performs bounded offline hash checks and rejects orphan render attribution; no parallel draft CI or package installation. Original authoring reproduction remains explicit. Scoped xtask tests, assets, Clippy, formatting and prepared SELENE validation pass; no application or renderer-wide result is inferred.

* fix(render): align saved bounds and progressive sample resolution (#5493)

Address review r4364211669/r4364211677/r4364211681/r4364211691/r4364211695. Persisted light/frame domains respect the existing 1e9 document bound; related LED/rectangle/direction cases use the same bound. Workstation primary resolve shares the 4096 admission cap and film counters use checked conversions. Exact candidate: 485 CPU render tests, 21 render document tests and strict scoped Clippy pass, including positive boundary round trips and 2048/4096 end-to-end checkpoints. No released format/migration edits, relaxed test limits or full-stack acceptance claim.

* wip(render): isolate optional resources and harden sample handling (#5493)

Review work in progress: opt-in encoded render library with reproducible runtime catalog exports; native-only robust dependency through the workspace; checked bloom slices; per-sample point-light diagnostics; independent area-light spatial/film keys. Resource-module binaries in both configurations, generation, Cargo production feature graphs and attribution checks pass. Full engine/render regression and combined acceptance are pending: do not merge this donor as a constituent or treat scoped resource proof as runtime acceptance.

* fix(gpu): preserve donor allocations through the scope-safety repair (#5722)

Port the native-validated #5723 scope-cleanup correction into the experimental donor, retaining its adaptive, volume, aging, photographic and bloom allocations. Same reverse-drain helper and regression cases; the donor combination still needs its own compile/test gate and is not covered retroactively by render-base results.

* claim: #1369

* Reject unknown pending concepts after format folding (#1369)

* test(render): close bounded sampling and bloom review regressions (#5493)

Validate the optional-resource/lighting/dependency donor at its exact tree. Required Vulkan GPU 127/0/3; CPU renderer 487/0; engine Render 72/0; document render 21/0; lean library 7/0; strict scoped Clippy, assets/layers/lists/containers and lean-engine WASM pass. Preserve original failed controller/typing attempts. This is the draft donor/disposition source, not a replacement for constituent render PRs or final main acceptance.

* wip(render): preserve stable aging target validation candidate

Exact staged source from prior review work on donor 3b892eab5e. This is a recovery/review checkpoint, NOT accepted delivery. An actual command-path regression currently fails because the selected executor refuses ordered surface aging. No assertion, capability or admission limit is weakened. Native/UI/full combination acceptance remains pending. Saved/runtime split adds one pending descriptor and retains original file scope; no main/render branch is changed.

* test(render): preserve numeric setup intent at the admitted coordinate bound

Follow up jyviko review on #5494 without weakening the corrected saved-coordinate contract. The positive clicked fixture uses 1e9 instead of inadmissible 2e9; explicit out-of-range cases still refuse, and the full saved setup round-trips through JSON and the native container. Exact-source Render workspace 95/0 and strict all-target UI Clippy pass. This does not incorporate the separately failing stable-aging candidate or claim full current-render acceptance.

* test(render): use the real GPU executor for saved aging

Move successful native cold-reopen Check/Start coverage from the CPU-backed protocol fixture into the production GPU executor tests. Verify capture-index changes preserve the stable target and that enabling aging changes both PNG and raw EXR output. Retain explicit, allocation-free refusal coverage for executors without aging support. Production capabilities and admission checks are unchanged.

* fix(render): persist stable identities for targeted aging (#5493)

Separate saved RenderBodyTarget identities from captured mesh ordinals. Reject legacy ambiguous targets, resolve Check/Start after visibility changes and preserve native reopening, copies and undo. Unsupported executors still refuse; real AMD Vulkan regression completes saved aging after reordered capture.

Source tree 6b84c8ad passes document 23, engine Render 75, GPU effects 5 and Render UI 95 with no failures; scoped strict Clippy, WASM and repository gates pass. Fresh CLI/native reopen and clean/aged GPU exports pass with identical physical totals and inspected actual images. Whole current-render integration is separate.

* fix(render): reconcile combined CPU/GPU contracts on current upstream

Unify captured resources/status and CPU-vs-GPU request schemas after the real two-parent integration; remove obsolete duplicate Vulkan selector and retain combined platform-filter regression. Deduplicate only identical or superseded test definitions, retaining the stronger card metadata and reserved-executor assertions. No assertions, admission limits or feature refusals are weakened.

All targets of render dependencies, GPU, engine, UI, CLI and native app pass cargo check with raytrace-cpu and bundled-render-library at tree c70d00d1. Native executable tests and full current-source acceptance remain pending. This is a private integration rehearsal for subsequent constituent PRs, not an aggregate official render/main merge.

* test(render): retain one complete host lifetime regression set

Deduplicate byte-identical DropProbe/task-lifetime tests and retain the adapted environment/texture ownership regressions with every assertion and complete memory estimate. Keep the registered-geometry admission regression once; only struct field order differed. Replace a one-element diagnostic loop with its equivalent block, preserving all wrap/width assertions.

Test-only integration repair. Formatting and diff checks pass; refreshed executable validation is required. No production behavior, limits, assertions or ignores changed.

* fix(doc): recognize the proven format-29 card descriptor alias

Normalize only the historical format-29 physical-material-cards spelling, and only when material-engineering-cards is registered. Admission and migration de-duplication use the same identity. Unknown concepts, wrong versions and incapable readers still refuse before mutation. Six controlled-history Rust regressions and actual CLI migration/no-clobber acceptance pass. No version, released migration or CI changes. Refs #5793, #1369, #5493.

* test(render): preserve grounding refusal before explicit instance moves

Update the two Render binding fixtures for upstream first-occurrence grounding. Verify grounded movement refuses without changing document/history, then explicitly unground through the public command before the intended move. Retain every target, resource, copy and persistence assertion. Refs #5493.

---------

Co-authored-by: Christian Svensson <blue@cmd.nu>
Co-authored-by: Victor Santos Oliveira <56417388+Vittuu@users.noreply.github.com>
Co-authored-by: cfaulkingham <colin.faulkingham@gmail.com>
2026-10-24 14:21:59 +00:00

304 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Integrated Render workspace (R3)
The native image panel offers CPU raster, optional CPU ray tracing and
[GPU path tracing](render-path.md) as explicit image methods. All three methods can be edited and saved offline. Check and Start are enabled
only when the selected method has an installed supporting host; an unavailable method never falls back.
R4a builds on this viewport contract with a separately advertised CPU product-image
executor and Check/Start/Cancel/Export controls. See [render jobs](render-jobs.md) for
the asynchronous protocol, image limits, captured revisions and PNG export. The legacy
`ui.render` snapshot remains a separate route.
Choose **Render** in the workspace switcher after finishing a modelling operation.
The current integrated GPU renderer shows a separate product scene. Return to Design
restores its camera, projection preference and existing viewport drawing policy.
The live product preview remains independent of the selected image method.
## Image methods and controls
**CPU raster** produces the existing preview PNG with approximate transparency.
**CPU ray tracing** requires a native worker and the `raytrace-cpu` build feature.
Its panel offers **Single image** with 1, 4 or 16 spatial samples per pixel, or
**CPU progressive** with 1–64 accumulated samples and a separate seed. Both use
Neutral / Warm and cool / Key and rim lighting, cast shadows and exposure from
−16 to +16 EV. Progressive sampling has a 1,048,576-pixel and 16,777,216 pixel × sample
limit; the UI proposes a smaller size only as an explicit action. It requires an
opaque background; the panel explains the incompatibility and lets the user clear
Transparent background. Additional collapsible sections expose body reflections,
captured HDR or constant environments, directional lights and point lights. Reflection
bindings require explicit confirmation after a document change; reusing a name cannot
redirect them to another body. Check and the current job display their separate HDR
capture metadata. See [CPU workspace controls](render-cpu-workspace.md) for units,
limits and the immutable capture contract. CPU glass, emission, surface effects,
anisotropy, area lights and spot cones remain API capabilities without panel editors.
**GPU path tracing** preserves asynchronous shader preparation and its timing display.
Its independent image device requires Vulkan; the live viewport may use another backend.
When no compatible Vulkan device is available, GPU settings remain editable and
saveable, while Check and Start explain why GPU execution is unavailable.
The panel exposes progressive sample counts from 1 to 4096 and an Advanced section
for maximum path depth (1–16), random seed and exposure (−32 to +32 EV). One setup
exposure field controls the selected image method. Switching methods retains their
local numeric drafts while submitting and saving only the active method. Reloading
or choosing another setup replaces those drafts with the saved numeric intent.
The live product preview keeps its fixed studio response and does not apply image
exposure, environments, lens or material overrides.
The GPU Advanced section also exposes Reinhard / ACES fitted tone mapping, optional
final edge-aware denoising, and a thin-lens depth-of-field control. Positive aperture
requires a perspective product camera. Denoising preserves raw accumulation but can
soften detail; glass and sharp specular first hits bypass its final spatial filter.
The Environment section selects no map, an original artistic sky gradient, or a local
Radiance `.hdr` panorama. HDR input is bounded to 16 MiB, 2048 × 1024, 2:1, and linear
sRGB/D65 primaries; unspecified primaries require the explicit interpretation checkbox.
EXR is not supported. Rotation and intensity affect illumination, while the saved
background remains the camera backplate. Selecting a file runs the bounded public
`render.hdr.inspect` command; a typed path has an explicit **Check HDR file** action.
The picker belongs to the originating document revision, setup, method and input
selection. A cancelled or stale answer never replaces a newer selection.
The panel distinguishes a pending file, a checked file and **HDR saved inside this
design**. It shows dimensions, declared colour primaries and intensity; the source
digest is available in a collapsed details section. Check, Start and Save use the
checked file's expected SHA-256, rejecting changed bytes until an explicit recheck.
An already captured image retains its immutable source independently of later edits.
Custom studio lighting exposes constant linear-RGB environment radiance, a finite-radius sun,
and up to four one-sided rectangular emitters. World-space centers and orthogonal
half-edge vectors specify their geometry in millimetres; radiance is linear RGB.
An environment map replaces the constant environment term. The path integrator uses
the published emitter/BSDF MIS contract.
### GPU image materials
The GPU image materials section assigns runtime optics to whole visible scene bodies.
Refresh the authoritative body list, explicitly choose a body, and add its assignment.
The captured ordinal and exact name must match; a document identity or revision change
requires explicit revalidation. A removed, renamed or reordered body cannot silently
receive another body's settings. The editor uses weak document identity references, so
stale assignments do not retain historical documents. The normal Appearance and material
library dialogs keep their existing behavior.
Glass, clear coat and planar maps have separate collapsible controls. Six original glass
recipes come directly from the starter pack: linear transmittance over the recipe's
reference distance becomes absorption per millimetre via `-ln(T) / distance`. Selecting
one never changes saved opacity or assigns a scalar appearance. The swatch shows the
recipe's transmittance, not a rendered preview. Manual IOR, RGB absorption, thin-sheet
thickness and straight-shadow transmission are available. Closed solids derive optical
distance from geometry; full topology, orientation, overlap and optical-boundary checks
run during GPU preparation. Successful Check does not certify those geometric properties.
Clear coat exposes weight, roughness and IOR over the existing opaque base. Runtime maps
accept bounded local PNG/JPEG base-color sRGB and OpenGL +Y normal images, normal strength,
and orthogonal world-space origin/U/V vectors in millimetres. Each vector spans one full
repeat. The backend's 1024×1024 per-map, 16 MiB encoded-total and 128-repeat bounds remain.
Glass cannot share one body with coat or maps. Limits are eight glass bodies, 64 coat
bodies and 16 mapped bodies, within a maximum of 64 editor assignments.
All these controls are temporary per-document-tab state, explicitly labelled in the UI.
They are not saved in the design, render setup or portable material library. Disable the
overrides before choosing a CPU method; active GPU assignments cause Check/Start to
refuse a CPU request. Both buttons submit the same freshly validated runtime parameters,
and file contents are captured by the engine at that boundary. File-picker completion
checks the original document, revision and body identity before accepting the path.
Check and Start build the same request from the current product camera, size and
selected method, including when Render Result is open. Every click revalidates host
availability and scene readiness. The engine checks resource admission at Start;
an earlier successful Check does not reserve a queue slot or memory.
## Product scene
`engine::product_scene::extract` consumes authoritative evaluated geometry, reusing
the document's world/occurrence placement and mesh Arcs. Body, component, material,
face and imported appearances retain their existing precedence and opacity. Source
geometry is never transformed a second time or altered to serve a renderer.
The shared L1 `ProductScene`/`ProductMesh` contract contains world-space meshes,
resolved sRGB colours, opacity and face appearance overrides. Face indices are the
existing mesh-to-B-rep mapping, resolved through document appearance references;
they are not new persistent names or triangle-derived face identities.
There are no grid/axis/edge lines, sketches, construction objects, selection or hover
colours, section cuts, analysis shading, active-component fading, canvases or decals
in this initial product policy. Browser visibility still controls which bodies appear.
The existing Design viewport and CPU snapshot routes keep their current policies.
Extraction refuses a stale live-drag model. The explicit model-reading `render.scene {}`
command follows the normal engine evaluation boundary, then returns bounded metadata:
body names, triangle counts, resolved colours/opacity, face-override counts and bounds.
It does not return mesh payloads, change the document or add an undo step. Product
extraction admits at most 16,384 visible bodies.
## Image result canvas
The image panel switches between **Live Preview** (the product camera) and
**Render Result** (the current CPU checkpoint or last completed PNG). Clicking the
small image preview also opens the result on the main canvas. Check, Start, Cancel and Export
remain available in the same panel. An empty result explains how to start a job;
it never substitutes the live preview for an exported image.
**Fit Image** frames the complete image and follows window resizing. **100%**
maps one image pixel to one physical display pixel, including on high-DPI screens.
Pan, wheel, trackpad and Space + drag use the shared Navigation preferences with
orbit disabled. Ctrl + arrow keys pan the image; Fit/Home frame it. Image navigation
does not move the product or Design camera and does not change the saved setup.
The canvas shows the image dimensions, executor, full job identity and captured
model revision. A visible warning identifies an earlier captured revision when the
document has changed. A CPU progressive checkpoint is explicitly provisional and
shows its samples per pixel and sequence. Its texture is cached by job identity
and sequence, separately from the last completed image. **Export final PNG** keeps
using that completed image even while a checkpoint is shown. Cancelling or failing
the active job clears its preview and returns to the retained final image.
Transparency is shown over a checker
background; display scaling and navigation never modify the PNG bytes.
Canvas selection, framing and pan/zoom are local to each open document tab. Switching
tabs never displays another document's texture. A new image starts fitted; later
checkpoints and transitions to final/cancelled state preserve pan/zoom. Final
publication is checked directly after the preview read so a stale status reply
cannot briefly select an older frame and reset the next frame's zoom. The canvas
itself adds no document fields; CPU sampling intent is saved with the job below.
## Settings and product camera
The right panel stages a named setup's camera, background, output and active image
method. **Save Setup** records the complete numerical `RenderSetup.job` and the current
product `Camera` through `render.settings.set`, with one undo step. A new checked HDR
uses `render.settings.capture_hdr` to save both source bytes and setup in that same
atomic step. Editing the name
is Save As; choosing an existing name from the picker loads that setup. **Reload Saved
Settings** replaces the numeric draft with the saved values. Drafts remain separate
for each open document, and loading a setup preserves completed images and result framing.
| Active method | Saved numeric intent |
| --- | --- |
| CPU raster | Transparency, with zero exposure |
| CPU ray tracing | Single-image AA or progressive SPP/seed, preset or custom directional lights, point/spot lights, area lights and their samples/seed, shadows, constant RGB environment or embedded HDR with rotation/intensity/samples, setup exposure |
| GPU path tracing | Transparency, samples/depth/seed, tone map, denoise, lens, RGB studio lighting/sun/area lights, procedural sky or embedded HDR with rotation/intensity/explicit colour assumption, setup exposure |
The CPU panel preserves existing area-light and spot-cone fields even though it does
not yet edit every field. Opening a GPU setup retains non-power-of-two sample counts,
RGB environment values, exact sky gradients and radians. Explicit empty light lists,
black environments and absent settings remain distinct. The only exposure authority
is `RenderSetup.exposure_ev`: CPU requests lower it to their raytrace options with zero
outer exposure; GPU jobs use the same value in their job options. Choosing raster
explicitly selects its zero-exposure response.
Saving uses pure numeric validation and does not require an installed renderer or a
current evaluated scene. New HDR capture reads and validates the bounded source through
the engine; failure leaves the document, resource table and local file selection intact.
After success, the draft changes to the embedded resource and contains no source path.
Saving that setup again, Save As, Reload and design reopen use the included bytes, even
when the original file has been removed. CPU/GPU setups may share the same immutable
payload. The engine limits each source to 16 MiB and the design to 64 resources/64 MiB.
Check and Start use the same complete typed setup and then perform normal host, scene
and capture admission. Temporary bindings can still use an embedded HDR through the
runtime resource selector. GPU maps and all body bindings, including disabled
assignments, cannot yet be saved as a complete job.
The panel explains the limitation and refuses Save before changing the document.
Those inputs can still execute through the existing transient request route. Older
setups with nondefault legacy environment rotation/intensity are also retained and
refused for full-job saving until explicitly converted; their values are never erased.
**Restore Saved Camera** runs `render.settings.apply {name}`, preserving target,
distance, yaw, pitch, roll, FOV and up axis as view state. It neither edits the document
nor settles a stale model. The UI honours its up axis in Render; the Design camera
is restored when returning. The camera moves exactly as in Design: the navigation preset,
Orbit around, zoom to the cursor, the SpaceMouse, the middle double-click, F6 and the axis
view or navigation cube all work (nothing is picked or selected here), and
**Fit Product** frames visible product bodies without including sketches or selection.
Preview drafts do not make the document dirty until saved. Unknown backend preferences
and unsupported modes remain saved intent: the strict resolver reports the unsupported
viewport request. **Use Integrated Preview** is an explicit draft change, never an
automatic fallback. The method selector describes the desired image execution independently of the
installed host. It does not claim support for a saved final-mode or external-engine
preference. Saved image settings do not change the fixed live product preview.
## Host capabilities and resources
`render.backends` always retains the built-in `cpu-raster` preview/PNG image executor.
An installed CPU image host adds `cpu-product`; a native host with `raytrace-cpu`
also advertises `cpu-raytrace`, with its bounded PBR/HDRI/refraction profile. Discovery
does not select that method automatically or enable native workers in the browser.
Only an installed UI GPU host adds `gpu-viewport`, advertising **Preview / Viewport**
with no image formats or HDRI/refraction/progressive features. The installed
[opaque PBR consumer](render-opaque-pbr.md) adds the `pbr` feature. The host reports
effective limits from its created device and depth attachment: at most 4096 pixels
per dimension and 4,194,304 pixels, within the 256 MiB pixel scratch admission policy.
The estimate includes the selected MSAA colour/depth cost; it excludes scene geometry,
driver overhead and cached source meshes. It is not a measurement of total GPU memory.
The preview never refuses a frame because of the screen size. When the viewport's physical
size is past those limits (a maximised 4K or 5K window is 8–15 million pixels), the preview
draws at the largest size of the same aspect the executor admits (`RenderLimits::fit`, both
axes scaled by one factor, scratch included) and filters it up into the viewport. A viewport
within the limits draws at full size.
PNG images keep the saved-setup limits above. A setup past them is refused with the limits and
the largest size at its aspect (for example `4096 × 4096` → `2048 × 2048`), and the image panel
offers to use that size.
Pure capability metadata lives in the session/host, outside persistence and history,
surviving document replacement, scratch sessions and document-tab switches. No wgpu
types enter the engine or document crates. A host without an installed GPU/depth buffer
reports that product viewport preview is unavailable, rather than silently using the
opaque CPU snapshot path to approximate transparent appearances.
GPU product batches are separate from Design batches while sharing the installed
device and pipelines. Model/visibility/appearance changes update the product scene;
camera movement updates uniforms without rebuilding vertices. Selection and section
state do not change the product buffers. Vertex uploads are bounded to 128 MiB and
checked before allocation; malformed/non-finite triangles and invalid opacity fail.
Reinstalling the host invalidates product uploads. This is not a general device-loss,
render-job or cancellation protocol; those ownership mechanisms belong to R4.
Transparency uses the existing raster far/near alpha-blending approximation, without
refraction or HDR illumination. Opaque PBR uses a separate surface batch in the
same installed renderer. R3 itself added no export job; R4a supplies CPU product
PNG jobs. There is no result gallery or Bevy dependency. Saved setups were added
in format 21, alongside opt-in optical parameters on existing looks.
`ui.render` remains the existing Design snapshot API, using its installed renderer;
`ui.screenshot` captures
the actual integrated Render workspace. Product-image export uses `render.start`
and `render.export`, rather than the Design snapshot API.
## Reproduce
Run the original procedural `examples/render-studio.json` through the engine/CLI and
open its saved design in the app. Select Render, adjust its background or camera and
save a setup. The fixture uses original boxes/cylinders and simple colour/opacity
assignments; no commercial CAD files, artwork or materials are used. Actual Windows
Vulkan/MSAA evidence is attached to [#673](https://github.com/bherbruck/solidcraft/issues/673).
## Explicit Render camera and the Design view contract
`render.camera.set {camera}` applies a complete camera snapshot as transient view
state. It uses the saved-render camera's strict decoder and finite mm/radian
limits, preserves its explicit roll and up axis, and does not evaluate geometry,
change a saved shot, modify the design or add an undo step. Omitted roll/up use
zero/Z defaults; all other camera fields are required. Unknown fields, invalid
axes, nonfinite values and out-of-bounds numbers refuse atomically.
The Render inspector uses this command for numerical edits and before Frame
Subject. Design's `view.apply` retains upstream's independent policy: it accepts
finite roll (clamped to +/-pi) and refuses an explicit up axis. Render does not
reintroduce the former fork-specific extension to that Design command. Saving
or restoring a shot still uses the existing render-settings commands.
The camera pitch label is explicitly **Camera pitch**, so the legacy English
label adapter does not replace mechanical screw pitch translations. Material
axis conventions have stable catalog IDs; the numerical/wood conventions and
engineering data remain unchanged.
The legacy English-label adapter gives explicit catalog IDs precedence and, for
an ambiguous source label, retains a translation already present in the chosen
locale before falling back to English. Adding an untranslated Render alias no
longer hides existing Library, Appearance or Checkpoint translations. Contextual
Render labels still use their own stable IDs rather than borrowing a different
feature's meaning.