Skip to content

chore: [Remote rendering 3.6b] Resolve state on server and apply as given on the client - #166

Open
LKasianAnsys wants to merge 14 commits into
chore/3.6c-reserialize-in-rendererfrom
chore/3.6b-resolve-state-on-server
Open

LKasianAnsys wants to merge 14 commits into
chore/3.6c-reserialize-in-rendererfrom
chore/3.6b-resolve-state-on-server

Conversation

@LKasianAnsys

@LKasianAnsys LKasianAnsys commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Issue

Addresses #24

Context

Until now, the viewer's per-part visual state (whether a part is visible, its opacity, selected, diffuse color, color variable) was allowed to be unset/null at every level. The server's runtime record for a part could hold null in any field. For example, a freshly loaded dataset had no part records at all, so if a dataset were loaded immediately followed by a save_state, the save would write parts: {}, and a load_state had inconsistent handling of null or missing values: a literal fallback in some server apply paths, and the client's own values in others.

This PR makes this behaviour deliberate: the server resolves a value for every field, so a runtime record is never unset. A file is applied over the server's current state by one rule. The client applies what it is sent, no longer holding defaults of its own.

Changes

  • The server resolves a value for every field in the state, per part and per scene, so a runtime record is never unset. The runtime state is split by owner (RuntimeUIState, RuntimeSceneState, RuntimeViewState, composed by RuntimeAppState).
  • Persisted state application rules: A loaded file is applied over the server's current state, once, in VisorStateMapper.persisted_to_runtime, per field:
    1. key absent: not applied; the server keeps its existing value (defaults, where no custom state had previously existed)
    2. key present but null: reset to the default
    3. key present with a value: take the value.
  • The wire carries every key with a resolved value. null appears only where it is meaningful: colorVariable, the camera, clipping plane, and orthographicEnabled before a camera exists.
  • RuntimeViewState now handles the camera and cross-section plane.
    • It is composed into RuntimeAppState (used in load_state) and is dropped from VisorSceneDetails (used in server pushes/reconnects). The renderer owns camera and cross-section plane records, and the object graph already delivers them on every API push so the payload copy was a second channel the client never applied.
    • The load_state path keeps them under RuntimeAppState.view: the client currently applies them from that push rather than relying on the object graph for delivery.
  • The client builds each node from its its delivered record and holds no defaults. A null colorVariable turns scalar coloring off and the delivered diffuse color shows. The Dash parts prop follows from the wire.
  • In add_dataset the server applies every part's record to its pipeline. Metadata-seeded records were prviously stored and never applied on the server; the client did it on first delivery, which this PR removes.

Persisted state

The persisted file schema is unchanged and older files load as before.
Visible behaviour changes:

  • Running start with a dataset loaded, then immediately running save_state writes a record per part. (Previously it held 'null' values throughout).
  • A null or malformed field in a loaded state is rewritten resolved on the next save
  • A file's unit now overrides the metadata unit, if load_state contains a unit.

Manual check

  1. Load a dataset with two or more parts, turn the bounding box on, and save. The file has a record per part (previously parts: {}).
  2. Edit the file: part A "opacity": null; delete part B's "visible" key; "unit": null; delete "bounding_box_enabled"; "darkTheme": null.
  3. In the app set A's opacity to 0.3 and hid B, then load the saved state. A should be opaque, and the unit should be empty (null reset); the theme is the theme that it was launched with. Run save_state again: A's opacity should read 1.0 in the saved state file, not null.
  4. Run start or add_dataset with metadata setting the opacity of one or more part: the correct opacity should be applied on the first frame.

Copilot summary

This pull request refactors and improves how runtime and persisted viewer state are modeled and resolved on the server. The changes clarify the separation between runtime (in-memory, server-owned) and persisted (file-loaded) state, introduce overlay logic to cleanly resolve state when loading files, and update several models to use required fields with explicit defaults. The refactor also splits the UI, scene, and view state into distinct models, each with clear responsibilities.

The most important changes include:

State Modeling and Overlay Logic:

  • Introduced overlay methods (overlaid_with) for RuntimeUIState, RuntimeSceneState, and RuntimePartProperties to resolve the final runtime state by combining current, persisted, and default values according to clear rules. [1] [2] [3]

UI, Scene, and View State Separation:

  • Split the runtime state into three distinct models: RuntimeUIState, RuntimeSceneState, and new RuntimeViewState, each with required fields and explicit defaults. Updated RuntimeAppState to own these records. [1] [2] [3]

Part Properties Refactor:

  • Refactored RuntimePartProperties to require all fields except color_variable, provide a default_for method, and implement overlay logic for merging with persisted properties. Added VariableReference for color mapping.

Persisted State Model Renaming:

  • Renamed VisorUIState to PersistedUIState for clarity, and updated all references to use the new name. [1] [2] [3] [4]

Defaults and Constants:

  • Added VisorPartDefaults for default part property values, centralizing defaults for opacity, visibility, selection, and color.

These changes collectively improve maintainability, clarity, and correctness when resolving viewer state, especially when loading files with partial or missing information.

@github-actions github-actions Bot added test Work associated with testing miscellaneous labels Oct 9, 2026
@LKasianAnsys
LKasianAnsys changed the base branch from main to chore/3.6a-clean-up-state October 9, 2026 21:54
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6b-resolve-state-on-server branch from 2b71e87 to b43d7cd Compare October 9, 2026 22:09
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6a-clean-up-state branch from 72ff429 to edc2803 Compare October 13, 2026 17:06
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6b-resolve-state-on-server branch 3 times, most recently from 094f434 to 137b19f Compare October 14, 2026 03:37
@LKasianAnsys
LKasianAnsys changed the base branch from chore/3.6a-clean-up-state to chore/3.6c-reserialize-in-renderer October 14, 2026 03:38
@LKasianAnsys
LKasianAnsys marked this pull request as ready for review October 14, 2026 04:41
@LKasianAnsys LKasianAnsys changed the title chore: [Remote rendering 3.6b] Resolve state on server when a file is loaded chore: [Remote rendering 3.6b] Resolve state on server and apply as given on the client Oct 14, 2026
@LKasianAnsys
LKasianAnsys changed the base branch from chore/3.6c-reserialize-in-renderer to main October 14, 2026 13:34
@LKasianAnsys
LKasianAnsys changed the base branch from main to chore/3.6c-reserialize-in-renderer October 14, 2026 13:34
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6b-resolve-state-on-server branch from 3d535ce to 7458089 Compare October 14, 2026 20:45
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6c-reserialize-in-renderer branch 2 times, most recently from 4a618a5 to 3e43f27 Compare October 15, 2026 15:00
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6b-resolve-state-on-server branch from 285c16f to 2b40e33 Compare October 15, 2026 15:00
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6c-reserialize-in-renderer branch from 3e43f27 to bf0e6dd Compare October 16, 2026 17:04
@LKasianAnsys
LKasianAnsys force-pushed the chore/3.6b-resolve-state-on-server branch from 2b40e33 to a1b3d5d Compare October 16, 2026 17:05

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

miscellaneous test Work associated with testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants