Core Crates

A selective deep-dive: of the 19 crates under core/, this section covers the seven a contributor touches most (backbone, query, selection-engine, render, edit, forcefield, periodic). Repository Layout lists them all in one line each, and Services Layer covers core/services.

5.1 Backbone (core/backbone/src/lib.rs)

  • Defines newtype identifiers (AtomId, BondId, FrameId, PropertyId) and element metadata (periodic module) used across the workspace.
  • SceneBuilder constructs snapshots with atoms, bonds, metadata, editable MolecularElectronicState, and derived data (electronic structure, vibrational modes, thermochemistry). The molecular state belongs to the current structure; parsed ElectronicStructure remains evidence from the source calculation. SceneGraph wraps the snapshot with provenance hashing (SceneDigest) for change detection.
  • PropertyRegistry stores globally registered per-atom or per-scene properties, enabling dynamic queries and render overlays.
  • Exports helpers such as infer_covalent_bonds, AtomPopulation, FrequencyData, Trajectory, and UnitCell. Loader and renderer crates consume these types.

5.2 Query & Selection (core/query, core/selection-engine)

  • core/query provides the selection expression enum, parser, and evaluator. Supported primitives include element filters (element O, bare symbols, atomic_number == Z), distance shells, angle windows, nearest-neighbour queries, property comparisons, and residue terms (chain A, resname HIS, resid 42), and retained alternate locations (altloc B).
  • Residue terms read the same accessors as the grouping. There is no residue entity in the scene graph — a residue is a view over per-atom PDB/mmCIF annotation — and orbitron_backbone::residues is the one definition of (chain, seq, insertion code). Both the selection evaluator and any panel that reports a residue go through ResidueProperties, so they cannot come to disagree about what HIS 42 means. The insertion code is part of the identity: an antibody numbered 100, 100A, 100B is three residues, and dropping it merges them. The Scene panel’s Coordination readout is the other consumer: it names a metal’s site (Zn C1) and its donors (via HIS A1 NE, …) through the same accessors, and caches the formatted strings on the scene digest — resolving a donor id costs a lookup, and the panel redraws sixty times a second for text that only changes when the structure does.
  • The residue view also retains mmCIF label-chain and label-sequence identifiers, label-component identifiers, named alternate locations, and source atom IDs. _chem_comp definitions supply controlled component type, name, formula, mass, and standard parent identity. ResidueKind and Residue::one_letter_code supply the compact protein/nucleic-acid labels used by the desktop navigator. Modified peptide and nucleic-acid monomers use their source type and parent, while unknown, peptide-like, and non-polymer components remain Other rather than being guessed into a polymer sequence. Parsers store coordinate-independent DeclaredResidue rows under pdb:polymer_sequence. residue_sequence joins them to observed residues by mmCIF label identity first and author identity second, then emits atom-free unresolved entries for unmatched source rows. This also keeps non-standard declared monomers in their polymer chain. The navigator caches the joined model by scene digest and emits SelectionPanelAction::ApplyAtomSet, so it shares the canonical viewport selection. Per-digest egui memory retains the residue query and focused identity. The latest still-selected atom in selection_history supplies a one-shot scroll target; recording the followed atom prevents the panel from snapping back on every frame. A second digest-keyed cache joins pdb:atom_name values to residue ids once per scene for live filtering. Search terms are ANDed; qualified author sites are exact, while plain residue and atom terms support partial matching.
  • ResidueProperties also owns alternate-location access. Bond inference uses it to reject contacts between different named locations in the same residue, while blank-location atoms remain compatible with every conformer.
  • alternate_location_choices and preview_alternate_location_edit in orbitron-edit keep alternate-location mutation residue-local. Keep-only removes other named conformers and clears the retained pdb:alt_loc values; delete removes only the selected conformer. Both preserve shared blank atoms, report incident and cross-residue bonds, reject stale previews, and restore deleted atoms, bonds, and property values exactly on Undo.
  • water_ion_cleanup_selection groups candidates through the shared residue model and uses the query crate’s whole-residue, minimum-image contact search for Within/Beyond filters. Classification is conservative: named water must have water-site composition, while an ion must be monatomic and its component identity must agree with its metal or halide element. The preview pins exact residue, atom, charge, and bond removal before one undoable command.
  • Shared structure analyses live beside the selection evaluator in core/query: residue contacts, ligand and chain interfaces, explicit-H hydrogen bonds, named salt bridges, disulfides, and steric clashes. steric_clashes_excluding returns deterministic worst-first pair records with distance, the limit at 80% of the summed van der Waals radii, and positive overlap. It excludes bonded and 1-3 pairs, applies caller-supplied alternate-location exclusions, and uses Cartesian or periodic candidate bins before the exact distance test. The residue-mutation preview consumes these records rather than carrying a second clash implementation.
  • ramachandran_residues_excluding builds complete protein triplets from the same residue model, converts the shared math crate’s dihedral sign to the PDB/CCTBX phi/psi convention, and unwraps periodic coordinates one backbone leg at a time. It bilinearly interpolates six Richardson Lab Top8000 grids bundled under core/query/data/ramachandran/. The data directory pins the upstream commit, CC BY 4.0 license, binary layout, and regeneration command. Callers supply hidden alternate-location atoms; the result records residue identity, visible residue atoms, the five defining backbone atoms, reference class, angles, score, and favored/allowed/outlier category.
  • missing_side_chain_residues_excluding compares each retained amino-acid conformer with the expected heavy side-chain atom names from Orbitron’s standard residue templates. A retained CA atom distinguishes a coordinate-bearing residue from an unresolved entry or an isolated named donor. The result records residue and conformer identity, visible atom IDs, and missing atom names. It ignores backbone atoms and hydrogens, maps common protonation variants to their parent template, supports MSE and SEC, and omits residues without a known complete template. Caller-supplied exclusions keep the result aligned with the active alternate-location view.
  • rotamer_residues_excluding measures CCTBX-defined chi angles for complete rotamer-bearing amino-acid side chains and unwraps each path in periodic structures. It interpolates 17 sparse Richardson Lab Top8000 grids bundled under core/query/data/rotamer/; the data directory pins the upstream commit, CC BY 4.0 license, binary layout, and regeneration command. The result records residue and conformer identity, visible residue atoms, every chi-defining atom quartet, angles, score, and favored/allowed/outlier category. Callers supply alternate-location exclusions through the same interface used by the other structure analyses.
  • Primitives combine through the And / Or / Not AST variants, plus WithinSelection (the within <R> of <selection> operator, evaluated as the set of atoms within the radius of any anchor matched by the sub-selection). parse_expression (core/query/src/query/parsing.rs) is a two-layer parser: a lexer keeps function-call parens and quoted property names inside one primitive token, and a recursive-descent layer handles the boolean operators, the within … of prefix, and grouping (not > and > or). Element symbols resolve to AtomicNumber via orbitron_backbone::atomic_number_for_symbol, so evaluation and formatting reuse the existing atomic-number path. PropertyCompare carries a CompareOp (>, >=, <, <=, ==, !=).
  • parse_expression returns SelectionExpr ASTs; the UI’s command palette and CLI subcommands rely on it to turn input strings into programs.
  • evaluate_selection resolves expressions against a SceneGraph. Errors are surfaced via QueryError (UnknownProperty, NonNumericProperty, Evaluation).
  • core/selection-engine::SelectionProgram wraps expressions with digest-aware caching and optional scoring metadata (SelectionScore). This crate is responsible for keeping UI selection interactions performant.

