Multi-model scene API

vibeview.model_scene.ModelScene maintains several structures in a common Cartesian coordinate system. Each model has a unique string identifier, visibility, colour and representation. Model imports are detached copies; changing a caller’s structure does not change the scene.

The example below reads the first structure from two QVF archives. Use reader.read_structure("section-id") when an archive contains several structures and you need a particular one.

import numpy as np
from vibeview import QVFReader
from vibeview.model_scene import ModelScene

scene = ModelScene()
with QVFReader("reference.qvf") as reader:
    scene.add("reference", reader.read_structure())
with QVFReader("mobile.qvf") as reader:
    scene.add("mobile", reader.read_structure())
scene.appearance("mobile", colour="#e89c28", style="wireframe")
scene.transform("mobile", np.eye(3), np.array([1., 0., 0.]))
scene.select('model reference and not element H')
scene.name_group("reference heavy atoms")

Selection expressions use the shared grammar. In a scene, index refers to the one-based flattened atom list in model insertion order. Returned atom references are (model_identifier, zero_based_local_index). These references remain stable when another model is moved or removed. Selections include hidden models; visibility changes drawing, not membership. Radius queries use the current transformed coordinates, without periodic images. Removing a model prunes its references from the current selection and named groups.

transform(model, rotation, translation) requires a proper orthonormal rotation. It transforms atoms and lattice vectors consistently, retaining integer bond images; translation applies to atoms. Reflections, scaling and nonfinite inputs are refused. align_model(model, mobile_indices, target_references) fits explicit ordered atom correspondences using proper Kabsch alignment, transforms the entire mobile model and returns RMSD. Correspondences must be unique and equally sized. No atom mapping is inferred; collinear or very small selections may leave the rotation underdetermined even when RMSD is zero.

Save and replay

scene.to_dict() is a versioned JSON-compatible scene snapshot. Restore it with ModelScene.from_dict(snapshot). scene.script() produces a JSON event log; ModelScene.replay(script) reconstructs the scene, including model appearance, rigid transforms, selection and named groups. Structures and metadata are embedded in the import event so replay does not reopen a potentially changed source file. A loaded scene starts its log with an embedded restore event. Logs contain data, not executable Python; unknown events and versions are refused.

import json
from pathlib import Path

Path("scene.json").write_text(
    json.dumps(scene.to_dict(), allow_nan=False), encoding="utf-8"
)
Path("scene-script.json").write_text(scene.script(), encoding="utf-8")
restored = ModelScene.replay(Path("scene-script.json").read_text(encoding="utf-8"))

Use scene methods for edits that must be replayable. Direct mutation of the public model objects is not journalled. The model scene is a working structure representation, not a replacement for a complete QVF archive: wavefunctions, volumes and calculation records remain in their original files. Save those files alongside the scene when they are needed for subsequent analysis.

The browser adapter below provides command controls and rendering. The desktop Python console exposes the same scene API. These submodule interfaces are version-specific; pin the viewer version for scripts that use them, as described in the SDK contract.

Command interpreter

vibeview.scene_commands.SceneCommands shares one interpreter between SDK and viewer adapters. execute(line) returns a JSON-compatible result; successful commands enter history. Invalid commands do not alter scene state or enter history. Selection evaluation for measurements does not replace the active selection. Names and paths containing spaces, and each measurement/alignment selection expression, must be quoted. The select command takes the remainder of the line as the selection expression, preserving its own quotes.

open reference "reference structure.xyz"
open mobile mobile.xyz
select model reference and not element H
group "reference heavy atoms"
colour mobile orange
style mobile wireframe
hide mobile
show mobile
move mobile 1 2 3
rotate mobile 0 0 1 90
align mobile "model mobile" "model reference"
measure centroid "model reference"
measure axes "model reference"
measure plane "group 'reference heavy atoms'"
measure rmsd "model reference" "model mobile"
measure rmsd-fit "model reference" "model mobile"
measure plane-angle "index 1-3" "index 5-7"
measure point-plane "index 4" "index 1-3"
save scene.json
save-script scene-script.json
capture figure.png
remove mobile

move supplies an angstrom translation. rotate supplies a nonzero axis and an angle in degrees, about the scene origin. Use translations before/after a rotation to rotate about another point. A model colour paints atoms, the bonds of the bond-only sticks_only and wireframe styles, and cartoons; ball-and-stick bonds keep their usual colour. colour MODEL none restores default element colours. Supported styles are ball_and_stick, space_filling, sticks_only, wireframe and cartoon (the renderer’s usual non-biomolecular fallback applies).

Alignment and paired measurements order each selected set by model identifier then local atom index. Verify that this order expresses the intended chemical correspondence; use the lower-level align_model API for another explicit order. The mobile alignment selection must belong entirely to the named mobile model. The first point-plane selection must contain exactly one atom. Measurement results include units; principal-axis variances have squared length units.

An adapter supplies load_structure(path), write_text(path, text) and capture(path) callbacks. Without the relevant callback, file and capture commands refuse explicitly. The interpreter itself executes no Python and opens no files. save writes the scene snapshot, and save-script writes the embedded data event log described above; replay reconstructs state without repeating file writes or captures. history retains the successful command text for display. In the browser, the command box clears after a successful command (pick it again from the history list) and keeps a failed one for correction.

Browser working scene

The Working model scene card can copy the current open structure into a named model, preserving connectivity. Open another file normally, then add it under a different name. The Show working scene switch temporarily hides the original structure actors; switching it off restores their prior visibility. Volumes and experimental maps remain separate. Model edits operate on the copied working scene and do not overwrite the original QVF structure.

Enter commands in Command / history and press Enter or Run command. Pick a previous command from the same field to edit and repeat it. open accepts a server-side path, like the viewer’s standard open-path control. Alternatively, use the normal browser file picker and Add current structure. Selected atoms are highlighted in gold in atom representations. Cartoon colour is per model; atom selections remain available for measurements regardless of representation.

save and save-script download JSON. They also include the current server camera and successful command history. Paste either JSON file into the restore field and choose Restore scene / replay script to rebuild the working models and camera. capture downloads a PNG from the same server actors, using the camera synchronized by the viewer. Filenames designate browser downloads; these commands do not write arbitrary server paths. A moved periodic model keeps its unit-cell drawing at the transformed cell origin as well as rotating its lattice vectors.

The model scene is independent of the standard single-structure editor and its undo stack. Use scene commands for these models; disable the working scene to return to the single-file editor. Browser event/render acceptance is tracked separately from server-side controller and pixel replay tests.