Strip near / far from a settings snapshot when dynamic clipping
owns them.
TWO places push the LIVE camera near/far into settings.near /
settings.far so the (read-only, greyed-out) sliders show current
values: ClippingDisplay's RAF loop, and syncCurrentState on every
panel-open. Those are transient camera-derived readouts, not user
intent — but saveSettingsToStorage
serializes the whole settings object, so ANY later control change
would persist whatever the camera happened to read at that instant
(e.g. near = 1.05e-4, far = 61 from a zoomed-in pose). The next
load then re-applies them as FIXED manual planes via
setSceneId → updateClippingPlanes, pinning a pathological
near/far even though nothing was set by hand.
Omitting the keys (rather than writing defaults) means the load path's
{ ...buildBaseDefaults(), ...loaded } spread in
RenderingControls.loadSettings leaves config.renderingControls.defaults
standing for near / far, after which autoAdjustClippingPlanes + the
per-frame dynamic update take over — which is the whole point of the mode.
(The validateRenderingSettings call wrapping that spread only clamps
non-finite / out-of-range values; it is the spread, not the validator,
that supplies the fallback.) When dynamic clipping is OFF the values ARE
user intent, and are persisted unchanged.
Strip
near/farfrom a settings snapshot when dynamic clipping owns them.TWO places push the LIVE camera near/far into
settings.near/settings.farso the (read-only, greyed-out) sliders show current values:ClippingDisplay's RAF loop, andsyncCurrentStateon every panel-open. Those are transient camera-derived readouts, not user intent — butsaveSettingsToStorageserializes the whole settings object, so ANY later control change would persist whatever the camera happened to read at that instant (e.g.near = 1.05e-4,far = 61from a zoomed-in pose). The next load then re-applies them as FIXED manual planes viasetSceneId→updateClippingPlanes, pinning a pathological near/far even though nothing was set by hand.Omitting the keys (rather than writing defaults) means the load path's
{ ...buildBaseDefaults(), ...loaded }spread inRenderingControls.loadSettingsleavesconfig.renderingControls.defaultsstanding fornear/far, after whichautoAdjustClippingPlanes+ the per-frame dynamic update take over — which is the whole point of the mode. (ThevalidateRenderingSettingscall wrapping that spread only clamps non-finite / out-of-range values; it is the spread, not the validator, that supplies the fallback.) When dynamic clipping is OFF the values ARE user intent, and are persisted unchanged.