5.3 Rendering Core (core/render)

  • Renderer::new initialises a WGPU surface for a winit::window::Window. Headless rendering (headless module) enables CLI exports without a window.
  • RenderSceneData aggregates instanced atoms, bonds, and labels ready for GPU upload. Helper functions (pick_atom, distance_between) are used by the viewer for hit-testing.
  • Lighting presets live in lighting.rs; set_colorblind_safe (in core/render/src/lib.rs) toggles the Okabe–Ito palette globally.
  • Bonds are rendered as instanced quads with per-instance thickness, dash, and glossiness. BondInstance::order plus orbitron_viewer_core::render_styles::apply_theme_styles (shared by desktop + CLI; ui/shell/src/util/render_styles.rs is a re-export shim) expand double/triple/quad bonds into multiple lanes using theme-provided spacing and highlight scaling.
  • Mesh pipelines (mesh::MeshRenderPipeline) handle GPU buffer management; renderer crates are the only place WGPU appears, keeping other crates backend-agnostic.

5.3.1 Embedding Orbitron Renderer (EmbeddedRenderer)

You can host Orbitron’s GPU renderer inside your own application window without using the egui UI shell. This is useful for Rust hosts (Tauri, winit, native desktop apps) that want to reuse Orbitron’s rendering pipeline.

