API reference

Every member of the athanor object an Athanor plugin can call in API version 1, with signatures, return values, permissions and the shapes they use.

API version 1. This page lists everything a plugin can call. A plugin's main.js sees the global athanor object and standard JavaScript, and nothing else. Calls that ask Athanor for something return promises; the host answers each one only if the plugin holds the permission it needs, and otherwise the promise rejects with a sentence naming the permission.

Version

Member Returns Description
athanor.apiVersion 1 The API version this Athanor runs.

Reading the page

Member Returns Needs Description
athanor.snapshot() Promise<Snapshot> document.read The whole page: structures, text and the selection.
athanor.selection() Promise<{ structures: string[]; atoms: number[] }> none The selected structure ids and atom ids. Works without document.read.
athanor.conformer(structureId: string) Promise<{ atoms: Array<{ element: string; x: number; y: number; z: number }> }> document.read A structure's 3D coordinates in angstroms from Athanor's engine, hydrogens included. Rejects when no structure has that id.

Changing the page

Member Returns Needs Description
athanor.apply(change: Change) Promise<{ label: string; added: string[] }> document.edit Makes the change as one undo step named "Plugin: label". added lists the ids of added structures ("s:…") and text ("n:…"). Rejects, with nothing changed, if any op is refused. At most 5 a second (20 for official plugins).
athanor.propose(change: Change, meta?: { title?: string; detail?: string }) Promise<{ accepted: boolean }> document.edit Makes the change and shows it with Accept and Reject in a box naming the plugin. Resolves when the person answers. A new proposal from the same plugin rejects the previous one.

See Changes, undo and previews for every op.

Talking to the person

Member Returns Description
athanor.notify(message: string, opts?: { error?: boolean }) void Shows Athanor's toast, prefixed with the plugin's name. Cut at 100 characters; at most 12 a minute, any more are dropped. error: true shows it as an error.
athanor.closePlugin(message?: string) void Shows the optional message (up to 100 characters) and closes the plugin's window.

Handling what Athanor asks for

Each registers the handler Athanor calls. Register one handler per key; when two are registered for the same key, only the first runs. A handler may return a value or a promise.

Member Handler gets Handler returns Description
athanor.commands.on(key: string, fn) parameters: Record<string, unknown> (always {} in API 1) anything (ignored) Runs when the person runs the command declared with that key.
athanor.formats.onExport(key: string, fn) nothing { filename: string; text?: string; base64?: string } Builds the file when the person exports in the format declared with that key.
athanor.formats.onImport(key: string, fn) Registers an import handler. API 1 never calls it.
athanor.checks.on(key: string, fn) snapshot: Snapshot Finding[] Runs the check declared with that key.
athanor.sources.onSearch(key: string, fn) query: string Array<{ name: string; smiles: string }> Answers a Quick insert search for the source declared with that key.

Events

Member Description
athanor.on(event: string, fn: () => void) Calls fn when the event happens while the plugin is running. A plugin that is not running is not started for an event.
Event When
documentchange The page changed. Sent 300 ms after the last edit, only to plugins that hold document.read.
settingschange The person changed one of the plugin's settings. Read them again with athanor.settings.get().

Settings

Member Returns Description
athanor.settings.get() Promise<Record<string, boolean | number | string>> The settings the manifest declares, as the person set them, or their defaults. Needs no permission.

The plugin's window

Available when the manifest has a ui file. See Panels and windows.

Member Returns Description
athanor.ui.show(opts?: { width?: number; height?: number; title?: string }) void Opens the window (default 320 by 240, held between 160 by 120 and 1200 by 900), or updates the open one.
athanor.ui.hide() void Closes the window.
athanor.ui.resize(width: number, height: number) void Resizes the window.
athanor.ui.postMessage(data: unknown) void Sends plain data to the window.
athanor.ui.onmessage ((data: unknown) => void) | null Set it to receive messages from the window.

Inside ui.html, the window has its own small athanor object:

Member Description
athanor.postMessage(data) Sends plain data to the plugin's logic.
athanor.onmessage = fn Receives messages from the logic. Setting it replaces every earlier listener.
athanor.addEventListener('message', fn) Adds another listener.

Standard globals

Global Description
console.log, console.info, console.warn, console.error Write to the plugin console. Each line is cut at 2,000 characters; the console keeps the last 500.
setTimeout(fn, ms), clearTimeout(id) Timers run by the host. ms is held between 0 and 600,000.

There is no fetch, no DOM, no importScripts, no Worker and no setInterval in main.js.

Shapes

interface Snapshot {
  apiVersion: 1;
  title: string;                                   // the document's title
  structures: Structure[];
  texts: Array<{ id: string; text: string; x: number; y: number }>;   // id is "n:<id>"
  selection: { structures: string[]; atoms: number[] };
}
 
interface Structure {
  id: string;                  // "s:<first atom id>", stable until the structure is edited
  smiles: string;
  molfile: string;
  formula: string;             // Hill order
  mw: number | null;           // g/mol, three decimals
  name: string;
  atoms: Array<{ id: number; element: string; x: number; y: number; charge: number }>;
  bonds: Array<{ id: number; a: number; b: number; order: number }>;
  box: { minX: number; minY: number; maxX: number; maxY: number };
  selected: boolean;           // any of its atoms is selected
  stereocenters: Array<{ atom: number; label: string | null }>;   // R, S, r or s; null when no wedge says which
}
 
interface Change {
  label?: string;              // up to 60 characters; "Edit" when missing
  ops: Op[];                   // 1 to 500
}
 
type Op =
  | { op: 'addStructure'; smiles?: string; molfile?: string; x?: number; y?: number; name?: string }
  | { op: 'addText'; text: string; x: number; y: number; role?: 'caption' | 'conditions' | 'title' | 'compoundLabel' }
  | { op: 'setStyle'; id: string; color: string }        // "#rrggbb", or "" for ink
  | { op: 'setName'; structureId: string; name: string }
  | { op: 'setAtom'; id: number; element?: string; charge?: number }
  | { op: 'setBond'; id: number; order?: 1 | 2 | 3; stereo?: 'none' | 'wedge' | 'hash' }
  | { op: 'remove'; ids: Array<string | number> };
 
interface Finding {
  atom: number;
  severity?: 'error' | 'warning' | 'note';   // "note" when missing
  title: string;                             // up to 80 characters
  message: string;                           // up to 400 characters
}

About athanor.d.ts

The template's athanor.d.ts does not yet declare everything on this page. athanor.propose, athanor.conformer, the stereo field of setBond (it declares order as required) and Structure.stereocenters all work, but your editor's type check reports them as errors. Add a // @ts-ignore above such a line, or extend the typings in your own copy of the file. This page is the reference; the typings will catch up.

Is this helpful?

Last updated Nov 11, 2026