Files
solvecraft/docs/render-workspace.md
0xlillith 1b55174743 Render: isolate lens saves and retain bounded previews
Save only lens parameters on existing CPU/GPU jobs while keeping unrelated
draft settings dirty. Retain pinned checkpoints through preview and status,
and release host-only snapshots outside the status lock.

Use the admitted PNG bound for registered-executor checkpoint slots. Preserve
executor work credits, final publication and regrade ownership. Add regression
coverage and align help, translations and capability documentation.
2026-11-05 04:22:03 +01:00

46 KiB
Raw Permalink Blame History

Integrated Render workspace (R3)

The native image panel offers CPU raster for schematic output, optional CPU ray tracing and GPU path tracing 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 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. New native setups select CPU ray tracing with progressive sampling when the installed host supports it. Existing saved final settings keep their interpretation. Preferences > Graphics > Use previous Render image defaults restores the previous manual workflow.

A first entry with an active saved shot restores its authored camera when that camera is more than the untouched default. An uncomposed setup still fits the current product. Leaving Render remembers its transient camera separately from Design, so returning preserves framing and a saved lens stays paired with its perspective projection. Clicking a shot in the tree or Shots strip activates its numerical settings and complete saved camera, including an active shot when its camera differs. Unsaved edits retain Save/Discard/Keep. The standalone editor-selection command only focuses its editor; numerical reloads, saves and Undo do not navigate. The compatibility preference keeps the former camera-neutral thumbnail and entry-refit behaviour.

Live image feedback

Render automatically computes a separate live image after visual edits settle for 200 ms. Appearance, lighting, camera, visibility and image settings invalidate the capture; selecting an editor alone does not. The selected ray-traced method is retained. The stage bar identifies the live resolution and accepted/current sample count and offers Pause/Resume (view.render_live {paused: true|false}). Live resolution follows the active output frame inside the free product canvas, with a longest edge of 512 pixels. Common output ratios use exact integer multiples; otherwise the live image uses the nearest bounded pixel dimensions and picking uses that captured aspect. Final output size and saved sampling settings are unchanged. Invalid authored dimensions/sampling are refused before constructing the small live copy. An older image is marked as updating and cannot be used to pick geometry against a different projection.

Automatic images belong to an isolated scratch session. They do not enter retained results or replace the completed image selected for Copy, Export or Regrade. An explicit Render action displays its progressing image. If live capture or rendering is still releasing resources, the captured final request waits for cleanup; a changed source cancels that pending request instead of silently rendering different settings.

CPU progressive and GPU jobs publish each complete nonfinal pass. Adaptive GPU feedback distinguishes pilot passes from production iterations; each production pixel has its own budget, and pilots are excluded from the final image. Fast passes can coalesce between screen repaints. Unsupported combinations are not silently converted to fixed sampling. Unsupported CPU optical combinations also retain their settings and show their reason. These remain open parts of complete CPU/GPU parity.

Retained comparisons and all-shot rendering

The result viewer retains up to eight completed images per document tab, outside the design and undo history. render.compare {left, right} accepts "live" or a zero-based retained-result index (oldest first); the sides must differ. It resolves indices to job identities so later index shifts cannot retarget an open comparison. render.compare {off:true} leaves comparison. The shared segments toggle the two sources, Swap exchanges them, and the shared divider stays within 5–95%. Both sides share image pan/zoom; the live product uses the captured camera and current design. Dragging the divider cannot navigate either camera. Copy, export and regrade use the compared result on the right (or the left when the right is Live). That selection remains stable while new results arrive; evicting a source ends its comparison.

The Output footer's All shots (n) runs render.batch. The command snapshots up to 32 saved shot cameras and names and uses one common image setup. The UI supplies the current draft as request (the existing render.start parameters); a headless render.batch {} uses the first saved setup in name order. Each queued shot keeps its own captured camera while all other options remain the same. Each admission runs through render.start, one job at a time. No shots, an active render/queue or stale geometry refuses without editing the design or history.

render.status {} advances an explicitly started queue and returns {queue:{running,waiting,job,shot,error}}; a status call with a job also includes that queue metadata. The UI ticks advance queues in active and background tabs. render.cancel {} cancels the active batch job and drops all waiting shots; an explicit job ID retains the single-job cancellation API. Opening a stage, editor or queue readout never starts a batch. The Shots strip reports running and waiting counts, and completed shots enter the same retained-result list.

