Extend Dottie with plugins on Mac

Dottie can run user plugins written in JavaScript. A plugin can be a loose .js command or a package folder containing plugin.json and a JavaScript entry point.

Where plugins live

By default, Dottie loads plugins from its own container folder—nothing to configure. Choose Plugins > Open Plugins Folder… to reveal that folder in the Finder, and Plugins > Reload Plugins to re-scan it after you add or edit files.

Running a plugin

Commands, validators, and tools appear in Plugins. Plugin importers and exporters appear in the corresponding File menus. Dottie bundles isometric projections, configurable Shadow and Extrude effects, and palette-range remapping.

To try it: make a rectangular selection with the Select Rectangle tool, then choose Plugins > Selection > Make Selection Isometric Up-Right (or Up-Left). Press Command+Z to undo it in one step.

Writing a plugin

A command calls dottie.command({ name, menu, run }) or the compatible dottie.plugin(…). Packages may also register dottie.tool, dottie.importer, dottie.exporter, or dottie.validator. Every callback receives a context object containing only host-mediated operations.

Context properties:

Returning changes:

Native parameters and background work:

Package manifest:

{
  "id": "com.example.my-plugin",
  "name": "My Plugin",
  "version": "1.0",
  "apiVersion": 2,
  "entry": "main.js",
  "capabilities": ["document.read", "document.write", "preferences"]
}

Supported capabilities are document.read, document.write, palette.write, preferences, files.open, files.save, validators, and tools. Unsupported API versions, unknown capabilities, duplicate IDs, and entry paths outside the package are rejected and listed by Plugins > Show Plugin Errors….

The isometric example below shows the full pattern:

// Make Selection Isometric — the named edge stays put and the tilt rises away from it.
function isometric(ctx, anchorRight) {
  var b = ctx.selection.bounds;
  if (!b) return;                        // nothing selected → no-op
  var mask = ctx.selection.mask;         // mask[x][y], bounds-relative
  var cols = ctx.selection.colors;       // "#RRGGBBAA" or null
  var out  = ctx.emptyResult();          // builder for the new content
  for (var x = 0; x < b.w; x++) {
    var dist  = anchorRight ? (b.w - 1 - x) : x;  // columns from the fixed edge
    var shift = -(dist >> 1);                      // 2px columns, 1px up each
    for (var y = 0; y < b.h; y++) {
      if (mask[x][y]) {
        var nx = b.x + x, ny = b.y + y + shift;
        out.select(nx, ny);              // selection follows the tilt
        if (cols[x][y]) out.paint(nx, ny, cols[x][y]);
      }
    }
  }
  ctx.commit(out);                       // apply as one undo step
}

dottie.plugin({ name: "Make Selection Isometric Up-Right", menu: "Selection",
  run: function (ctx) { isometric(ctx, false); } });
dottie.plugin({ name: "Make Selection Isometric Up-Left",  menu: "Selection",
  run: function (ctx) { isometric(ctx, true); } });

Plugins have no network or ambient file access. Packaged plugins receive only declared capabilities; file reads and writes additionally require a path chosen by the user in a native panel.

See also