Prerequisites

  • Rust toolchain from rust-toolchain.toml (or newer).
  • Access to a SceneGraph (load via orbitron-io-pipelines::load_scene, or via OrbitronServices, or construct using SceneBuilder).

Minimal integration

orbitron_render::EmbeddedRenderer wraps the renderer with a synchronous API. For a full runnable reference see examples/sdk/ (Rust SDK integration) and examples/web-embedding/ (WASM viewer).

The core steps are:

  1. Create an EmbeddedRenderer from your window. The constructors borrow the window (EmbeddedRenderer::new(&window) / new_async(&window) / with_mode_async(&window, mode)), so the window must outlive the renderer.
  2. Call prepare_scene whenever the scene or highlight selection changes.
  3. Call render_prepared in your redraw loop with your Camera.

Under winit 0.30 the event loop is driven by ApplicationHandler + run_app (there is no EventLoop::run closure, WindowBuilder, or Event::RedrawRequested anymore), and a window created in resumed() has to outlive a borrowed renderer stored beside it. The maintained reference for that pattern is the desktop shell (ui/shell/src/runner.rs), which owns the window as an Arc<Window> and builds the lower-level renderer via Renderer::new_owned for a 'static surface. For a headless SDK integration (no window/event loop), see examples/sdk/basic.rs.

5.4 Editing Engine (core/edit)

  • Provides the edit-mode foundation: EditableScene, EditCommand implementations, ID helpers, and the geometry engine behind the molecular builder.
  • command/ holds the high-level actions, grouped by target (atom_commands.rs, bond_commands.rs, fragment_commands.rs, geometry_commands.rs, hydrogen_commands.rs, electronic_state_commands.rs, residue_commands.rs, residue_state_commands.rs, residue_state_definitions.rs, disulfide_commands.rs, disulfide_annotations.rs, terminal_cap_commands.rs, conformer_commands.rs, perception_commands.rs, wrap_commands.rs, cluster_commands.rs, cell_commands/), with the EditCommand trait itself in command/edit_command.rs.
  • ops.rs executes mutations against editable scenes, ensuring invariants such as bond symmetry and selection history updates.
  • The viewer’s Edit Mode panels (ui/shell/src/edit) invoke these commands via run_edit_command_with_feedback, emitting undo/redo stacks and error toasts.

geometry/ — the builder. The pattern throughout is a pure planner plus a thin command: the planner takes coordinates and returns what should change, so it is testable without a scene, and the command applies the plan and reports it. plan_clean_geometry / CleanGeometryCommand is the reference example.