Stage bar and floating docks

Render has no ribbon. A shared 88 pt two-row stage bar sits 8 pt to the right of the 104 × 88 pt workspace card, with matching top and bottom edges. The icon sits above the Render label and Workspace caption. The header is 36 pt; the remaining 52 pt contains the tools, centred vertically below a 1 pt divider. Numbered Look, Light, Frame and Output chips run view.render_stage {stage: look|light|frame|output}. The selection belongs to the open document tab's view state; it is not saved in the design. Opening a stage never applies or saves settings or submits a final image job. It focuses the existing Inspector page, while every Inspector page and registered Render command remains reachable. The headless command validates and echoes the request without changing the document.

Render, Cancel and the shared command search (S) occupy the top row. The Pick control's icon-text Body/Face/Component segments, Paint/Pick Up actions and direct-light preview information chip occupy Look's second row with 8 pt side padding. Changing the light coordinate frame remains disabled with its reason in this checkout. Frame uses the existing explicit camera command for projection and the registered Save Shot action opens the shared naming confirmation; Output shows the current size/format and directs edits to the Output Inspector. No completion ticks are inferred.

The Browser and Inspector float in both shell layouts and share a top edge, 8 pt below the bar. Their default outer widths are 266 pt and 305 pt, with shared resize bounds. The Browser keeps the upper left card (up to ten compact scene rows); its stage panel fills the remaining height below it, ending 8 pt above the 48 pt Shots strip. Both cards share width and side preferences. Narrow windows shorten the Browser to reserve library space, then omit cards that cannot fit safely.

Look hosts Appearances: search with the actual catalog count, In Design / Library / Recent / favorites scopes, horizontally scrolling category chips and a three-column sphere grid or list. Resources used in the design or matching a selected look's finish family or category appear first. Clicking a look applies through appearance.assign to selected bodies, faces or components; with no target it only inspects. Favorites and recent history live in user preferences. Explicit catalog navigation opens the corresponding stage library.

Look also offers Surfaces and references. Surfaces/References segments and search lead to authored surface rows with availability badges. Selecting a surface loads its bounded source-map preview; Target, Plane and Repeat precede Use uniform, Use GPU maps and Save maps. GPU actions remain faded with a reason on other methods. Physical profiles retain their properties and sources; Prepare creation plan opens a read-only review with acknowledgement and Copy plan. It creates no material.

Light hosts Studios and environments: a Scope dropdown, search and three-column tiles for Studios, Rigs, Environments and read-only Specifications. Mine remains visible with the reason that personal studio saving is unavailable. Clicking selects; Apply prepares a review without changing the method or saved settings.

The shared ui_kit::ReviewAndApply dialog presents a resource card, Replaces/Kept, variant controls and explicit acknowledgement before applying. Studio, rig fit, environment, ground/stage, physical plan, fixed quality budget and uniform/spatial maps use this composition. Canonical Draft, Balanced and High quality chips instead apply their listed fixed GPU budget as one reversible numerical edit. Sampling shows size, samples, depth, seed and noise reduction; the chip hover lists all three budgets. Other image settings and the saved/live cameras are kept. Library specifications retain the acknowledged review. A captured review expires when the document, revision, shot, method or settings change. Rig fitting offers centre, extent, captured bounds and emitters-only projection. Quality review reports projected dimensions, samples, depth and omissions; render.quality.prepare remains reachable through command activation. S5 can call render_workspace::review_resource(app, "render.quality.prepare", id) for its selected specification. Programmatic commands continue to execute without opening dialogs.

Remove shot uses the existing shared Confirm; remove stage and saved optics now also use it. Resource removal confirmations expire after a document revision change.

Confirmed reviews run render.preset.apply, render.library.studio.apply or render.library.environment.apply, preserving validation and undo. Studios require an explicitly selected GPU path setup; environments require CPU or GPU ray tracing. Frame shows a faded Frame presets placeholder with its Shot editor reason. Output hosts the Size presets card described below. Stage navigation itself never applies a resource.

The 110 pt compass uses the free canvas beside the Inspector; the navigation bar keeps its shared handler. The Shots strip's independent view.shots_strip preference is unchanged.

