Repository navigation
Plugin Runtime and Panels
This page explains how ChemDraft keeps plugin commands alive across edits and renders their reports in native desktop windows.
The desktop owns one persistent plugin runtime through usePluginRuntime and createPluginRuntime. The host receives current document and selection through callbacks. Changing selection, zoom, pages, or undo history must not reconstruct the host, re-register commands, or discard a running plugin's state.
Core and plugin commands share the same CommandRegistry. Plugin-owned registrations carry a pluginId, so invocation can build the correct permission context and unregister can remove only that plugin's commands. All desktop registration paths use the runtime's registerPlugin and unregisterPlugin wrappers. Calling the bare host directly bypasses toolset staging and whole-plugin rollback.
Registration is transactional: validate permissions and references, check conflicts, then register all contributions. A failure must unwind the plugin rather than leaving a toolbar whose command was never registered. Plugin menu items use the same command route in native menus and the browser fallback.
A Web Worker is a separate browser execution environment without the document page's DOM. Analyzer plugins run in per-plugin ES-module workers through PluginWorkerBridge. The bridge uses a versioned ready handshake and request IDs for commands and host capabilities. A handshake must finish before an installed plugin is accepted.
Worker execution does not give a plugin direct native APIs. The bridge services its calls against the host-created, permission-gated command context. Installed worker responses carry a restrictive Content Security Policy: code, nested workers, WebAssembly, and data stay on the same origin. network.fetch is reserved and refused by the current desktop.
terminate() is total teardown: startup and in-flight commands are rejected, not left waiting. Disable, uninstall, failed installation, and replacement all use this lifecycle. Closing a report is different from disabling the plugin; the panel-close hook lets that plugin cancel the work associated with that panel.
For authors, an installable package owns src/workerEntry.ts and calls runPluginWorker. Do not re-export that side-effecting entry from the public src/index.ts. Packaging uses worker.format: "es" and relative asset references. Keep all built assets together.
Plugins call panels.showReport(panelId, report) with a PluginPanelReport. The panel must be declared and ui.panel must be present. The host's single PluginReportRenderer draws the report.
| Section kind | Use |
|---|---|
text |
Explanations, warnings, failure details |
keyValue |
Label/value rows |
table |
Columns and string-valued rows |
svg |
A static figure; displayed in an image context so embedded scripts do not execute |
chemicalName |
Host-labelled name and warnings, with a host-provided Copy action |
linkedFigure |
Interactive spectrum data and optional structure geometry with cross-highlighting |
New section kinds require an SDK contract and renderer change. An unrecognized kind must not be silently dropped. Plugins supply report data rather than React components, page DOM mutations, or arbitrary event handlers.
A minimal report follows the authoring example:
await context.panels?.showReport("panel.widget.result", {
title: "Widget",
sections: [{
kind: "keyValue",
rows: [{ label: "Result", value: "Complete" }]
}]
});A report may include source: { objectId, sourceFingerprint }. Capture the fingerprint from the selection used for the calculation. Desktop chrome compares it with the current object and marks the report stale after a change. This is a change detector, not proof that two molecules are chemically identical.
rerunCommandId makes Run again invoke the variant that produced the report. Without it, the host falls back to the panel contribution's command. This matters when one panel displays several command variants.
Analysis records are separate from document objects. analysis.write stores a method, version, source, status, payload, and warnings in the session store. The host stamps identity and time; plugins can read only their own records. Neither a report nor an analysis record automatically inserts anything on the page.
On desktop, each report has its own native window, keyed by plugin and panel ID. It can move away from the document and onto another monitor. The browser build uses an in-app fallback.
| Behavior | macOS | Windows |
|---|---|---|
| Menu ownership | Application-wide menu | Menu on the document window only |
| Ordinary report interaction | Drawing retains keyboard focus except deliberate text/control editing | Same goal, with native focus hand-back to the document |
| Click while another app is foreground | A user click can activate ChemDraft | Background focus requests are refused; ordinary panel interaction keeps the other app in front |
| Packaged plugin origin | tauri://localhost |
http://tauri.localhost |
Opening a report does not deliberately take keyboard focus from drawing. Editable controls and deliberate report-text selection borrow focus. Use Command+C on macOS or Ctrl+C on Windows to copy selected report text. Escape first dismisses an inner view if one is open, or releases an active editing/selection focus lease; with neither, it closes the report window.
Report windows have no direct filesystem, clipboard, or dialog permission. Save and copy operations needing native access travel back to the document window and report success, cancellation, or failure.
onPanelClosed(panelId) is the lifecycle hook supplied with registration or runPluginWorker. Use it to cancel expensive work, and prevent late results from reopening a dismissed panel. Disable and uninstall close panels before tearing down registration so the hook can run. Pending proposals remain in their separate review queue until resolved.
On Windows, the host supports one level of nested module worker beneath a plugin worker through a compatibility shim. Deeper nesting is unsupported there. macOS and browser builds keep native worker behavior; author portable plugins to the supported Windows depth.
ChemDraft repository · Apache-2.0 · Home
- Features overview
- Installation
- Quick Start
- Your first molecule
- FAQ
- Troubleshooting
- Glossary
- macOS and Windows differences
- Drawing basics
- Atoms and labels
- Bonds and stereochemistry
- Rings and chains
- Selection and editing
- Charges, radicals, and dative bonds
- Copy, paste, and clipboard
- Keyboard shortcuts
- Toolbars and palettes
- Documents, pages, and tabs
- Arrows and mechanisms
- Art objects and styling
- Publication figures and style presets
- Compound layouts
- Templates and abbreviations
- Chemistry guarantees
- Analysis and properties
- NMR prediction
- Name from structure
- Name to structure
- Structure recognition
- Spin 3D