Module Role
build_template.rs The nine BuildGeometry shapes, their substituent directions, AttachmentSites (non-empty only for the two five-coordinate shapes), and the staggering twist used when growing onto an existing atom
ring.rs carbocycle(size) for MIN_RING..=MAX_RING (3–8): polygon, pucker, cap, then idealize_in_place, so a placed ring and a cleaned one agree by construction
clean.rs plan_clean_geometry — angles, then coordination spheres, then the point-group fit, each gated by CleanGeometryOptions
idealize.rs The Gauss–Seidel distance-constraint solver seeded at current coordinates. ANGLE_STIFFNESS = 0.1 makes a bond about ten times stiffer than an angle, which is why PASSES is 2000
cluster.rs plan_cluster_model — cutting a metal site out as a cluster model for a QM calculation. One rule does both cuts: grow outward from each donor and stop at TRUNCATION_STOP_ATOMS, so a histidine keeps its imidazole plus CB and a backbone carbonyl keeps the peptide unit, with no table of twenty residues. Takes a distance shell as well as the bond list, because a metal–ligand contact is longer than covalent radii reach and a catalytic water would otherwise be dropped
sphere.rs, sphere_assessment.rs, shape_measure.rs Continuous shape measures against reference polyhedra, and the SphereVerdict the Scene panel reports
coordination_template.rs Coordination geometry and Shannon-radius reach per element and oxidation state
embed.rs, graph.rs, stereo.rs 3D coordinates from a flat connection table, and handedness preservation / inverted-stereocentre repair
conformer.rs Deterministic bounded torsion sampling, UFF relaxation/ranking, stereochemistry checks, and heavy-atom aligned-RMSD deduplication
attach.rs, donors.rs, ops.rs, math.rs Ligand attachment, donor suggestion, and shared helpers

smiles.rs sits beside geometry/. It converts Yowl’s parsed graph into an explicit-H SceneGraph or SmilesFragment, assigns molecular charge, and invokes the same 3D embedding path when requested. Unsupported stereochemistry, query syntax, maps, and metals are boundary errors. command/residue_commands.rs consumes the pinned CCD-derived templates in core/edit/data/standard-amino-acids.json; backbone identity and coordinates remain stable while side-chain atoms are replaced. command/residue_rotamers.rs reads the CC BY 4.0 Top8000 derivative under core/edit/data/rotamer/. It selects a smoothed 20° phi/psi bin, or a declared backbone-independent fallback when phi/psi cannot be measured, and supplies the named chi-angle candidates used by residue_preview.rs. The preview keeps the existing exact candidate application and undo transaction. Clash-free rows follow local library probability; clashing rows follow summed squared overlap and then probability. command/side_chain_repair.rs wraps that mutation path for a same-component repair. It requires a positive missing-side-chain finding, refuses alternate locations, ambiguous protonation aliases, active SSBOND endpoints, and any side-chain bond crossing the residue boundary, then ranks complete candidates by clash-free status and minimum-image RMS displacement from existing heavy side-chain atoms. The detached validation reports missing atoms, source atoms replaced, explicit hydrogens removed, formal charge, and clash scores before and after. RepairSideChainCommand retains the preview’s materialized source digest and delegates exact candidate application and undo to the existing mutation transaction. command/terminal_cap_commands.rs builds undoable heavy-atom ACE/NME caps from the shared protein_termini query. Its preview digest uses the materialized EditableScene representation because entering edit mode turns lazy inferred bonds into explicit session topology; comparing against the pre-session graph would reject an unchanged PDB preview as stale. command/residue_state_definitions.rs defines the supported ASP/ASH, GLU/GLH, CYS/CYM, and LYS/LYN hydrogen, charge, and bond-order patterns. The planner in residue_state_commands.rs materializes inferred bonds before recording its source digest and returns a detached scene plus residue and molecular charge changes. SetResidueProtonationCommand stores only the affected residue atoms and incident bonds for exact Apply, Undo, and Redo. Retained heavy-atom IDs and coordinates do not change; generated hydrogens use the shared approximate hydrogen placement code and stripped experimental/computed properties. command/disulfide_commands.rs plans explicit bridge creation and cleavage from two annotated CYS/CYX residues. Creation is bounded to a 1.7–2.5 Å minimum-image SG-SG distance and never moves heavy atoms. Cleavage creates two approximate thiol hydrogens. The command stores residue-local atoms, incident bonds, and the active SSBOND metadata string for exact Apply, Undo, and Redo. disulfide_annotations.rs is the one writer for pdb:ssbond_pairs; residue mutation uses the same helper when it removes a cysteine endpoint. Edited bond properties identify the live connection as disulf, while imported raw pdb:struct_conn data remains unchanged source provenance.

5.5 Force Field (core/forcefield)