view.render_focus {on: true} hides the Browser, Inspector and Shots strip and releases their canvas reservations. Tab toggles focus while Render is active and no text field has focus; the Exit focus chip sits at the Browser's remembered side below the stage bar. The workspace card, stage bar, compass and view bar remain available. Focus belongs to the window, is never saved in a design or preferences, and retains the docks' sides, widths and folded state.

Below 1100 pt, or with view.layout {mode: compact}, the docks use their shared minimum width without overwriting the remembered width. Below 800 pt the Browser folds into a chip. Its floating card opens through view.render_browser {open: true} and closes through Fold Browser; it shields navigation beneath the card without reserving a canvas column. Neither command edits or evaluates the design, moves the camera or creates an undo step.

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. Fresh native setups use CPU progressive with sample and seed controls. The normal UI presents progressive sampling as the active mode; a loaded fixed setup keeps its existing 1, 4 or 16 spatial samples until the user explicitly adopts progressive sampling. The compatibility preference also exposes the old Single image / Progressive selector. Sample and image limits follow the selected CPU resource profile. Both routes use Neutral / Warm and cool / Key and rim lighting, cast shadows and exposure from −16 to +16 EV. The UI proposes a smaller size only as an explicit action. Transparent background exports straight-alpha edge coverage for both sampling modes; body and face opacity still require 100%. Bloom, backdrop and photographic effects require opaque output and remain explicit refusals. 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 for units, limits and the immutable capture contract. The common Glass editor supports stable saved targets. Without Indirect lighting, CPU Glass uses the certified sheet/box subset. With Indirect lighting, general Glass adds certified closed meshes under its geometry, transmission and scattering restrictions. The Lights editor exposes point/spot and rectangular lights. Emission, surface effects and anisotropy retain their bounded API contracts. Indirect lighting has its own Sampling controls and validates saved or temporary optical bindings against the selected transport; unsupported combinations refuse without removing the bindings.

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. Sampling > Path tracing exposes progressive sample counts from 1 to 4096, maximum path depth (1–16) and random seed. Exposure (−32 to +32 EV) lives in Shot. 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. Automatic ray-traced live images use the captured image exposure, environment, lens and supported material effects at interactive resolution. The integrated direct-light preview is the fallback while no live image is available, or for Raster and the compatibility workflow.

Effects > Tone exposes Reinhard / ACES fitted tone mapping. Sampling > Path tracing owns optional edge-aware noise reduction for progressive and final display images; Shot owns thin-lens depth of field. Positive aperture requires a perspective product camera. Denoising preserves raw accumulation but can soften detail; glass and sharp specular first hits bypass its spatial filter.

The Environment Browser row opens the Environment editor. The legacy Environment and Background pages use that same editor, with five sections in order: Source, Orientation and strength, Backdrop, Ground and stage, and Atmosphere (GPU). Source offers None, Artistic sky, HDR file and embedded HDR for GPU, or None, Constant and HDR for CPU. Change opens the Environments scope of Studios and environments. Embedded HDR shows its name, kind and saved-in-design status; sky exposes zenith, horizon and ground linear colours. CPU HDR has lighting samples. Radiance .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.

Rotate and Intensity use the existing environment command; the rotation ring is their shortcut. Backdrop offers World, Colour, Gradient and Clear. Gradient uses the existing GPU camera backdrop (vertical, horizontal or radial, two colours, centre and radius). It never lights, casts shadows or reflects, and is refused with transparent output. World visibility and blur remain faded because no saved renderer setting backs them. Unsupported method choices stay faded with a reason.

Ground and stage fits a saved ground, floor and wall, or polygonal cyclorama. Replacing a stage requires the explicit consent checkbox; removing it uses the shared Remove the saved stage? confirmation. The fields expose extent margin, clearance gap and linear reflectance, followed by the saved panel count. Atmosphere edits the bounded participating medium: enable, world bounds in mm, extinction, scattering albedo and phase. The transitional Aging page's airborne section calls this same function. CPU and raster show the controls faded with the GPU requirement. These controls use existing render state and commands; opening the editor never changes the design or renderer.

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.

Appearance editor and body optics

Picking a face, body or component opens Appearance. Its kind chips, look card and Applies to scope lead to Edit: colour, finish, metallic, roughness, opacity and IOR. The look card's source tag opens the inheritance chain. Reset restores the picked target's values from when it was opened; Save to library uses the existing design library export flow.

