Skip to main content

Overview

Upstream PyMOL’s command line is a Python interpreter: type a command verb and it runs the command language; type anything else and it is evaluated as Python, with cmd in scope (from pymol import cmd). tenmol keeps that exact split, but swaps the scripting language. In tenmol the console is a client-side JavaScript REPL running against the in-browser TypeScript engine (packages/engine-ts/). The engine is the port’s PyMOL instance; it exposes the same cmd.* surface, so the thesis holds:
You can run all the same PyMOL scripts — just write them in JavaScript instead of Python.
cmd.fragment('ala') is identical in both languages. Only the host language changes: for loops, let, ===, and object literals for keyword arguments replace Python’s for … in, assignment, ==, and foo=bar kwargs. State persists across console lines exactly like a Python REPL: objects you load, selections you name, and settings you change stay live for the next line.
This page documents only what the TypeScript engine actually implements today. Symbols that are not yet ported reject with a NotPorted error rather than silently no-op — see What’s not yet ported.

The console

A console line is dispatched by Engine.do() (packages/engine-ts/src/engine.ts). The rule:
  1. A PyMOL command verb runs the command language. If the line (split on ; and newlines) contains any verb in the recognized set, the whole line is parsed as keyword arg1, arg2, … and run through the command handlers.
  2. Everything else is JavaScript. The line is evaluated as JS with cmd, print, console, and one global per PyMOL command namespace in scope — editor, util, preset, movie, gui (and any other registered namespace). So a bare namespaced call like editor.attach_amino_acid('pk1', 'gly') or util.cbag('all') dispatches through the engine instead of throwing ReferenceError: editor is not defined; an unported namespace verb reports a clean NotPorted rather than a JS error. A bare expression prints its value; print(...) / console.log(...) print to the console; errors are shown, not thrown.
  3. import … / from … import … lines are silent. These are internal plugin bootstraps (real PyMOL runs them in its interpreter); the port stays silent for them.
  4. /expr is the explicit JavaScript escape — a leading slash forces the rest of the line to run as JS even if it would otherwise look like a command.

Command language

JavaScript

cmd.<fn>(...) calls the engine synchronously and returns its value, so you can compose:
Statements work too — the console tries expression form first, then falls back to statement form for loops, let, and multiple statements:
The explicit escape, when a line would otherwise be read as a command verb:

Python → JavaScript, side by side

The cmd calls are the same. Only the surrounding language changes. Key differences:
  • Syntax is JavaScript. Braces and semicolons, let/const for variables, === for equality, C-style for loops.
  • Keyword arguments become a trailing object. Python object='m1' becomes { object: 'm1' } as the last argument. (The engine reads kwargs from a trailing object for the handlers that accept them, e.g. read_pdbstr and fragment.)
  • String arguments stay quoted, selections included: cmd.color('red', 'chain A').
  • print and console.log both route to the console output, the same place Python print writes upstream.
A fuller port, side by side:

The command language

The console recognizes these verbs directly (from KNOWN_KEYWORDS in engine.ts). Syntax is keyword arg1, arg2, comma-separated, exactly as in PyMOL. Multiple commands can be separated by ; or newlines. Any other verb-shaped line is treated as JavaScript instead (a bare line runs as JS; an import line is silent plumbing).

The cmd API reference

Every symbol below is registered in Engine.register(). Call them as cmd.<name>(...) from the console, or as command verbs where one exists. Signatures show tenmol JS argument order; the PyMOL column is the Python equivalent.

Loading

Objects & selections

Representations

The reps that render in-browser (Mode G) are: lines, spheres, sticks, nonbonded, nb_spheres.

Color

Camera

Command namespaces

Beyond the flat cmd.<verb> surface, whole PyMOL command namespaces are ported. Call them as cmd.<ns>.<verb>(...) or, in a JavaScript console line, as the bare namespace global (preset.pretty('all'), editor.attach_amino_acid('pk1', 'gly') — see The console). Engine.commandNames() lists every registered symbol. An unported namespace verb reports a clean NotPorted (cmd.editor.combine_fragment: not ported by @tenmol/engine-ts yet), never a silent no-op. Progress per namespace is tracked in docs/parity-dashboard.md.

Settings

The engine also answers a set of benign read defaults so the app’s panels (movie, scenes, views, settings) render cleanly on the local engine — e.g. get_frame, get_state, count_frames, count_states, get_scene_list, get_type, get_version, get_renderer. These return the values a fresh, empty PyMOL session would; they are reads only, not feature implementations.

The selection language

Selections are parsed by packages/engine-ts/src/select/selector.ts. Case-insensitive. Property selectors take +-grouped multi-values (name CA+CB); resi, index, and id also take lo-hi ranges. * and ? are wildcards in property values. An empty selection means all (as in PyMOL).

Property selectors

Keyword selectors

Operators & set selectors

What’s not yet ported

Everything outside the surface above rejects with a PymolError of type NotPorted (mirroring the bridge’s NotAllowed) — never a silent no-op — so gaps are visible and the differential parity suite catches them. Reps beyond the five listed above are treated as “nothing to draw” in Mode G. For the full picture of what is ported and how parity with real PyMOL is proven, see The TypeScript engine port.