---
name: ovito
description: Use when code imports `ovito`, or user asks to render molecular snapshots / animations from LAMMPS, XYZ, GSD, PDB, CIF or POSCAR files. Covers headless rendering (Tachyon/OSPRay), coloring, PBC handling, bonds, camera setup, and publication-ready output.
---

# ovito - Molecular Snapshot Rendering

## Overview

**OVITO Python** is the headless pipeline API of the OVITO Pro/Basic visualization
tool. It loads atomistic configurations, applies modifiers (color, unwrap, bonds,
selection), and renders publication-quality PNG / MP4 output without a GUI or
display. Targets OVITO 3.15+.

**Core pattern:** `import_file()` → `pipeline.modifiers.append(...)` → configure
`Viewport` → `viewport.render_image()` / `render_anim()`.

**Scope of this skill:** rendering snapshots and animations only. For analysis
(RDF, MSD, order parameters), use the `freud` skill in this marketplace.

## Installation

```bash
# Option A: official conda channel (recommended on conda/mamba systems)
conda install -c https://conda.ovito.org -c conda-forge ovito

# Option B: pip (works, but may emit a Qt-conflict warning in conda envs)
pip install ovito
```

If you see the warning *"Did you accidentally install the OVITO package from
PyPI in an Anaconda environment?"*, either follow option A, or silence with:

```python
import warnings
warnings.filterwarnings("ignore", message=".*OVITO.*PyPI")
```

This skill assumes `import ovito` works. See `references/gotchas.md` for the
full Qt/conda story.

## The 4-Step Mental Model

Every snapshot follows the same pipeline:

1. **Load** — `import_file()` returns a `Pipeline`.
2. **Modify** — append modifiers to `pipeline.modifiers` (color, unwrap, bonds, etc.).
3. **View** — create a `Viewport`, position the camera (or use `zoom_all()`).
4. **Render** — call `viewport.render_image()` (PNG) or `render_anim()` (MP4).

Canonical end-to-end snippet — load a LAMMPS dump, color by particle type, render a single frame:

```python
from ovito.io import import_file
from ovito.vis import Viewport, TachyonRenderer
from ovito.modifiers import ColorCodingModifier

pipeline = import_file("dump.lammpstrj")
pipeline.modifiers.append(ColorCodingModifier(
    property="Particle Type",
    gradient=ColorCodingModifier.Rainbow()))
pipeline.add_to_scene()           # required: makes the pipeline visible in the viewport

vp = Viewport(type=Viewport.Type.Perspective)
vp.zoom_all()                      # fit camera to data
vp.render_image(size=(1600, 1200),
                filename="snap.png",
                renderer=TachyonRenderer())
```

`add_to_scene()` is mandatory — without it, the viewport renders an empty scene.

## Loading Files

OVITO auto-detects format from the extension. `import_file` returns a `Pipeline`.

| Format | Call | Notes |
|---|---|---|
| LAMMPS dump | `import_file("traj.lammpstrj")` | Auto-detects columns; types are ints (1, 2, …) |
| LAMMPS data | `import_file("init.data", atom_style="full")` | `atom_style` often required (`atomic`, `bond`, `full`, …) |
| XYZ / extxyz | `import_file("frames.xyz")` | extxyz preserves cell + per-atom properties |
| GSD | `import_file("traj.gsd")` | HOOMD-blue trajectories, includes topology |
| PDB | `import_file("protein.pdb")` | Biomolecules; bonds read from CONECT records |
| CIF | `import_file("crystal.cif")` | Reads cell + symmetry |
| POSCAR | `import_file("POSCAR")` | VASP; no extension required |

**Multi-frame trajectories:**

```python
pipeline = import_file("traj.lammpstrj")
print(pipeline.num_frames)               # frame count (lazy, doesn't load all)
data = pipeline.compute(frame=10)        # compute one specific frame
```

**Globs and sequences** (separate files per frame):

```python
pipeline = import_file("frame_*.dump")   # wildcard merges to one trajectory
```

**Sftp / https URLs** also work: `import_file("sftp://host/path/traj.dump")`.

For deeper format-specific options (atom-style detection, custom column maps),
see the OVITO docs at <https://docs.ovito.org/python/modules/ovito_io.html>.

## Core Modifiers (Pre-Render)

Modifiers transform data between loading and rendering. They run in order; the
output of one is the input of the next.

### Color by particle type

```python
from ovito.modifiers import ColorCodingModifier

pipeline.modifiers.append(ColorCodingModifier(
    property="Particle Type",
    gradient=ColorCodingModifier.Rainbow()))
```

Available gradients: `Rainbow`, `Viridis`, `Magma`, `Hot`, `Jet`, `BlueWhiteRed`,
`Grayscale`, `CyclicRainbow`, `Fast`. See `references/modifiers.md` for custom
palettes and per-type color overrides.

### Color by a scalar property

```python
pipeline.modifiers.append(ColorCodingModifier(
    property="Potential Energy",
    gradient=ColorCodingModifier.Viridis(),
    start_value=-5.0, end_value=0.0))
```