Glass and absorption (CPU/GPU), Clear coat (CPU/GPU), built-in Maps (CPU/GPU), Saved with this shot, and Reflections (CPU) follow in that order and start collapsed. Unsupported methods remain visible with an explanation; opening a section never changes the renderer. Optical bindings currently target one whole visible body, so face, component and multiple-body picks show the same controls disabled with a reason. The Browser command has no Wear selection kind yet, so no Open Wear link is shown.

The old Appearance page retains explicit target selection and the library/reference and wear controls awaiting their own editors. Its body optics use the same sections as the picked-body editor. Scene ordinal, exact name, stable target and document identity are checked; a document revision change requires Revalidate this body.

Six original glass recipes use linear transmittance over a reference distance to compute absorption per millimetre via -ln(T) / distance. Glass exposes boundary, IOR, thickness, RGB absorption, straight shadow transmission and closed-solid interior scattering. Thickness is disabled for closed glass, which uses geometric distance. Glass cannot share a body with coat or maps. Full topology, orientation, overlap and optical-boundary checks use the selected producer. CPU without Indirect lighting keeps its strict sheet/axis-aligned-box subset. Explicit CPU Path supports certified general closed meshes, nested media and selected-medium scattering; GPU has its own certificate and nested-mode policy. The common controls never bypass those geometry or combination checks. See renderer parity for historical qualification and this change's Glass follow-up.

Clear coat retains weight, roughness and IOR in common CPU/GPU saved bindings. Built-in surfaces can save base-colour, normal, metallic and roughness maps for both methods, with stable target identity and a definition-local frame. External PNG/JPEG picker maps remain GPU-only temporary inputs; portable external-map import is separate unqualified work. The map-size, encoded-byte, repeat and assignment limits still apply. File-picker completion checks the original document, revision and body identity.

Local edits remain prospective on the document tab until saved. Save these optics uses render.optics.bind; replacing different saved Glass requires the explicit Replace this body's saved optics checkbox. Save coat to shot uses the separate stable coat binding. Built-in surface bindings are also saved; external image file mappings remain temporary. Remove saved opens the shared Remove saved optics? confirmation before render.optics.unbind; stale confirmations cannot affect a changed document. Saved authored surface bindings remain manageable in Saved with this shot. Reflections retains this body's Off/Mirror/Rough CPU binding and explicit target confirmation.

CPU uses the common IOR/Beer controls, while transport choices remain explicit. Without Path, general boundaries, scattering and transmitted shadows refuse. With Path, certified general Glass and thin transmitted shadows are supported; closed transmitted shadows and external Atmosphere with Glass still refuse. Coat/maps cannot share a Glass target, but unrelated opaque targets keep their supported effects. Check and Start each use fresh captured intent. Strict preparation performs the full general-Glass certificate and carries its proof into that prepared job's renderer. A separate Render click prepares a fresh capture; it does not reuse an earlier Check proof. Saved target A and prospective target B merge as stable assignments; checked file HDR capture preserves them on CPU and GPU without an ordinal-override detour. Unsupported combinations refuse and no implicit Save occurs. See PR #11087 for this follow-up's exact source and qualification. Historical CI7 and opaque native results remain separate.

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, section cuts, analysis shading, active-component fading, canvases or decals in the product scene. 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 Transparency, fixed AA or progressive SPP/seed, resource profile, optional opaque path depth, guided noise reduction, physical lens, tone map/finishing/backdrop and raw EXR retention, certified saved optical bindings, preset or custom directional lights, point/spot and area lights with 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

CPU path lighting can combine with certified optical bindings under the general Glass restrictions. Incompatible saved intent still refuses before HDR IO or scene capture. 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. Saved stable Glass, clear-coat and built-in surface bindings travel with complete CPU/GPU jobs. Temporary runtime body bindings, including disabled assignments and external GPU image maps, still cannot be saved by full-job Save; use the explicit portable binding actions for supported inputs. The panel explains those limitations and refuses unsupported Save before changing the document. Temporary inputs can still execute through the 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 and Fit Product frames visible product bodies without including sketches or selection.