A self-contained UFF implementation, split out of core/edit so the geometry planner and the minimiser stay independently testable. It is what Relax Geometry runs.

  • params.rs holds the UFF parameter table; typing.rs assigns atom types from geometry.
  • All five terms are present, each in its own module: bond.rs (stretch), angle.rs (bend, including the periodic form metals need), torsion.rs (dispatching on hybridisation across all six cases), inversion.rs, and vdw.rs.
  • topology.rs builds molecular or explicit-image periodic interaction graphs; system.rs evaluates them; minimise.rs runs the minimisation. Every analytic gradient is checked against a numerical one in the crate’s tests.

Van der Waals has two entry points, and the difference matters. vdw_energy is the bare Lennard-Jones with no cutoff. vdw_energy_switched tapers it to zero between VDW_TAPER_START (10 Å) and VDW_CUTOFF (12 Å) using the quintic S = 1 − 6x⁵ + 15x⁴ − 10x³, which has zero first and second derivative at both ends — a C² energy and a C¹ gradient, which is what a line search needs. A bare truncation steps the potential and a shifted-force form distorts it everywhere; both were rejected for those reasons. Below 10 Å the two functions agree exactly.

The 12 Å radius comes from the table rather than convention: UFF’s deepest pair is Fr–Fr at x1 = 4.9 Å, retaining 2.75% of its well depth at 10 Å and 0.92% at 12 Å, with ordinary organics at 0.37% and 0.12%. A test pins both figures.

The non-bonded pair list is bounded by distance as well as by connectivity. It used to hold every pair more than two bonds apart, which was quadratic and eagerly allocated — 800 MB at ten thousand atoms. A uniform grid now bounds it by VDW_CUTOFF + VDW_SKIN, so the count follows density. The topological exclusion is unchanged and still comes first: a 1-3 pair stays excluded however far its angle opens.

Fixed-cell periodic minimisation uses explicit lattice images in all five terms. Each interaction participant is an atom index plus an integer (a, b, c) image. Directed bond images compose into angles, torsions and inversions; gradients from every occurrence return to the one base-atom coordinate. This represents self-image bonds and several bonded images of one atom pair, which a minimum-image shortcut cannot.

Nonbonded terms enumerate one half-space of image shells to the 12 Å cutoff plus skin. Their 1-2 and 1-3 exclusions are a depth-two walk over (atom, accumulated image) states, so only the bonded image is excluded. A Cartesian grid bounds candidate work by density. Slab axes marked non-periodic are neither folded nor replicated, and singular cells fail explicitly.

System::new remains the molecular API; System::new_periodic is the fallible fixed-cell entry point. BondRecord is unchanged because it cannot distinguish two images of the same atom pair. Cross-face contacts are inferred internally and have single order. Preserving an aromatic or multiple bond through a face would require parser-supplied image-bearing topology. The implementation contract and validation evidence are in notes/periodic-minimisation-plan.md.

Relax entrenches the geometry it is given — it finds the nearest local minimum. Clean (core/edit/src/geometry/clean.rs) moves a structure onto what its connectivity implies instead. Keeping those two distinct is the load-bearing design decision in the builder; see notes/archive/PROJECT_PLAN-edit-builder.md for the reasoning.

5.6 Reciprocal-Space Analysis (core/periodic)

orbitron-periodic converts a canonical BandStructure plus its calculation cell into one ReciprocalScene shared by every presentation surface.

  • orbitron-symmetry::first_brillouin_zone constructs the exact Wigner-Seitz cell of the physical reciprocal lattice, including the factor.
  • ReciprocalScene::from_band folds every parsed sample into that zone while retaining its source index. A mesh remains independent points.
  • Declared paths are split at zone boundaries, so a renderer cannot draw a false chord across opposite faces.
  • projection.rs supplies the common orthographic projection used by the desktop painter and SVG/PNG exporters.

The crate owns geometry and selection state, not widgets. Desktop controls live in ui/shell/src/panels/analysis/bands_dos/brillouin.rs; the TUI summarizes the same scene; Python converts it to plain containers; the WASM custom element uses the same indexed zone and path records.