### Unwrap a periodic trajectory

```python
from ovito.modifiers import UnwrapTrajectoriesModifier
pipeline.modifiers.append(UnwrapTrajectoriesModifier())
```

Apply this **before** `CreateBondsModifier` or any per-atom coloring that
depends on continuity across the box boundary.

### Wrap back into the primary cell

```python
from ovito.modifiers import WrapPeriodicImagesModifier
pipeline.modifiers.append(WrapPeriodicImagesModifier())
```

### Replicate the simulation cell

```python
from ovito.modifiers import ReplicateModifier
pipeline.modifiers.append(ReplicateModifier(num_x=2, num_y=2, num_z=1))
```

### Create bonds by distance cutoff

```python
from ovito.modifiers import CreateBondsModifier
pipeline.modifiers.append(CreateBondsModifier(cutoff=1.8))
```

For polymers with topology loaded from a data file, bonds are already present —
no need for this modifier.

### Hide / slice particles

```python
from ovito.modifiers import SelectTypeModifier, DeleteSelectedModifier
pipeline.modifiers.append(SelectTypeModifier(types={1}))   # select type-1 atoms
pipeline.modifiers.append(DeleteSelectedModifier())         # remove them
```

`SelectTypeModifier` supports `operate_on="bonds"` for bonds. See
`references/modifiers.md` for region-based selection and slicing.

## Viewport & Camera

A `Viewport` defines the camera. Preset views are usually enough:

```python
from ovito.vis import Viewport
vp = Viewport(type=Viewport.Type.Perspective)   # or .Ortho, .Front, .Top, .Left, .Right, .Back, .Bottom
vp.zoom_all()
```

### Manual camera placement

```python
vp = Viewport(type=Viewport.Type.Perspective)
vp.camera_pos = (20.0, 20.0, 20.0)   # world-space position
vp.camera_dir = (-1.0, -1.0, -1.0)   # look direction (will be normalised)
vp.camera_up  = (0.0, 0.0, 1.0)      # optional, defaults to world up
vp.fov = 0.6                          # radians for Perspective
```

For `Viewport.Type.Ortho`, `fov` is the half-height of the visible region in
world units (not radians):

```python
vp = Viewport(type=Viewport.Type.Ortho)
vp.camera_pos = (5.0, 5.0, 20.0)
vp.camera_dir = (0.0, 0.0, -1.0)
vp.fov = 6.0                          # world units
```

`zoom_all()` is convenient but overrides any manual `fov` and recenters the
camera; call it before manual tweaks if you want both.

## Rendering

Three renderers ship with OVITO. Choose by use case:

| Renderer | Speed | Quality | Headless | Use case |
|---|---|---|---|---|
| `TachyonRenderer` | Fast | Good | ✓ | Default; iteration, quick figures, animation |
| `OSPRayRenderer` | Slow | Excellent | ✓ | Publication figures, AO + denoising |
| `OpenGLRenderer` | Fastest | OK | ✗ (needs display) | Interactive previews only |

### Single image (PNG / JPEG / TIFF)

```python
from ovito.vis import TachyonRenderer
viewport.render_image(
    size=(1600, 1200),
    filename="snap.png",
    renderer=TachyonRenderer(ambient_occlusion=True, antialiasing_samples=4),
    background=(1.0, 1.0, 1.0),      # white
    alpha=False,                      # set True for transparent PNG
    frame=0,                          # which animation frame
)
```

### Publication-quality with OSPRay

```python
from ovito.vis import OSPRayRenderer
viewport.render_image(
    size=(2400, 1800),
    filename="figure.png",
    renderer=OSPRayRenderer(
        samples_per_pixel=8,
        refinement_iterations=4,
        denoising_enabled=True,
        material_shininess=10.0))
```

### Animation — MP4

```python
viewport.render_anim(
    filename="movie.mp4",
    size=(1280, 720),
    fps=30,
    renderer=TachyonRenderer())
```

`render_anim` also accepts `.avi`, `.mov`, `.gif`, or an image-sequence
pattern with `*` in the filename (`frame_*.png` produces `frame_0000.png`,
`frame_0001.png`, …). Use `range=(start, end)` and `every_nth_frame=k` to
sub-sample.

See `references/renderers.md` for a full kwarg reference and the renderer
decision tree.

## Reference Files

- `references/renderers.md` — Full renderer kwargs (Tachyon, OSPRay, OpenGL) and a "which renderer should I use?" decision tree.
- `references/modifiers.md` — Extended modifier reference: custom color palettes, computed-property expressions, slicing, transforms.
- `references/recipes.md` — Copy-paste recipes: publication PNG, dark-mode slide figure, transparent overlay, MP4 from LAMMPS dump.
- `references/gotchas.md` — Six common pitfalls: Qt/conda conflict, headless OpenGL failure, wrap vs unwrap, missing cell, type-color stability, lazy frame loading.