In the normal workflow, Fit Product, entry fit, product drawing, navigation, live capture and picking always use the active output frame inside the free canvas. Selecting Shot, Sampling, Effects or Output changes neither its camera nor aspect; a portrait output therefore stays portrait in every editor. Entry fit waits for the saved setup to load. The previous Frame-only projection policy remains behind Use previous Render image defaults. render.camera.fit takes the picture's aspect (width over height, 0.000001 to 1000000, default 1) and refuses a fit whose camera would be out of range, leaving the current camera as it was.

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. The integrated schematic fallback keeps its existing drawing policy; its normal-workflow framing still follows the active output aspect.

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 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. On desktop the preview takes up to eight of the device's largest buffers of vertex geometry (2 GiB with the usual 256 MiB buffers, never more than 2 GiB); uploads are split into buffers within that size. The web keeps a 128 MiB budget. The budget is checked before allocation, and a refusal names the scene's geometry size, the limit and how to get under it (hide bodies in Design). The upload itself runs under its own GPU error scopes: an allocation the device refuses is shown in the preview instead of drawing, and nothing else in the app changes how GPU errors are handled. Messages sit on a theme panel card so they stay readable on any background colour. The separate CPU image job keeps its own memory and work limits. 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.

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.

Picking in the product view

The Look stage bar's second-row Pick control selects Body, Face or Component granularity, using Design’s selection filter state through the select.filter command. Component picks use the Browser’s exact occurrence path, including nested and repeated placements; a body at the design root retains its body identity. Face picks use the existing mesh-to-B-rep mapping and connected-surface selection rules.

Hover highlights the target; clicking selects it. Clicking empty space clears the selection. Shift and Ctrl/Cmd follow Design’s add/toggle behavior and the Shift add-only preference. Browser row selections and product picks share the same selection commands and state, retained across Design/Render switches. Picking works with the Shots strip shown or hidden. Render picking never starts a geometry edit.

Selection and hover use Design’s highlight drawing and theme tokens in a separate GPU overlay on the live product view. The product scene and its upload stay unchanged. CPU image jobs, exported PNGs, retained images and the Render Result canvas never contain this overlay; the Pick control is disabled on the result canvas.

Look's tools row contains Paint (B) and Pick Up (I). A library click applies to the current selection or starts painting when nothing is selected; dragging previews the look until release. Esc or Done ends painting or sampling. Copy Look and Paste Look use Ctrl/Cmd+Alt+C and Ctrl/Cmd+Alt+V.

The selection pill uses shared kit chrome and follows the projected selection. Its actions open the look chain, Replace All, toggle a library favourite and hide the selection. The name opens the selection menu. Assign, Replace All, Copy Look and Remove are available there and in the Appearance Inspector; commands also remain available to search and scripts. Replace All asks for the replacement in a shared confirmation and applies one undoable command. A changed document cancels that pending request. Hover uses the shared tooltip with the object and look names.

Browser scene focus

The existing Camera Inspector page shows a standalone Shot editor when the Browser selection is a saved shot. Opening it leaves the live camera and saved design unchanged. Camera fields use render.camera.set; Update shot saves that camera and Revert restores the saved camera. Name, output dimensions and exposure use the existing undoable shot/settings commands. Distance is shown as a multiple of the visible subject's bounding-box diagonal (one millimetre for an empty scene). The lens chip uses the camera's vertical FOV and a 24 mm sensor height.

Frame's floating panel offers five aspect presets and Custom, plus composition guides. Clicking a preset saves its output dimensions in one undo step; Custom preserves dimensions. view.render_frame independently validates and echoes transient aspect/guide preferences; headless calls never edit a design. Guides are per-document UI state, never saved in design JSON. Composition guides and their size/lens chips appear only in Frame or the Shot editor. Their transient/selected-shot aspect is independent of the active output camera; hiding or changing those guides never changes normal-workflow product framing, live pixels or picking. Image jobs and the Result canvas omit guides. Retained results and comparison images continue to use their captured dimensions.

The shared Browser lists Environment (with its source), Lights, saved Shots, Objects and Output (with image dimensions and format). Shots + opens the existing Shots manager; Lights +, Solo and Mute remain faded with an explicit reason until named light commands exist. Existing light entries describe the current numerical image setup, without inventing a saved rig.

ViewState.selection exposes RenderSelection for Nothing, Object (the existing engine selection), Environment, Light, Shot and Output. It belongs to each document view and is never saved in a design. view.render_select validates semantic focus requests without opening dialogs or editing/evaluating a design. Object picks and Browser selections keep the existing selection commands. Selecting Output opens the Output editor; selecting Environment opens its editor. The legacy Environment and Background entry points share the Environment editor.

Look expands Objects, Light expands Lights and Environment, and Frame expands Shots. Output leaves expansion unchanged. Stages preserve selection and never lock rows or prevent manual expansion.

Appearance editor

Look shows one Appearance editor with scope, current look, the four-step look chain and Edit controls. There is no Inspector page strip. Applies to chooses the selected target or every exact user of the look; mixed values remain inert until edited. Edit contains colour/hex, finish and metallic/roughness/opacity sliders. Advanced reuses the existing surface library, optical bindings, glass, clear coat, texture-map, reflection and aging controls. The separate Textures disclosure is marked Soon. The shared footer exports the design library through library.export and resets the current target's override through appearance.assign. view.render_inspector {visible} controls transient per-document visibility; selecting a stage reopens the editor. Output selection routes to its dedicated editor; Environment selection routes to its editor. Other semantic selection focus routing remains deferred.

Output editor

The Output stage offers size, format, quality and a Check summary in the stage bar's second row. Its lower-left Size presets card offers Preview (1280 × 720), Full HD, 4K, Square and Custom. Presets outside the selected executor's limits stay visible with a disabled explanation showing the selected method's dimension/pixel limits and largest fitting size. The default raster limit is 4,194,304 pixels, so 4K exceeds it; methods with larger resource profiles can admit 4K. Custom retains the current size and reveals its fields through render.output.size. Numerical size edits and preset clicks patch width and height with render.settings.set, as one undo step. Opening the panel never applies a preset or starts a job.

Selecting Output in the Browser shows a short editor with Renderer, Image, Destination and Render sections. Sampling, Effects and Check are child rows under Output, each with a summary and its own editor. Sampling owns Quality, GPU Path tracing, Adaptive, Glass transport and CPU ray tracing. Method-specific controls stay visible and faded with their reason on other methods. Effects owns Tone, Creative looks, Lens effects, Finishing and Regrade, in that order; its controls support CPU ray tracing and GPU path tracing. Effect edits patch the saved job with render.settings.set; opening an editor never saves or switches methods. Check owns the preflight notes, This request, Renderers and collapsed Under the hood diagnostics. The legacy Effects, Output and Diagnostics pages call the same editors.

The stage bar's Check chip and Output's note count open Check. Check now runs the read-only render.preflight without admitting a job. Notes offer links to their owning editor. Copy report and diagnostic JSON use render.preflight.copy and the platform clipboard queue; headless calls only validate and echo bounded text. GPU Draft, Balanced and High apply a fresh canonical fixed budget in one undo step. Sampling shows resolution, samples, path depth, seed and noise reduction; hovering the chips lists all three budgets. Imported library specifications keep their acknowledged review. The saved camera and other effects stay intact; an incompatible combination leaves the draft unchanged. The highlight follows the actual budget fields and returns to Custom after an edit. These GPU budgets remain disabled on CPU and Raster. CPU keeps its own sample controls; Raster remains the schematic method. EXR export is available only for the selected completed image with an actual retained master. Destination selection uses the completed-image export picker. The pinned Render Image / All shots footer starts the active setup or queues all saved shots through render.batch; opening the editor never starts a job.

Render and Cancel stay in the stage bar. Active jobs also show a single-row progress pill with Cancel. The result viewer retains Copy, export, close, Fit/100% and shared pan/zoom. R starts the active setup; Escape closes the image without cancelling its job.

Preferences › Graphics offers “Use previous Render preview geometry budget” (render_previous_geometry_budget). It restores the fixed limit (512 MiB on 64-bit desktop, 128 MiB elsewhere); by default, desktop previews use the device-based budget. Changes apply to the next preview frame.

CPU Glass uses the common body editor and stable saved optical targets. Fixed jobs retain the strict sheet/axis-aligned-box subset and refuse scattering or transmitted shadows. Explicit Indirect lighting selects the certified general Glass path, including its conditional thin-shadow and scattering contracts. Reopened controls preserve the actual saved numbers. Edits are prospective; Save/replacement/Remove own document changes. Unchanged hydration and Discard do not save or start a final job. The multi-target merge in this change does not imply an automatic Save. See general Glass and the qualification record.