PluginContext
What a plugin’s entry module receives in its exported activate function:
export function activate(context) { context.registerCommand({ id: "hello", title: "Say Hello", run: () => context.showMessage("Hello") });}A plugin is a folder with a plugin.json manifest and its entry module, index.js by
default. Its module stays loaded while Modlumi runs, so module-level variables keep
their values between commands. When the user turns the plugin off in the Extensions
window, Modlumi calls the module’s exported deactivate(), if it has one, and then
removes the plugin’s commands and listeners.
Properties
Section titled “Properties”documentData
Section titled “documentData”
readonlydocumentData:DocumentData
The plugin’s value stored in the open model.
entityData
Section titled “entityData”
readonlyentityData:EntityData
The plugin’s values stored on faces, edges, groups, component instances, definitions and materials.
features
Section titled “features”
readonlyfeatures: readonlyPluginFeature[]
The parts of the plugin API added within its version that this Modlumi has, such as
"network" or "mergeVertices". They depend on the build too: one that can’t send
requests lacks "network", whatever the user granted. A plugin that needs one lists it under "requires" in
plugin.json, so an older Modlumi refuses it with a clear reason; one that can do without
checks here.
readonlyfiles:PluginFiles
File dialogs, the files the user picks in them, and the plugin’s data folder.
readonlyid:string
The plugin’s id from plugin.json.
readonlyname:string
The plugin’s name from plugin.json.
permissions
Section titled “permissions”
readonlypermissions:PluginPermissions
What the user granted of the permissions plugin.json asks for. Calls that need a
permission the plugin lacks throw an Error named "PermissionError".
selectedItems
Section titled “selectedItems”
readonlyselectedItems: readonlystring[]
The ids of the plugin’s pickable items the user selected, in the order selected.
settings
Section titled “settings”
readonlysettings:PluginSettings
The plugin’s settings for the current user.
version
Section titled “version”
readonlyversion:string
The plugin’s version from plugin.json.
viewport
Section titled “viewport”
readonlyviewport:Viewport
The viewport of the desktop window: its live camera and size.
Methods
Section titled “Methods”addOverlay()
Section titled “addOverlay()”addOverlay(
draw): () =>void
Draws over the viewport on every frame, whichever tool is selected, beneath the selected
tool’s preview. draw describes the drawing with the same view as ToolDefinition.draw,
in model coordinates, or in screen pixels with screen: true. It only reads the model, and
must be synchronous and quick, since it runs every frame. An overlay that throws is
removed, with a message; the plugin’s other overlays keep drawing. Returns a function that
removes the overlay.
Parameters
Section titled “Parameters”(view) => void
Returns
Section titled “Returns”() => void
Example
Section titled “Example”// Marks the origin with a red cross.context.addOverlay((view) => { view.lines([[-0.5, 0, 0], [0.5, 0, 0], [0, -0.5, 0], [0, 0.5, 0]], { color: { r: 0.85, g: 0.2, b: 0.2 }, width: 2 });});addPanel()
Section titled “addPanel()”addPanel(
panel):Panel
Adds a dockable panel, listed in the Window menu, where the user opens and closes it. Panels start closed; Modlumi remembers which ones the user left open and where. Adding an id again replaces its definition.
const state = { width: 1, steps: 12 };context.addPanel({ id: "stairs", title: "Stairs", draw(ui) { state.width = ui.length("Width", state.width); state.steps = ui.integer("Steps", state.steps, { min: 1 }); },});Parameters
Section titled “Parameters”Returns
Section titled “Returns”addPickableItems()
Section titled “addPickableItems()”addPickableItems(
definition): () =>void
Lets the user select the plugin’s own items, such as building levels, with the Select
tool, and delete them with Delete, like model entities. items runs every frame, like an
overlay, and returns each item’s id and the lines and points the user picks it by, in
model coordinates; draw the items themselves with an overlay. Selected items show in the
selection’s color. onDelete receives the ids of the deleted items inside one operation,
so storing the items in documentData makes deleting them undoable. Returns a
function that removes the items.
Parameters
Section titled “Parameters”definition
Section titled “definition”Returns
Section titled “Returns”() => void
Example
Section titled “Example”context.addPickableItems({ items: () => marks.map((mark) => ({ id: mark.id, points: [mark.position] })), onDelete(ids) { marks = marks.filter((mark) => !ids.includes(mark.id)); context.documentData.set(marks); },});addPropertiesSection()
Section titled “addPropertiesSection()”addPropertiesSection(
section):void
Adds a section to Properties, shown while the selection is one group or component instance holding the plugin’s PluginContext.entityData. This is how a plugin lets the user re-edit objects it made:
context.addPropertiesSection({ id: "box", title: "Box", draw(ui, container) { const size = context.entityData.get(container); const changed = ui.length("Size", size); if (changed !== size) rebuild(container, changed); },});Parameters
Section titled “Parameters”section
Section titled “section”Returns
Section titled “Returns”void
addSnapProvider()
Section titled “addSnapProvider()”addSnapProvider(
provide): () =>void
Parameters
Section titled “Parameters”provide
Section titled “provide”(viewport) => Iterable<SnapTarget, any, any> | null | undefined
Returns
Section titled “Returns”() => void
alert()
Section titled “alert()”alert(
message,options?):void
Shows a message in a modal dialog with an OK button.
Parameters
Section titled “Parameters”message
Section titled “message”unknown
options?
Section titled “options?”title?
Section titled “title?”string
Returns
Section titled “Returns”void
animate()
Section titled “animate()”animate(
frame):number
Calls frame once every frame, with the seconds since the animation started and since the
previous frame, until it returns false or clearTimer stops it.
Parameters
Section titled “Parameters”(elapsed, delta) => unknown
Returns
Section titled “Returns”number
Example
Section titled “Example”// Shows a countdown in the status message for three seconds.context.animate((elapsed) => { tool.status = `Done in ${Math.ceil(3 - elapsed)}s`; return elapsed < 3;});clearTimer()
Section titled “clearTimer()”clearTimer(
id):void
Stops a timer or animation; ids of stopped ones are ignored.
Parameters
Section titled “Parameters”number
Returns
Section titled “Returns”void
confirm()
Section titled “confirm()”confirm(
message,options?):void
Asks a question in a modal dialog with confirm and cancel buttons.
Parameters
Section titled “Parameters”message
Section titled “message”unknown
options?
Section titled “options?”Returns
Section titled “Returns”void
createImage()
Section titled “createImage()”createImage(
source):PluginImage
Makes an image from the bytes of a PNG or JPEG file, like loadImage, or from pixels: four bytes of red, green, blue and alpha each, in rows from the top.
Parameters
Section titled “Parameters”source
Section titled “source”ArrayBuffer | Uint8Array<ArrayBufferLike> | { height: number; pixels: ArrayBuffer | Uint8Array<ArrayBufferLike>; width: number; }
Returns
Section titled “Returns”Example
Section titled “Example”// A 2 by 1 image, red then half-transparent blue, saved as a PNG the user chooses.const image = context.createImage({ width: 2, height: 1, pixels: new Uint8Array([255, 0, 0, 255, 0, 0, 255, 128]) });const file = await context.files.save({ name: "swatch.png", filters: [{ name: "PNG image", extensions: ["png"] }] });file?.writeBytes(image.toPng());fetch()
Section titled “fetch()”fetch(
url,options?):Promise<FetchResponse>
Sends a request to a host the plugin’s "network" permission lists and the user granted,
and resolves with the response, or rejects with a TypeError when the request fails. Only
http and https URLs work, redirects come back as responses rather than being followed,
and a plugin may have 8 requests in flight. A command can await it: its run finishes
while the request is out, and continues once the response arrives. When another model
opens before the response arrives, the promise rejects with a ReferenceError instead,
and the code that runs for it, such as a catch or finally, can’t reach the model open
now: reading or editing it throws a ReferenceError too. Restarting or turning
off the plugin cancels its requests. Desktop builds on Linux and macOS can make requests;
others throw.
Parameters
Section titled “Parameters”string
options?
Section titled “options?”Returns
Section titled “Returns”Promise<FetchResponse>
Example
Section titled “Example”const response = await context.fetch("https://api.example.com/prices?part=beam");if (response.ok) { context.showMessage(`Beams cost ${response.json().price}`);}loadImage()
Section titled “loadImage()”loadImage(
path):PluginImage
Loads a PNG or JPEG file from the plugin folder, for overlays and previews to draw with ToolView.image. A plugin’s images may hold 64 million pixels together.
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”onActiveContextChanged()
Section titled “onActiveContextChanged()”onActiveContextChanged(
listener): () =>void
Calls listener after the user enters or leaves a group or component. Returns a
function that removes it.
Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
onCameraChanged()
Section titled “onCameraChanged()”onCameraChanged(
listener): () =>void
Calls listener after the camera moved: orbiting, panning, zooming, a standard view or
Viewport.setCamera. While the user orbits it runs every frame, so keep it quick.
Returns a function that removes it.
Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
onDocumentClosed()
Section titled “onDocumentClosed()”onDocumentClosed(
listener): () =>void
Calls listener after New or Open replaced the open document, just before the
PluginContext.onDocumentOpened listeners. The previous document is already gone.
Returns a function that removes it.
Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
onDocumentOpened()
Section titled “onDocumentOpened()”onDocumentOpened(
listener): () =>void
Calls listener after New or Open replaced the open document, once the new document
is open. Returns a function that removes it.
Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
onModelChanged()
Section titled “onModelChanged()”onModelChanged(
listener): () =>void
Calls listener after the model changes: an edit, an undo or a redo, by the user, a
script or a plugin. Returns a function that removes it.
Listeners run once per frame for everything that changed during it, in this order:
document closed, document opened, active context, selection, model. They receive no
arguments; read what they need from activeModel. Listeners only read, so the
user can keep drawing: editing the model or the selection, undo and redo throw
ModelError. Use a command for edits. A listener that runs for more than a second is
stopped and its plugin restarted. Listener errors are logged and never stop other
listeners.
context.onModelChanged(() => { const faces = modlumi.activeModel.entities.ofType("Face").length; console.log(`${faces} faces`);});Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
onSelectionChanged()
Section titled “onSelectionChanged()”onSelectionChanged(
listener): () =>void
Calls listener after the selection changes. Returns a function that removes it.
See PluginContext.onModelChanged for when listeners run.
Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
onViewResized()
Section titled “onViewResized()”onViewResized(
listener): () =>void
Calls listener after the viewport changed size. Returns a function that removes it.
Parameters
Section titled “Parameters”listener
Section titled “listener”Returns
Section titled “Returns”() => void
registerCommand()
Section titled “registerCommand()”registerCommand(
command):void
Adds a command to the plugin’s submenu in the Extensions menu. Registering an id again replaces that command.
Parameters
Section titled “Parameters”command
Section titled “command”Returns
Section titled “Returns”void
registerExporter()
Section titled “registerExporter()”registerExporter(
exporter):void
Adds File > Export name, which asks the user where to save a file with one of the
extensions and passes it to export, which writes the model to it. export must be
synchronous, only reads the model, and needs no permission to write the file.
Parameters
Section titled “Parameters”exporter
Section titled “exporter”Returns
Section titled “Returns”void
registerImporter()
Section titled “registerImporter()”registerImporter(
importer):void
Adds File > Import name, which asks the user for a file with one of the extensions and
passes it to import, inside one undoable operation; dropping such a file on the window
imports it too. import must be synchronous, and needs no permission to read the file.
Modlumi keeps .modl and .skp to itself. When the plugin restarts or another model opens
before the import runs, it is dropped.
Parameters
Section titled “Parameters”importer
Section titled “importer”Returns
Section titled “Returns”void
Example
Section titled “Example”context.registerImporter({ id: "points", name: "Point List", extensions: ["xyz"], import(file) { const points = file.readText().trim().split("\n").map((line) => line.split(/\s+/).map(Number)); for (const point of points) modlumi.activeModel.activeEntities.addGuidePoint(point); },});registerTool()
Section titled “registerTool()”registerTool(
tool):PluginTool
Adds an interactive tool, listed in the plugin’s submenu of the Extensions menu, where choosing it selects it, and optionally in the toolbar. Returns its handle. Tools and commands share ids.
const tool = context.registerTool({ id: "mark", title: "Mark Points", activate: () => { tool.status = "Click to add a guide point."; }, onMouseUp(event) { if (event.point) model.operation("Mark", () => model.activeEntities.addGuidePoint(event.point.position)); },});Parameters
Section titled “Parameters”Returns
Section titled “Returns”setInterval()
Section titled “setInterval()”setInterval(
callback,interval):number
Calls callback every interval milliseconds, at most once a frame, until clearTimer.
Parameters
Section titled “Parameters”callback
Section titled “callback”() => unknown
interval
Section titled “interval”number
Returns
Section titled “Returns”number
setTimeout()
Section titled “setTimeout()”setTimeout(
callback,delay?):number
Calls callback once, between frames, after at least delay milliseconds, and returns an
id for clearTimer. Timers stop when the plugin is turned off or reloads.
Timer callbacks may edit the model inside model.operation(); an edit ends the gesture of
the active tool, as a command does. Callbacks must be synchronous; one that throws stops
its timer.
Parameters
Section titled “Parameters”callback
Section titled “callback”() => unknown
delay?
Section titled “delay?”number
Returns
Section titled “Returns”number
showDialog()
Section titled “showDialog()”showDialog(
dialog):Dialog
Shows a dialog, or brings back the open one with the same id with this definition.
Parameters
Section titled “Parameters”dialog
Section titled “dialog”Returns
Section titled “Returns”showMessage()
Section titled “showMessage()”showMessage(
text):void
Shows a short message to the user, such as the result of a command.
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”void