Structure viewer: InstancedMesh atom rendering + UX improvements

Motivation

The previous renderer created one THREE.Mesh per atom. At 10 000+ atoms this means 10 000 draw calls per frame, 10 000 objects in the raycaster traversal, and O(N) mutation cost for every atom change. Switching to InstancedMesh collapses all atoms of the same type into a single draw call.

Changes

Atom rendering rewrite (StructureViewer, AtomSelector)

  • InstancedMesh layers (ATOM_MESH_CONFIGS): two layers — one for unconstrained atoms, other for constrained atoms. Each layer is one draw call regardless of atom count.
  • atomLookup[i] = { mesh, instanceIdx }: reverse-lookup table so any per-atom operation (colour change, position update, highlight) can find the right mesh and slot in O(1).
  • mesh.userData.globalIndices[instanceIdx] = i: forward lookup so the raycaster result (hit.instanceId) maps back to a global atom index.
  • _buildAtomMeshes / _rebuildAtomsInstances: build/rebuild both instanced meshes and the lookup table. ADD, REMOVE, and CONSTRAINT changes now call _rebuildAtomsInstances instead of patching atoms.children directly.
  • AtomSelector rewritten: raycasting uses intersectObjects(atomMeshes) + globalIndices; dragging tracks draggingMesh/draggingInstanceIdx; selection and highlight operate on indices.
  • changeSpeciesColor, changeAtomsColors, animation render loop, and wrap-atoms handler all ported to atomLookup.

Bond defaults for large structures

  • For structures with ≥ 10 000 atoms, bonds are off by default (the "Show bonds" checkbox is unchecked and no bond geometry is computed at load time).
  • Checking "Show bonds" triggers on-demand calculation via recalculateBonds. Subsequent toggles just flip visibility — bonds are not recalculated again.
  • Small structures keep the existing behaviour: bonds computed at load, checkbox on by default.

Brillouin zone viewer fixes

  • Small BZs (large supercells with tiny reciprocal vectors) are scaled up for display so lattice-vector arrows remain proportional to the cell.
  • Cartesian axes hidden by default.
  • pointerdown on the controls panel no longer propagates to the orbit controls, preventing accidental camera rotation when clicking dropdowns.

Supercell / slab atom limit

Raised from 30 000 to 100 000 atoms before the operation is refused.

Edited by Andrei Sobolev

Merge request reports

Loading