Skip to content
| Marketplace
Sign in
Visual Studio Code>Visualization>Molecular Viewer 3DNew to Visual Studio Code? Get it now.
Molecular Viewer 3D

Molecular Viewer 3D

Atreides-Jimmy

|
3 installs
| (0) | Free
3D molecular structure viewer and editor for computational chemistry files (Gaussian .gjf/.log, ORCA .inp/.out, .xyz, .mol2, .coord, VMD .tcl). Features ball-and-stick rendering, auto bond detection, interactive rotation/zoom, bond length/angle/dihedral editing, atom add/delete/replace, rotate group
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Molecular Viewer 3D

English | 简体中文

A VS Code / Trae extension for visualizing and editing molecular structures in 3D, designed for computational chemists working with Gaussian, ORCA, and other quantum chemistry software — especially on remote servers where GUI tools like GaussView are unavailable.

Features

  • 3D Ball-and-Stick Rendering — Atoms rendered as spheres (scaled by covalent radius) with CPK coloring; bonds rendered as dual-colored cylinders

  • Bond Order Support — Visual distinction for single (1 line), aromatic (1 solid + 1 dashed), double (2 lines), and triple (3 lines) bonds

  • Auto Bond Detection — When files lack explicit connectivity, bonds are derived from the coordinates by a single pass that applies two checks, each covering what the other cannot. The geometric check reads each length against element-pair-specific bond length specifications (C-C, C-N, C-O, etc.) with tolerances and pair-specific distance cutoffs, placing every bond on the order the measured length actually supports (candidate orders are limited to a spec tolerance or the pair's closest fit, so a long non-bonded contact is never promoted), pins terminal elements (H, halogens, noble gases) to single bonds, and falls back to a covalent-radii ratio for pairs with no entry. A valence-conservation check is then applied to any connected component that still holds an atom off its allowed valence: every atom is given a target valence from its element's permitted set (N 3 or 4, O 2/1/3, S 6/3/2/1), unsaturated atoms are paired by a maximum-cardinality matching until each atom reaches its target, and an assignment is accepted only when the formal charges it implies sum to the total charge the file states — so a nitro group comes out as one N=O plus one N–O and an N⁺ instead of a five-valent nitrogen, and an ammonium or a carboxylate is told apart from its neutral form. Geometric candidates are tightened first to the band an atom's degree and its neighbours' spare capacity allow; aromatic rings the second solver re-derived as alternating single/double bonds are restored to order 1.5 when that leaves every atom's valence unchanged; and a structure whose geometry is already self-consistent is left exactly as the geometric pass produced it. Every re-detection runs this one module — loading a file, both sides of a Diff comparison, and the Move Atoms release (which re-derives only the connected components containing the moved atoms, so a move lands on the same answer a fresh load of the moved coordinates would give) — and the webview receives it from the extension host rather than keeping a second copy of it. The default is the geometric pass, unchanged — the valence solver is opt-in, because it re-derives a whole connected component and would visibly re-assign bonds that were never in doubt. What the default does add cannot change a bond: formal charges for every atom, derived from the finished orders, plus a report of the atoms whose valence is not one their element may take and a count of how many components a solver could settle. Whichever mode runs, the result is held to a measured monotonicity property against the detector it replaces — no structure may end up with more atoms off their allowed valence, and every bond whose length fit gets worse must sit in a component the old result already had a valence problem in — backed by a runtime safety valve that rolls back a solver answer which fails to lower the component's total valence gap

  • GJF Connect Section — Reads explicit bond information from coordinate section in GJF files, including bond orders (1.0, 1.5, 2.0, 3.0)

  • Molecular Info Display — Shows the Hill-system molecular formula, atom count, charge, electron count, and spin multiplicity in the top-left corner of the 3D view; for crystal files, an additional Unit Cell composition line shows the full unit-cell formula

  • Two-row toolbar — The tool buttons are laid out over two rows so that the ones at the end are reachable without dragging a scrollbar: the editing modes and tools (View, Bond Length, Bond Angle, Dihedral, Rotate Group, Move Atoms, MM Optimize, Add/Delete/Replace Atom, Add H, Import Structure) on the first row, the selection pair and the structure and view actions plus the trajectory and molecule navigation (Select Atoms, Box Select, Diff, Undo, Save As, Reset View, ◀ n/N ▶, molecule selector) on the second. Each row scrolls horizontally on its own, and only when its own content does not fit — so a narrow panel still reaches every button, and a loaded trajectory never pushes the actions out of sight again

  • Interactive Mouse Control:

    • Left drag → Rotate around molecule center
    • Scroll → Zoom in/out
    • Middle/Right drag → Pan (cursor-locked: the grabbed point stays exactly under the cursor, 1:1 cursor speed)
    • Alt + left drag / right (or middle) drag → instead of only turning or panning the view, write that rotation/translation into the atom coordinates (see below)
    • Hover atom → Show element name + coordinates
    • Arrow keys (↑/↓/←/→) → Rotate molecule (left/right around Y axis, up/down around X axis; ignored when typing in input fields; with Auto Rotate on, holding a key spins the view up and releasing it keeps the speed — see below)
    • Delete key → If atoms are selected (via Select Atoms / Box Select), opens batch delete confirmation; otherwise enters Delete Atom mode
  • Auto Rotate — A small panel at the bottom-right of the view appears while the View mode is active and carries the Auto Rotate toggle. With it on, the view can be thrown from either input, and what it is given is angular momentum, so it keeps turning about a fixed world axis instead of stopping when the input does:

    • A left-drag that rotates the molecule, released: the throw's direction becomes the spin axis and its speed the spin rate (distance over time) — drag farther or flick faster to spin faster. Only the last 120 ms of the drag count, so a drag brought to a standstill before the button comes up does not spin.
    • An arrow key, held: it spins the view up like an accelerator rather than turning it at a fixed rate — the longer the hold, the faster — and releasing the key hands over the speed it reached. The axes are the same ones a drag uses (←/→ on Y, ↑/↓ on X), and two keys together give the diagonal.

    The spin rate is capped and has a floor, so a wild flick cannot blur the view and a near-zero throw reads as a stop. The next left press stops it; a right/middle press pans and deliberately leaves it running. Reset View, leaving Diff mode, leaving View mode and switching the toggle off also end it, and the first arrow key of a hold takes over from any spin already running. View-only: it rotates the camera, never the coordinates, so no edit or playback is affected, and in Diff mode the half you spun or keyed is the half that spins

  • Alt-drag writes the drag into the coordinates — In View mode, holding Alt while you press turns the drag into an edit: left rotates the structure, right/middle translates it, and it is the atoms that move rather than the camera — Save As then writes the geometry you dragged it to, in any format. Orient a structure for a figure, or bring several of them into a common frame, without leaving the viewer. The picture is exactly the one a plain drag would have shown: the rotation is written about the structure's own centre (its centroid, which a rotation about it leaves fixed) and the translation along the same screen direction the pan uses, both expressed in the structure's own frame, so nothing is turned twice and nothing jumps on release. One undo step per drag — an Alt-click that moves nothing leaves the stack alone — and no bond is re-derived, because a rigid transform changes no distance. Reset View afterwards returns the camera to the file's axes: the orientation the drag produced now lives in the coordinates, not in the view. Only the press decides, so releasing Alt mid-drag keeps the drag an edit. Where the coordinates are tied to something else — Diff mode (two structures, two view states) and crystal structures (the cell) — the drag stays view-only and the panel says so; a running vibration or frame auto-play is ended first, and Auto Rotate is not launched from such a drag. It is stated in its own Edit Coordinates card, which sits directly above the Auto Rotate card — both are separate boxes in the panel layout, so they stack instead of overlapping each other or the Diff panel below them

  • Touch Support — Single-finger rotate, pinch-to-zoom

  • Orientation Axes Indicator — A small axes gizmo in the bottom-left corner is shown for every structure: molecular files display the Cartesian X/Y/Z axes (X red, Y green, Z blue) of the initial coordinate frame, tracking every view rotation so you always know which direction the molecule faces; crystal files display the lattice a/b/c axes. Reset View returns the indicator to the initial orientation

  • Remote-SSH Compatible — Works seamlessly when editing files on remote Linux servers via VS Code/Trae Remote-SSH

  • VMD TCL Script Visualization — Opening a VMD visualization script reproduces its display recipe: representations (CPK/VDW/Licorice/Lines/Surf) with their relative sphere scales, bond radii and probe radii; colour modes Beta (per-atom scalar on the R→G→B gradient, with the script's mol scaleminmax range or the data's own), ColorID (the reference renderer's 33-colour palette at measured values) and Name; mol selection expressions resolved against the loaded atoms; molecules from repeated mol new selectable one at a time; and Surf patches extracted as real solvent-accessible surfaces. Visualizations that ship as a bare PDB instead of a script are coloured by their own per-atom scalar automatically. See VMD TCL Script Visualization

  • Performance — Dirty-flag rendering: the scene only re-renders on interaction or structural change (not every frame), so idle GPU usage is eliminated; meshes are properly disposed (geometry, material, texture) on rebuild to prevent GPU memory leaks that previously caused progressive lag within a session; adaptive level-of-detail reduces sphere segment count for large structures (>200 atoms: 20×16, >1000 atoms: 12×10) to maintain interactive framerate; the axes indicator SVG is rebuilt at most once per animation frame (~60 Hz) instead of on every mousemove event; automatic bond detection uses a 3 Å spatial hash grid (O(N·neighbors) instead of O(N²) pair tests — ~18× faster at 2000 atoms, ~130× on sparse systems) with byte-identical results, applied to initial detection and to the post-release bond re-detection in Move Atoms mode, whose re-judgement is further narrowed to the affected region (the moved atoms and their bonded neighbors) instead of the whole molecule; Move Atoms drags update bond meshes incrementally — only bonds touching the moving atoms are rebuilt each frame, and the release-time refresh likewise rebuilds only the affected region's bond meshes (surviving meshes are kept and re-indexed into the new bond list), instead of rebuilding every bond mesh in the structure; Gaussian optimization logs are parsed in a single pass (geometry frames, convergence steps and frequency tables used to be three separate full-file scans), and ORCA .out / MOPAC .out files likewise parse in a single pass (their fallback geometry-block scans were merged into the main traversal)

  • Large Structures — The scene's GPU objects are shared rather than owned per drawn thing: every bond cylinder (a bond is two to eight cylinders — one per bond half, plus a dashed line of six for an aromatic bond) is drawn by a single instanced mesh with the radius and length in the instance matrix and the colour in the instance colour buffer, and an atom's sphere geometry and material come from a pool keyed by radius and by (colour, occupancy, highlight state). A 2175-atom structure therefore costs 2177 three.js objects, 6 geometries and 7 materials where it used to cost 16 081 of each — the object count that made one frame expensive enough to reset the window's shared GPU process. The atom materials are the only part of the scene that still scales with the data, and only under scalar colouring, where every distinct scalar is its own colour (524 materials for a 2175-atom structure carrying a per-atom scalar; the pool is a bounded cache). A bond's transform is read off its two atoms by one routine that the scene build, a Move Atoms drag, a streamed MM chunk and a normal-mode playback all call, so a bond can never disagree with the atoms it spans. The viewer also handles the graphics context itself: a context lost mid-session is reported and the scene rebuilt when it comes back, the context is released when the page goes away, and a renderer that cannot be created explains that the window's GPU process is gone (and that reloading the window is what brings it back) instead of only repeating three.js

Molecular Editing

  • Bond Length Adjustment — Select 2 atoms, view current bond length, choose which atom to fix, choose Translate Group (rigidly move atom + connected subtree, preserving relative positions) or Translate Atom (move only the selected atom), adjust via numeric input or slider with real-time 3D preview
  • Bond Angle Adjustment — Select 3 atoms (2nd is the vertex), view current angle, fix/move either side, Translate Group/Atom option, real-time preview
  • Dihedral Angle Adjustment — Select 4 atoms, view current dihedral, fix/move either side, Translate Group/Atom option, real-time preview
  • Bond Order Editing — Change bond order (none / single / aromatic 1.5 / double / triple) in the Bond Length modal; selecting "None (0)" removes the bond; changes reflected immediately in 3D display
  • Add Atom — Click anchor atom, choose element (70+ elements), set bond length and bond order, direction auto-calculated for polyhedral coordination with existing bonds (maximum angular separation from existing neighbors, naturally producing linear/trigonal/tetrahedral/octahedral geometry); repeated additions to the same anchor fan out instead of overlapping
  • Delete Atom — Click atom and confirm; atoms and bonds are automatically re-indexed; or delete all currently highlighted atoms at once by selecting them first via Select Atoms / Box Select, then clicking Delete
  • Replace Atom — Click the Replace Atom toolbar button, then click one or more atoms in the 3D view to select them (click again to deselect); click the Replace Atom button again to open the element picker (70+ elements), then confirm to replace all selected atoms with the chosen element while preserving their coordinates; works with crystal base atoms too
  • Add Hydrogens (H Completion) — The Add H toolbar button (next to Replace Atom) fills the selected atoms' missing valences with hydrogens. Each selected atom whose bond valence is below its element's empirical valence receives exactly the difference, at the X–H length and the H–X–Y angles the plugin's SMILES → 3D engine already uses — S completes to 2 and P to 3, a C–H bond is 1.09 Å, N–H 1.01, O–H 0.96, S–H 1.34, P–H 1.42, and the angles are the element's theoretical ones (C 109.47° sp3 / 120° sp2 / 180° sp; N 106.5°, O 104.5°, S 98°) — with the centre's hybridization read off the bond orders it already has (triple → sp, double or aromatic → sp2, amide-like N → sp2, else sp3), so a ring carbon's hydrogen lands in the ring plane at 120°, a methyl group comes out tetrahedral and an alkyne's hydrogen linear. Click atoms in the mode (or carry a selection in from Select Atoms / Box Select / Replace Atom) and click the button again to place them: the atoms that were already there never move — every hydrogen is placed around its centre, the whole addition is one Undo step, re-running it adds nothing, and an atom already at or above its empirical valence is reported instead of completed. A hydrogen the structure has no room for (a non-bonded contact that would come out shorter than a chemical bond) is left out and reported rather than allowed to overlap an atom. Not available for crystal structures or in Diff mode
  • Molecular Mechanics Optimization — The MM Optimize toolbar button (immediately right of Move Atoms) opens a panel listing the built-in force field's parameters, a selection control for every settable parameter (the non-bonded / torsion / improper / electrostatics / hydrogen-bond / metal-coordination / polarisation term switches, the convergence force, step limit, time budget, step size and the non-bonded cutoff of 5–12 Å, default 8), three precision presets that fill those controls in one click — Low (quick pre-optimisation: bonds and angles only, every distance- and dihedral-dependent term off, 0.4 kcal/mol/Å, 120 steps, 1.5 s, 0.30 Å steps, 6 Å cutoff), Medium (the module's own defaults — the full geometric field: Lennard-Jones, the light Coulomb term and the hydrogen bond) and High (careful: everything including metal coordination and polarisation, 0.01 kcal/mol/Å, 2000 steps, 20 s, 0.05 Å steps, 10 Å cutoff) — with any hand-edited value turning the choice into "Custom", the atoms a run would move, and a Start Optimization button. Each control opens on the module's own default, the presets carry the module's own values, and every value is validated again host-side, so a choice can never put a run into an unreasonable state. Select atoms by clicking in the mode (toggle), or carry a selection in from Select Atoms / Box Select / Replace Atom / Add H / Rotate Group / Move Atoms — the selection survives the switch both ways and the panel follows it. This is a restrained optimisation, not an isolated one: only the selected atoms move, but every fixed atom is a full participant — its bonds, angles, torsions, impropers and non-bonded contacts all pull on the selection, and only a term whose atoms are all fixed is dropped (it cannot change). Pressing the button relaxes exactly those atoms and every other atom comes back bit-identical, so a fragment can be settled against the rest of a structure, or a whole distorted structure can be relaxed, without any risk to what was not selected. The panel then reports energy before → after (kcal/mol), the number of steps and why it stopped (converged / energy converged / step or time budget / no further gain), the final max and RMS force, the largest displacement, and how many of each term were live; the status bar carries the same summary. A run is a session the host steps in chunks, so the panel watches it work: the structure follows each chunk live (spheres and only the bonds that touch the moved atoms are redrawn), two canvases draw the energy and the max/RMS force against the step as the run goes, and a progress line names the step, the energy, its change and the forces. One Pause / Resume toggle button (the same single-button pattern the vibration panel uses) stops the run where it stands and continues it again — the session is kept, so Resume carries on from exactly that geometry, step size and conjugate direction, and the time spent paused does not count against the wall-clock budget; the label flips on the click itself, so the panel can never be left in a state it cannot leave. Restore initial writes the geometry the run started from back, as one Undo step. The geometry the run itself reaches is one Undo step too, taken in front of the first coordinate that actually changes — so a run that reports its starting geometry unchanged leaves the Undo stack exactly as it found it. Leaving the mode for anything else — another tool, a frame, a molecule, an Undo, an Import, a comparison — interrupts the run, so it can never keep writing coordinates into a structure the user has moved on from, and a late answer from a replaced run is ignored (every message carries the run's id). Closing the panel with its × only hides it: a small MM Optimize button next to the Convergence / Modes / Route buttons reopens it, and it doubles as the run's state while one is working ("running – step N" / "paused"). The whole run is one Undo step, and afterwards the bonds of the moved region are re-judged by the same perception module a fresh load of the moved coordinates would use (the Move Atoms release path), so a relaxation can only ever produce the geometry a reload would agree with. The force field is part of the plugin (src/tools/mmOptimizer.ts, zero dependencies): harmonic bond stretching whose reference lengths are the same table the SMILES → 3D engine and Add H use (r₀ per element pair and bond order, aromatic included), harmonic angle bending towards the centre element's theoretical sp/sp²/sp³ angle (force-free beyond 30° of a compressed angle, so a strained ring is left as drawn, but up to 60° of a widened one, which is a drawing to correct), three-fold staggered torsions on sp³–sp³ bonds and two-fold planar ones where an sp² centre or a double/aromatic bond is involved (no term where hydrogen defines the four-atom set), an out-of-plane restraint at three-coordinate sp² centres, and a Lennard-Jones non-bonded term with σ from the van der Waals radii, 1–4 pairs at half strength, switched off smoothly between 6 and 8 Å, plus a 1-3 clash guard that re-admits a pair as pure repulsion if it comes inside 0.45 of its van der Waals sum. Beyond the bonded and Lennard-Jones terms the field carries the light additions the higher precision levels switch in: a Coulomb term whose partial charges come from the Pauling electronegativity difference (weighted by bond order, neutralised per structure, so no formal charges are needed) with a distance-dependent dielectric εᵣ = r and the same pair list, taper and 1-4 halving; a hydrogen bond that blends a 10-12 well over the H···A Lennard-Jones pair inside ≈1.6–2.8 Å and a D–H···A window (donors and acceptors N/O/F); a metal-coordination term that bends a metal's ligand–metal–ligand angles toward the ideal geometry of its coordination number (linear, trigonal, tetrahedral, square planar for the d⁸ metals, and cis/trans for five or six ligands) and leaves the metal–ligand distances to the bond term; and a damped induced-dipole polarisation (∝ 1/r⁴, calibrated so α = 1.45 ų, q = 0.4 e at 2 Å gives ≈ −0.5 kcal/mol). The per-element tables cover the main-group elements of periods 4 and 5 (Ga Ge Rb Sr In Sn Sb and their group analogues) alongside the first rows, added by one documented group-analogue rule, so no existing value changed and the heavier elements no longer fall through to the table default. The optimiser is a preconditioned conjugate gradient in which every accepted step must lower the energy, so a run is monotone: whatever it returns — converged, out of steps, or out of time — is never worse than what it was given. The run is bounded by 3000 atoms, 500 steps and 5 seconds. Not available for crystal structures (the force field has no image atoms) or in Diff mode (there are two structures to choose from). Verified with finite-difference gradient checks (worst relative error 1.3e-8), a restrained-optimisation proof (a lone mobile hydrogen lands at the table length from a fixed carbon, all three H–C–H angles to frozen hydrogens come out exactly 109.47°, and a terminal carbon feels the torsion of a frozen backbone), a 19-file corpus in which every structure improves, and a stub-driven run of the real client script. The streaming, preset and cutoff work is verified on top of that: the answers of the build before the session refactor were dumped for 16 structures × 8 option sets and every field (coordinates included) is byte-identical after it; a chunk-size sweep (1 / 3 / 7 / 1000 steps per chunk) and a pause/resume in the middle of each run reproduce the single call exactly; a whole streamed run driven through the compiled extension code — mmProgress → mmResult — is byte-identical to the module's single call, with Pause stopping the pump, Resume continuing it and Cancel (or a disposing panel) stopping it for good; and the new client code was driven against a stub DOM (start → live coordinates → pause → resume → result → restore, one undo snapshot at the first write, a stale run id that cannot write anything, the navigation cancel). The cutoff gradients still match central finite differences inside every taper window (5, 6, 8, 10, 12 Å; worst relative error 2.3e-7), the default cutoff reproduces the previous behaviour bit for bit, and the three presets were measured against each other (medium 51 steps to max|F| 0.027 kcal/mol/Å, high 81 steps to 0.0093, low 29 steps to 0.377; medium identical to the no-options answer). A run is steerable while the rest of the viewer keeps working, and the three ways the panel's Pause toggle, its curves and its state could disagree with what the host is actually doing are closed: a chunk already in flight when Pause is clicked is recorded (its steps join the curves, so a paused run's energy and force history is complete) while its coordinates are held back — so the geometry the user paused on is the geometry they keep looking at, until the host's own pause reply brings the snapshot it actually stopped at; the host's pump is bound to the run it was scheduled for, so a chunk chain left over from a run that was cancelled and replaced can no longer wake up and step the newer one; and a pause or resume for a run the host no longer owns is answered (as an ending) instead of ignored, so the button cannot sit in a state nothing will confirm. The curves are drawn into the canvas's own box and redrawn whenever the layout reflows, so a window resize, a panel move or a closed-then-reopened panel leaves them filling the panel instead of clipped at their right edge. Closing the panel with its × leaves the run going with the reopen button showing its state, changing a parameter or clicking new atoms mid-run rebuilds the panel around the running session without disturbing it, starting a run is refused while an Add H request is still in flight, and an Add H answer that lands later ends the run it would otherwise be appending atoms underneath. Nothing else that writes the structure can fight a run either: starting a run stops a frame auto-play first, and a normal-mode playback ends the run before it plays (the mirror of a run ending a playback when it starts) — both before the run captures the geometry Restore initial will put back, so the two can never own the coordinates at once. While a run is live the panel names both atom sets — the run's own, which its buttons act on, and the view's selection, which is the next run's — and its chunk is a fixed amount of work rather than a fixed pass count, so a Pause lands promptly on a large selection too.
  • Import Structure — Click the Import Structure toolbar button (next to Add/Delete/Replace Atom); a dialog first asks for both the number of copies (typed into its input box, pre-filled with 1) and the source — From File or From SMILES — so the count is settled before the structure. From File loads a second structure from any supported file (XYZ, GJF, MOL2, PDB, log/out trajectories, crystal formats, …) into the current view. Multi-frame files (optimization logs) open a frame picker; crystal files (CIF/VASP/Cube/VESTA) contribute their unit-cell atoms as a molecule. From SMILES opens an input box that validates the string as you type — showing the parser's own error message (with the offending position) while the input is not a valid SMILES — and builds the 3D structure when you press Enter: a locally generated conformer with explicit hydrogens, correct bond orders, aromatic ring perception, cis/trans double bonds and tetrahedral stereochemistry (@/@@), produced by the bundled zero-dependency SMILES → 3D engine (src/tools/smilesTo3d.ts, a faithful port of the reference test/smiles_to_3d.py), so no Python and no external cheminformatics toolkit is required. Both sources then behave identically: the imported structure is placed beside the existing one with a bounding-sphere separation test (both structures padded by 2.5 Å + a 2 Å gap), so it never overlaps; importing into an empty view centers the structure at the origin. The import can be repeated any number of times with the same or different sources — each copy is stacked further along +X at one uniform stride, and a multi-copy import is laid out and placed in a single pass, so the copy count does not multiply the placement work. Bonds merge smartly: if neither side has explicit bonds, connectivity is re-detected for the combined structure; if either side has authored bonds (MOL2/PDB/GJF connect, or any SMILES import), existing bonds are preserved and only the imported part's bonds are added (aromatic bonds carry order 1.5, so they render as 1 solid + 1 dashed line). Each import is one undo step, the camera zooms out to fit, and saving exports the combined structure
  • Select Atoms — Click the Select Atoms toolbar button to show a floating panel (bottom-left corner) where you can type atom indices (1-based), ranges (e.g. 3-10), or element symbols (e.g. C H) to highlight specific atoms in yellow; press Enter or click Select to apply, Clear to reset; you can also directly click atoms in the 3D view to select them; clicking a highlighted atom again deselects it (toggle); selections accumulate while in Select Atoms mode; the panel is a truly floating overlay that does not affect the molecular view size; the panel toggles with the toolbar button and hides automatically when switching to another mode; selections are preserved when switching between Select Atoms and Box Select
  • Box Select — Independent toolbar button; in this mode, hold the left mouse button and drag a rectangle, then release to select all atoms inside the box (atoms are projected to screen coordinates and tested against the rectangle); selections accumulate with the same yellow highlighting as Select Atoms, and are preserved when switching between Box Select and Select Atoms; switching to any other mode clears the selection
  • Undo — Toolbar button reverts the most recent edit/delete operation; snapshots are captured automatically when an edit modal opens (including Add Atom) and before delete/remove-disorder/batch-delete execute; the stack is capped at 50 entries and resets on file reload
  • Save As — Export modified structure in 12 formats: XYZ, Gaussian GJF (preserving original file structure), CIF (fractional coordinates), VASP POSCAR (Direct fractional coordinates), Gaussian Cube (with volumetric grid), VESTA (P1 symmetry, fractional coordinates), Turbomole Coord (Å→Bohr conversion), ORCA Input, MOL2 (with bond orders), MDL Mol, PDB (with CONECT records), or MOPAC Input; GJF output preserves original Link 0, route, title card (written below the provenance line), charge/mult, and post-connect content; GJF atom coordinates use GaussView-style 8-decimal aligned format; connect section includes all atom lines; CIF/VASP/Cube/VESTA formats available only when crystal data is present
  • The saved title line records the structure's history — Every format that owns a title or comment line (XYZ comment, GJF title card, MOL2 molecule name, MDL title line, PDB TITLE record, MOPAC title, ORCA comment, POSCAR/CUBE/VESTA headers) is written with a line of provenance, e.g. MV: from opt.log, frame 12 of 40, Step 12; 2 atoms deleted, translated, displaced along mode 7 (38.2 cm-1) +0.45 A: the file it came from, the frame of an optimisation trajectory (or the molecule of a VMD script), the edits made here — atoms added/deleted/replaced, hydrogens added, translated, rotated, bond length/angle/dihedral adjusted, MM-optimized, disorder removed, files merged in, supercell bounds — and any manual normal-mode displacement with its mode number, frequency and amplitude. The record is written as the edits happen and rides in the Undo snapshot, so undoing an edit takes its clause off the title with the geometry; a GJF keeps its own title card under the provenance line, and saving a file the viewer produced never stacks provenance on provenance. Formats with no title line (Turbomole $coord, CIF) are written exactly as before. The file's own title is appended after a | only when it describes the structure on screen — a trajectory's title belongs to the frame the file opens on, so saving frame 79 of a log does not end with frame 1's comment. The wording is short and ASCII, and the line is capped at 190 characters
  • Continuous Editing — After completing an edit, the viewer stays in the current editing mode for repeated adjustments
  • Cancel/Undo — Cancel button restores original coordinates before confirming edits
  • Rotate Group Around Axis — A "Rotate Group" toolbar mode (grouped with View / Bond Length / Bond Angle / Dihedral) lets you select a group of atoms (by clicking in the 3D view or typing atom indices/element symbols, including the ElementN shorthand like H581) and define a rotation axis from 2+ axis atoms, then rotate the group 0–360° around that axis. The angle can be adjusted by dragging the smooth slider or by typing a value in the numeric input box and pressing Enter; both stay in sync. The axis is visualized as an orange line through the molecule. Axis atoms are validated chemically: any bonded pair among them must be a single bond (double/triple bonds are rejected, as they cannot rotate without breaking). The first and last axis atoms define the direction; intermediate atoms are included for validation only. Works for multi-atom collinear axes (e.g. C32 C33 C43 C53) or a simple two-atom bond axis (e.g. C33 C43). The axis atoms stay fixed while the rest of the selected group rotates around the line. Each angle adjustment is one undo step (Undo reverts a single adjustment and updates the slider display), while the panel's Reset button reverts the whole rotation session at once
  • Move Atoms — A "Move Atoms" toolbar mode (next to Rotate Group) for translating and rotating a selected group of atoms. Select atoms by clicking in the mode (toggle), by typing in the Select Atoms panel, or by carrying over a selection from Select Atoms / Box Select / Replace Atom / Add H / Rotate Group. While in the mode, plain controls act on the whole view and Ctrl-modified controls act on the selected fragment: left-drag / arrow keys rotate the view; right-drag pans the view (cursor-locked); Ctrl+left-drag / Ctrl+arrow keys rotate the fragment around its own center, in the same drag direction as view rotation regardless of orientation; Ctrl+right-drag translates the fragment — the movement plane passes through the atom under the cursor, so that atom stays exactly under the cursor while dragging (when starting from empty space, the fragment-center plane is used and the fragment follows the cursor at 1:1 speed). Release Ctrl, the mouse button, or all arrow keys to finish. While dragging, existing bonds stretch with the atoms and only the bond meshes touching the moving atoms are rebuilt (synchronously every frame, so bonds never lag behind); connectivity and bond orders are re-detected once when the session ends (on release), re-judging only the bonds that touch the moved atoms plus their neighbors' bonds — the cost scales with the moved region rather than the molecule size, with results identical to a full re-detection (a safety check falls back to the full detector for degenerate pre-existing valence violations); the release refresh also rebuilds only the affected region's bond meshes instead of the whole scene (surviving meshes keep their GPU resources and are re-indexed into the new bond list, and a full rebuild runs only when the safety fallback trips). Files with explicit bond blocks such as MOL2/PDB (and GJF files with a connect section) keep their authored bonds and orders — only bonds whose endpoints are pulled beyond the bonding cutoff are dropped on release (deletion only: no re-ordering, and no new bonds are added when a fragment approaches). Each drag or key-hold is one undo step. Not available for crystal structures

Optimization Trajectory Navigation (LOG files)

  • Frame Stepping — ◀ Prev / Next ▶ buttons to step through optimization frames
  • Jump to Frame — Direct input field to jump to a specific frame number
  • Auto Play — Plays the trajectory through all frames at 350 ms per step; playback stops on the last structure (the converged geometry) instead of wrapping back to the first one, and pressing Play there runs it again from the start
  • Route Keywords Panel — Gaussian logs show a third collapsible panel button (⚙️ Route) alongside Convergence and Modes, displaying the parse result of the log's route card(s): for every --Link1-- job section, the raw keywords line plus the parsed keyword breakdown (print level, method/basis, each keyword with its option list, an opt badge on sections that request an optimization). Tokenization is paren- and quote-aware (scrf=(SMD, Solvent=Acetone) keeps its option group, external="..." quoted values stay intact, iop(5/17=17) parses as keyword + option), wrapped continuation lines are joined (... opt / =(calcall) freq folds the options into opt), and full-width characters are normalized. The same parse drives the Convergence panel visibility, so the two always agree
  • Convergence Panel — Gaussian and xtb structure optimization logs display a collapsible panel (📈 Convergence) showing energy, force (max + RMS), and displacement (max + RMS) curves versus optimization step, mirroring GaussView's convergence plot; includes threshold lines (dashed amber) for Gaussian logs — the thresholds are Gaussian's own convergence criteria (force 0.000450/0.000300, displacement 0.001800/0.001200), so logs from other programs (e.g. xtb) draw the curves without a borrowed threshold scale — plus a vertical resize handle to adjust panel height, and a close/reopen toggle. The panel appears only when the log's Gaussian route card actually requests an optimization — single-point jobs with the force keyword (or freq jobs) print the same convergence table without optimizing, so the parser checks every #... route section for the opt keyword (opt, opt=..., full spelling optimization, freq=calcall; case-insensitive whole-token match) and shows no Convergence button when no route has it. Force and displacement charts use a logarithmic Y axis — axis ticks show the log₁₀ values with a rotated log₁₀ axis label — so the convergence-threshold lines stay readable even when early steps dwarf the final values (energy keeps a linear axis since it may be negative). Energies are read from SCF Done lines, or from the optimizer's Energy= ... NIter= line in opt=external runs (e.g. Gaussian + xTB/XO combined jobs, which print no SCF Done). For xtb trajectories, the gradient norm (gnorm) from each step's comment line is plotted as the RMS Force curve. The Energy axis prints one shared integer base in the chart title and only the changing fraction on the ticks (e.g. -6912 + with ticks .98 1.18 … 1.81); the number of decimals adapts to the data so the five gridlines are always distinct and monotonic, even for a run whose span crosses an integer boundary or shrinks to a few milli-Hartree. Hovering a data point shows a tooltip with the step index, the point's value and (on the Force/Displacement charts) that step's energy, each printed with enough decimals to separate neighbouring steps
  • Normal Mode Vibration — Gaussian logs with a frequency calculation (freq / CalcAll) display a collapsible Normal Modes panel (🎵 Modes) listing all harmonic frequencies (cm⁻¹) with symmetry labels; clicking a frequency plays the vibration animation (60 FPS via requestAnimationFrame, amplitude normalized to 0.35 Å, 3-second cycle); imaginary frequencies (transition states) marked with *; the animation ends whenever something else takes over the structure — a frame switch, a molecule switch, Undo, Import, Diff, an Add H answer landing, an edit modal opening, or a Molecular Mechanics run starting — and starting one ends a frame auto-play rather than being stopped by its next tick (exactly one thing writes the coordinates at a time). A mode's row now carries two separate selections: the circle at the end of the row picks that mode for the displacement slider, while the row itself (or its ▶) plays the vibration — playing never re-aims the slider, and picking never starts a playback. With a mode picked, Manual Displacement writes it into the coordinates instead of animating it: drag the slider — a proportion of that mode from −1.00 to +1.00, where 1.00 moves that mode's most-moving atom by 1 Å and every other atom by its own share (weights and phases kept exactly as calculated), with the distance it comes to printed beside the fraction — and the structure is set to equilibrium + Σ scaleₖ × modeₖ on every move. A mode is added to the distortion, not swapped in: the block lists every component (#2 +0.50 · [#1](https://github.com/Atreides-Jimmy/Molecular-Viewer-on-VScode/issues/1) +0.30), every contributing row is marked, dragging a component back to 0 takes that mode out, Reset clears all of them, and the largest displacement of the whole combination is shown next to the list — it is not the sum of the parts, because modes can partially cancel. Every write is rebuilt from the equilibrium snapshot, never accumulated, so dragging back and forth cannot drift and one slider value always means one geometry; merely picking a mode never rewrites anything. The session survives everything that does not replace or rewrite the structure — rotating the view, measuring, closing and reopening the panel, saving — and Save As writes the displaced geometry in any format (the dialog says which mode and how far). Playing any mode afterwards, that one included, swings from the undisplaced equilibrium and puts the displaced geometry back when it stops, so the animation always shows the mode the calculation produced and costs nothing of the adjustment; Reset returns exactly to the equilibrium and takes the session's undo step with it. Every coordinate edit closes the session first and keeps the geometry it produced (the edit starts from the displaced structure), while a frame switch, a molecule switch or an Undo drops it; a live Molecular Mechanics run refuses the slider (it owns those coordinates) and a Move Atoms session is committed before the slider takes over

Structure Diff

  • Diff Button — Compare the current structure against another molecular file (any supported format, no need for matching formats)
  • Frame Selection — If the comparison file is an optimization LOG/OUT, a QuickPick lets you choose which frame to compare
  • Skeleton Check — Graph isomorphism via recursive backtracking atom matching (element + degree + neighbor signature with most-constrained-variable heuristic); uses the plugin's own bond detection algorithm (not the file's original bond orders) to ensure consistent skeleton comparison even when files specify different bond orders for the same connectivity; matching considers connectivity only (bonded or not), not bond order — a single bond in one molecule and a double bond in the other at the same position does not prevent skeleton matching
  • Side-by-Side View — Left viewport shows the original molecule, right shows the comparison; each side has independent rotation, pan, and zoom controls. Left-drag rotates, scroll zooms and middle/right-drag pans the half you grabbed — panning is cursor-locked (the grabbed point stays exactly under the cursor) and is scoped to that viewport, so dragging the right structure never moves the left one and vice versa
  • Correct Aspect Ratio — Each viewport uses its own camera aspect ratio matching the half-width, preventing horizontal distortion
  • Conformation Diff — When skeletons match, highlights bond length, bond angle, and dihedral differences in orange on both sides; full list of all differences displayed (no truncation); each difference shows the percentage change relative to the average value
  • Grouped Coordinate Statistics — When the skeletons match, a collapsible Internal Coordinate Statistics block sits above the difference list and summarises the whole comparison: for bond lengths (Å), bond angles (°) and dihedrals (°) it gives n, rms, maxd (max |Δ|), mean and std for every element-composition group (e.g. C-C, C-C-H, C-C-C-H) plus a combined All row. The statistics cover every compared coordinate, not just the ones above the threshold slider, so they stay put while you drag the slider (the slider only changes what is highlighted and itemised). Values are signed differences (left − right), a torsion's difference folded into [−180, 180] so a chain and its reverse cannot disagree; rms = √mean(Δ²), maxd = max|Δ|, mean = mean(Δ), std = population standard deviation. Group keys are canonical, so one coordinate always lands in the same group whatever the atom numbering is. Click the block header to collapse or expand it
  • Adjustable Threshold — A percentage slider (0–20%) in the diff results panel lets you interactively adjust the sensitivity for what counts as a "difference"; all three types use the same relative difference formula (Δ/avg × 100%); for dihedrals near 0° where the average is very small, a fallback ensures robustness; the 3D highlights and difference list update in real-time as you drag the slider
  • Diff Info Panel — Floating panel listing all differences sorted by magnitude, with atom labels and values from both structures; can be closed and reopened via "Show Results" button; diff results are always accessible and not overwritten by measurement info
  • Auto-Mirror Selection — When selecting atoms for bond length/angle/dihedral measurement on one side, the corresponding atoms are automatically selected on the other side via the atom mapping, and both values plus the Δ difference are displayed simultaneously

Crystal Structure Viewing

  • Unit Cell Display — When opening CIF, VASP, Cube, or VESTA files, the crystal unit cell is rendered with a wireframe outline showing the lattice boundaries
  • Supercell Boundary Controls — 6 input boxes (a/b/c min/max) let you define a custom region of the crystal to display; supports fractional values (step 0.1) for partial cell selection; the view is a cutout of the crystal, not a deformation of the lattice; non-integer boundaries (e.g. -0.4 to 0.4) do not generate mirror images — atoms outside the range are simply not shown; finite molecules (not extending periodically) straddling the boundary are shown completely, extending beyond the boundary to avoid broken bonds; infinite periodic chains are truncated at the boundary via split bonds
  • Local Crystal Modifications — Atom edits (bond length, angle, dihedral) in crystal structures modify only the specific atom being edited, not all periodic images of the same base atom; each periodic image is independently editable
  • Minimum Image Convention Bonds — Crystal bonds are detected using the minimum image convention (MIC): interatomic distances are computed at their shortest periodic distance, and bonds crossing cell boundaries are rendered as short split bonds extending outside the view (not as long bonds spanning across the view)
  • Rotating Axes Indicator — For crystal structures the bottom-left axes gizmo shows the lattice a/b/c axes, rotating synchronously with the main 3D view (see the general Orientation Axes Indicator feature above, which covers molecular structures)
  • Fractional Occupancy Rendering — Atoms with partial occupancy (disordered crystal sites) are rendered with partial coloration proportional to their occupancy value
  • Remove Disorder — One-click button to clean up disordered sites: occupancy < 0.5 removed, > 0.5 set to 1, = 0.5 kept
  • Crystal Save — Export modified crystal structures as CIF (fractional coordinates, minimal format), VASP POSCAR (Direct fractional coordinates grouped by element), Gaussian Cube (with minimal volumetric grid), or VESTA (P1 symmetry, fractional coordinates)

VMD TCL Script Visualization

Opening a .tcl script renders the structure it loads the way the script asks for it, instead of applying the viewer's own defaults:

  • The script is a display recipe — Every mol new it performs becomes a molecule (with a ◀ n/N ▶ selector in the toolbar when there is more than one, as in the force-error series scripts that load one PDB per optimisation round), and each representation is reproduced: style and arguments (mol representation CPK 0.97 0.10, Surf 1.0 1.0, VDW, Licorice, Lines), colour mode (mol color Beta / ColorID n / Name / Element), selection, material and any mol scaleminmax colour-scale range. mol modstyle / modcolor / modselect / modmaterial modify an existing representation and mol delrep removes one — including the default representation mol new creates, so representation indices address what the script's author meant.
  • Selections are resolved against the loaded atoms — index lists and to ranges (0-based; out-of-range indices are dropped), element / name / type symbol lists, not negation, and all / none. A selection that needs residue metadata the viewer does not keep (e.g. resname BIB) is widened to the whole molecule and reported on the status bar and in the info panel, never applied silently.
  • Sizes stay ball-and-stick, with the script's relative scale — A script's representation arguments are relative to the reference renderer's own defaults, where CPK 1.0 means van der Waals spheres (a space-filling model). Applying them as absolute radii would turn every structure into one solid blob and hide the bonds and the segmentation, so the viewer applies the script's ratios to its own geometry: sphere radius = the viewer's own radius × the script's sphere scale (an ordinary script comes out the size of an ordinary structure, CPK 0.7 comes out smaller, CPK 0.1 tiny), and bond radius is rescaled the same way against the reference default of 0.3 (CPK … 0.3 is the usual stick thickness, 0.1 a thinner one, Lines a thin line). Anything physical is not scaled down: a Surf probe radius is an Å value, so the surface sits that far outside the van der Waals surface — which is what makes show_eggs.tcl read as coloured envelopes around the atoms. Atoms and bonds that no representation covers are not drawn at all, so a partial selection shows a partial view.
  • Colour modes — Beta paints the per-atom scalar on the reference renderer's RGB ramp as it is actually rendered: red → green → blue with the midpoint at 0.5, but with the two passive channels on a 15/255 floor and the active channel ramping at twice the nominal rate, so the low end is #FF0F0F, the midpoint #0FFF0F and the high end #0F0FFF rather than the pure primaries its scale nominally names. The range comes from the script's mol scaleminmax when it writes one (a written range is treated as an unconditional statement that the column is a scalar channel, so a constant column still gets painted — force_error_delta.3.pdb is all zeros on a −10…+10 scale and renders on the middle of the ramp) and from the representation's actual data range otherwise (a script's hardcoded 0 – 100 scale really does squeeze 0.04–3.92 force errors into the red end — that is what the script does, and the info panel shows the range in use). ColorID uses the reference renderer's 33-entry palette at its measured values, including script overrides from color change rgb. Name / Element uses the reference renderer's element colours — carbon is the soft cyan #40BFBF, not grey.
  • Surf representations are real surfaces — A mol representation Surf <probe> <isovalue> patch becomes the solvent-accessible isosurface of exactly the atoms it selects, extracted by marching tetrahedra at a 0.45 Å grid. Patches are drawn translucent: a script like show_eggs.tcl stacks fourteen of them, and opaque ones would hide everything but the outermost. They ride inside the molecule group, so they rotate and pan with the structure exactly as the atoms do. A fourteen-patch, 72-atom scene builds ~164 000 triangles in ~50 ms.
  • An egg list — When the structure sits next to the toolchain's egg metadata (an eggFile* naming each egg and the unit numbers it wraps — U12F1 : 1,10-15 — plus a unitfile with every unit's atoms), an Eggs button appears and a panel lists every egg the script draws: each row carries the egg's colour as a left accent bar, followed by its name and the units it contains (units 1, 10–15). All eggs are shown initially; unchecking a row hides exactly that egg's surface patch, checking brings it back, and a Hide all / Show all button toggles every egg in one click (completing a partial selection rather than resetting it). The choices survive scene rebuilds (edits, undo) and are reset when the patch list changes (switching molecules or frames). Metadata files are optional — without them the patches render unlabelled. When the directory holds several eggFile* files (leftovers from other settings or rounds), usually only one describes the structure: the viewer scores every candidate against the script's surface patches and asks which to use, each entry showing how many patches it matches (14/14 patches match vs 0/14 patches match), so the right file is unmistakable; cancelling, or picking a file that matches nothing, simply leaves the patches unlabelled. The question is asked once per (directory, structure) pair, so a multi-molecule script does not repeat it.
  • Bare PDB visualizations are coloured by their own scalar — Not every picture ships as a script: A4 and the per-round files of A5/A6 are PDB files whose 61-66 column is the visualization (a per-atom force error, a round-to-round difference, a unit index). A file is recognised as such when it carries nothing but coordinate records (no deposited-structure header) and its column is non-constant, and it then opens already painted on the same gradient over its own range, with the range on the status bar. A constant column (the exports written with 0.00) colours nothing, and a deposited PDB with a header record is left in its element colours. The Color by Beta toolbar button appears whenever such data is present, starts active for the automatic case and toggles it off again.
  • The viewer keeps its own background — A script's color Display Background white is a setting of the reference renderer and is deliberately not applied here: a white canvas would clash with the editor theme and wash out white atoms (which is what Name colouring gives hydrogen). The directive is still parsed and shown in the scene model; color scale method and color change rgb overrides are applied.

A script also participates in Structure Diff: the comparison side is the molecule the script draws, coloured the way the script colours it.

All of it lives in one module, src/parsers/vmdVisualization.ts — the reference renderer's palettes and radii, the resolution of a parsed script into drawing properties, the script parser itself and the recognition of a bare scalar file — so the visualization-file concern has a single home (the parser index re-exports its API).

Supported File Formats

Format Extension Notes
Gaussian Input .gjf, .gjf03, .gjf09, .gjf16, .com Reads Link 0, route, title, charge/mult, coordinates, connect section; supports fixed atom notation (C -1 x y z or C x y z -1)
XYZ .xyz Standard XYZ format with atom count header
MOL2 .mol2 Tripos MOL2 format; reads @<TRIPOS>ATOM and @<TRIPOS>BOND sections with bond order support (aromatic ar → 1.5)
Gaussian LOG .log Reads Standard orientation: / Input orientation: blocks; skips lines where atomic numbers are written as element symbols (e.g. from ONIOM external program calls); supports multi-frame optimization trajectory; extracts SCF energy and convergence criteria (force/displacement) for the convergence panel (shown only when a route-card section requests an optimization — force/freq single-point routes print the same tables but show no panel); parses Harmonic frequencies block for normal mode vibration playback. xtb trajectories (extended multi-frame XYZ with xtb: comment marker) are auto-detected and parsed as optimization trajectories with energy + gradient norm convergence
ORCA Input .inp Reads * xyz CHARGE MULT ... * blocks and %coords blocks; supports xyz and xyzfile coordinate formats; parses units bohr/angs for coordinate conversion
ORCA Output .out Reads CARTESIAN COORDINATES (ANGSTROEM) blocks; supports multi-frame optimization trajectory; extracts charge and multiplicity
Turbomole Coord .coord Reads $coord section (Bohr → Å conversion), $chrg and $spin/$mult for charge and multiplicity; supports both $chrg 1 and $chrg=1 syntax
PDB .pdb, .ent Reads ATOM/HETATM records with fixed-column parsing; element from columns 77-78 or atom name; occupancy from columns 55-60 and the temperature-factor column (61-66) as a per-atom scalar, which is painted automatically when the file is a bare coordinate file with a non-constant column; CONECT records for explicit bonds (up to 8 connections per line); handles duplicate serials; ATOMIC_NUMBER_MAP extended to Cf (98)
MOPAC .mop, .mopac, .dat Reads MOPAC input format with ELEM x 1 y 1 z 1 internal coordinates; supports atomic numbers or element symbols; auto-detects Å/Bohr units; extracts CHARGE and MS keywords; falls back to CARTESIAN COORDINATES output blocks
VMD TCL .tcl VMD visualization script, read as a display recipe rather than as a data file: every mol new (relative/absolute/quoted/braced paths, any supported structure format) becomes a selectable molecule, and each mol representation / mol color / mol selection / mol material / mol addrep becomes a representation — styles CPK, VDW, Licorice, Lines and Surf with their numeric arguments (sphere scale, bond radius, probe radius — applied as ratios to the viewer's own ball-and-stick geometry), colour modes Beta, ColorID and Name/Element, mol scaleminmax ranges, mol modstyle/modcolor/modselect/modmaterial, color scale method and color change rgb; a script's color Display Background is parsed but not applied (the viewer keeps its own background). Sidecar metadata (eggFile* + unitfile next to the structure) adds an egg list for toggling the surface patches
CIF .cif Crystallographic Information File; reads cell lengths/angles, space group symmetry operators, and fractional/Cartesian atom sites; applies symmetry operations to build the full unit cell; supports fractional occupancy with partial coloration
VASP POSCAR .vasp, POSCAR, CONTCAR VASP structure file; handles scale factor, lattice vectors, element types/counts, selective dynamics, and both Direct (fractional) and Cartesian coordinates; robust element-type detection (no false rejection of Cs/Cd/Ca/Cl etc.)
Gaussian Cube .cube Gaussian volumetric file; reads voxel vectors and atomic positions; auto-detects Bohr/Angstrom units; robustly handles corrupted voxel vectors by inferring an orthogonal lattice from atomic coordinate ranges
VESTA .vesta VESTA structure file; reads CELLP (cell parameters), STRUC (fractional coordinates + occupancy), GROUP (space group), and SYMOP (symmetry operations) sections; applies symmetry operations to expand the full unit cell; supports fractional occupancy for disordered sites

Installation

From VSIX (Recommended)

  1. Download the latest .vsix file from Releases
  2. In VS Code / Trae, press Ctrl+Shift+P
  3. Type Extensions: Install from VSIX...
  4. Select the downloaded .vsix file
  5. For Remote-SSH: Make sure to install the extension on the remote server (choose "Install on Remote" when prompted)

From Source

git clone https://github.com/Atreides-Jimmy/Molecular-Viewer-on-VScode.git
cd Molecular-Viewer-on-VScode
npm install
npm run compile
npx vsce package --no-dependencies
# Then install the generated .vsix file

Usage

Opening Molecular Files

  1. Right-click a supported file in the Explorer → Molecular Viewer: Open 3D Viewer
  2. Command Palette (Ctrl+Shift+P) → Molecular Viewer: Open 3D Viewer
  3. Custom Editor — Double-click a supported file and select "Molecular 3D Viewer"

Importing a Structure (File or SMILES)

  1. Click Import Structure in the toolbar (works in View mode; not available in Diff mode or for crystal structures)
  2. One dialog asks for both things: type the number of copies into its input box (pre-filled with 1; any whole number from 1 to 50 — a count that is not one re-opens the dialog with your input kept and the reason in its title), then pick where the structure comes from. The two entries below the box stay visible while you type:
    • From File — pick any supported file. Multi-frame optimization logs open a frame picker; crystal files contribute their unit-cell atoms as a molecule
    • From SMILES — type a SMILES string (e.g. CCO, c1ccccc1, CC(=O)Oc1ccccc1C(=O)O, OC[C@H]1OC(O)[C@H](https://github.com/Atreides-Jimmy/Molecular-Viewer-on-VScode/blob/HEAD/O)[C@@H](https://github.com/Atreides-Jimmy/Molecular-Viewer-on-VScode/blob/HEAD/O)[C@@H]1O). The input box checks the string on every keystroke and keeps showing the parser's error message until it is valid; press Enter to generate the 3D structure
  3. A structure large enough that the requested copies would add more than 20 000 atoms is trimmed to fit, with a warning naming the new count; cancelling any prompt (Esc) cancels the whole import
  4. Every copy is added beside the existing structure without overlapping it (bounding-sphere separation) and copies are spaced at one uniform stride, so they stack along +X and never overlap each other; the whole import is a single Undo step and Save As exports everything together

SMILES coverage and limits — the generator reads the OpenSMILES organic subset plus the common extensions: branches, %nn ring closures, aromaticity, explicit bond symbols, dot-disconnected fragments, isotopes, charges, and @/@@ tetrahedral configuration. Planar aromatic systems are emitted flat: ring substituents (hydrogens included) lie in the ring plane and fused rings — naphthalene, phenanthrene, the purine core of caffeine — are coplanar with each other; an aromatic ring fused to a saturated ring (indane, tetralin) likewise gets both of its benzylic bonds placed in the aromatic plane, as closely as the rigid saturated ring allows. Tetrahedral chirality is honoured; a double bond written without / or \ defaults to trans; the conformation comes from local geometric rules rather than a conformer search, so a long flexible chain may fold tightly; isotopes are parsed but do not influence geometry; organometallic geometry is not special-cased.

Set as Default Viewer

Add to your settings.json:

{
  "workbench.editorAssociations": {
    "*.gjf": "molecularViewer.editor",
    "*.gjf03": "molecularViewer.editor",
    "*.gjf09": "molecularViewer.editor",
    "*.gjf16": "molecularViewer.editor",
    "*.com": "molecularViewer.editor",
    "*.xyz": "molecularViewer.editor",
    "*.mol2": "molecularViewer.editor",
    "*.log": "molecularViewer.editor",
    "*.out": "molecularViewer.editor",
    "*.coord": "molecularViewer.editor",
    "*.inp": "molecularViewer.editor",
    "*.pdb": "molecularViewer.editor",
    "*.ent": "molecularViewer.editor",
    "*.mop": "molecularViewer.editor",
    "*.mopac": "molecularViewer.editor",
    "*.dat": "molecularViewer.editor",
    "*.tcl": "molecularViewer.editor",
    "*.cif": "molecularViewer.editor",
    "*.vasp": "molecularViewer.editor",
    "*.{POSCAR,CONTCAR,poscar,contcar}": "molecularViewer.editor",
    "*.cube": "molecularViewer.editor",
    "*.vesta": "molecularViewer.editor"
  }
}

The list mirrors the extensions the viewer registers; .dat is MOPAC's alternate input/output extension. Drop any line you do not want to divert from your normal editor.

Controls

Action Effect
Left mouse drag Rotate molecule around its center
Mouse scroll Zoom in / out
Middle / Right mouse drag Pan view (cursor-locked; in Diff mode pans the structure on the grabbed half only)
Hover over atom Show element + coordinates tooltip
Arrow keys Rotate molecule (←/→ around Y, ↑/↓ around X); with Auto Rotate on, a held key spins the view up instead — longer hold, faster spin
◀ ▶ (molecule selector) Switch between the molecules a VMD TCL script creates (mol new), shown only when a script defines more than one
Color by Beta Toggle scalar colouring for structures whose PDB columns 61-66 carry a scalar — each atom's sphere and the bond halves that meet it take that atom's scalar colour, so a force-error picture reads as one gradient rather than gradient spheres between element-coloured bonds; starts active when such a file was coloured automatically at load, and is hidden when a script is driving the view
Auto Rotate button In the panel that appears in View mode (bottom-right): toggle flick-to-spin. With it on, a left-drag that rotates the molecule keeps turning after release, at the direction and speed it was released with (farther/faster drag → faster spin), and a held arrow key spins the view up — the longer the hold, the faster — handing over the reached speed on release; the next left press stops it and a right/middle press pans while leaving it running
Reset View button Return to default view

Editing Workflow

  1. Click a toolbar button to enter an editing mode (e.g., Bond Length)
  2. Click atoms in the 3D view to select them (selected atoms glow yellow)
  3. A modal dialog appears showing the current value
  4. Choose which atoms to fix vs. move using the dropdown
  5. Adjust the value using the numeric input or slider — the 3D view updates in real-time
  6. Click OK to confirm the change, or Cancel to revert
  7. Use Save As to export the modified structure to a new file

Architecture

┌─────────────────────┐          ┌──────────────────────────┐
│   Local (Windows)   │   SSH    │   Remote (Linux Server)  │
│                     │ ───────> │                          │
│  Trae IDE (UI)      │          │  Trae Server (Extension) │
│  ├─ Webview 3D      │ <─────── │  ├─ Parse .gjf/.xyz/.log │
│  ├─ Three.js (inline)│  data   │  ├─ Bond detection       │
│  ├─ Editing UI      │          │  ├─ Save file (VS Code)  │
│  └─ Mouse events    │          │  └─ Return molecule data  │
└─────────────────────┘          └──────────────────────────┘

The extension runs on the remote side (reading files, parsing, saving), while the Webview renders on the local side (Three.js inlined into HTML, mouse interaction, editing UI).

Project Structure

molecular-viewer/
├── src/
│   ├── extension.ts           # Extension entry point
│   ├── types.ts               # TypeScript type definitions
│   ├── parsers/               # File-format readers: text in, molecule out
│   │   ├── index.ts           # Parser dispatcher (auto-detect format)
│   │   ├── gjfParser.ts       # Gaussian .gjf parser (connect section, fixed atoms)
│   │   ├── xyzParser.ts       # XYZ format parser
│   │   ├── mol2Parser.ts      # Tripos MOL2 format parser
│   │   ├── logParser.ts       # Gaussian LOG parser (optimization trajectory)
│   │   ├── xtbParser.ts       # xtb LOG parser (optimization trajectory, content-sniffed)
│   │   ├── coordParser.ts     # Turbomole .coord parser (Bohr → Å)
│   │   ├── orcaInpParser.ts   # ORCA input .inp parser
│   │   ├── orcaOutParser.ts   # ORCA output .out parser (optimization trajectory)
│   │   ├── pdbParser.ts       # PDB format parser (ATOM/HETATM/CONECT)
│   │   ├── mopacParser.ts     # MOPAC input/output parser
│   │   ├── vmdVisualization.ts # Visualization files: VMD TCL scripts (molecules, representations, selections) + palettes/radii + representation → colour, size, surface patches + bare scalar-file recognition
│   │   ├── cifParser.ts       # CIF crystal structure parser (symmetry, occupancy)
│   │   ├── vaspParser.ts      # VASP POSCAR/CONTCAR parser (scale, Direct/Cartesian)
│   │   ├── cubeParser.ts      # Gaussian Cube parser (voxel vectors, robust lattice)
│   │   └── vestaParser.ts     # VESTA structure parser (CELLP, STRUC, SYMOP)
│   ├── tools/                 # Chemistry engines: molecule in, molecule out (no file I/O)
│   │   ├── bondPerception.ts  # Bond detection and order perception — pair tables, order lookup, valence solver, aromaticity; serialised into the webview as `BP` so the page runs the same module the host does
│   │   ├── bondDetector.ts    # Thin entry point over bondPerception (`ensureBonds`), the single call the host makes
│   │   ├── smilesTo3d.ts      # SMILES → 3D coordinates (zero-dependency, port of test/smiles_to_3d.py)
│   │   ├── addHydrogens.ts    # Add H: empirical-valence completion from the engine's tables, frozen skeleton
│   │   └── mmOptimizer.ts     # MM Optimize: built-in force field (bond/angle/torsion/improper/LJ + light electrostatics/H-bond/metal-coordination/polarisation), period-4/5 element tables, settable cutoff, low/medium/high presets, monotone optimizer as a steppable session (pause/resume/history)
│   └── webview/
│       └── molecularViewer.ts # Custom editor + Three.js webview + editing
├── dist/                      # Compiled JavaScript (pre-built)
├── test/                      # Sample molecular files
├── media/
│   └── three.min.js           # Three.js r128 (bundled locally)
├── package.json
├── tsconfig.json
└── LICENSE

Development

# Install dependencies
npm install

# Compile TypeScript
npm run compile

# Watch for changes
npm run watch

# Type check without emitting
npm run lint

# Package as .vsix
npm run package

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Changelog

See CHANGELOG.md for the full release history.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft