Skip to content

Plugin options ​

Every first-party plugin can be tuned: which presets a filter offers, which aspect ratios a crop allows, whether a watermark is locked. Options follow two rules:

  • They tune behaviour and constrain edits. They never carry pixel data. A custom filter is written to the edit log as preset: 'custom' with its matrix, stickers and fonts are assets, so a render never depends on options and the parity guarantee holds.
  • Constraints are enforced on both sides when you ask for it. By default options only shape the tools. Set enforce: true on a plugin (or lock: true on the watermark) and every edit log that breaks the constraints is rejected with OPTION_VIOLATION, even from a modified client. Pass the same options to createRenderer on your server for the guarantee to hold; render() then throws OPTION_VIOLATION for such a log.

With enforce, a constraint applies to the state an operation produces, not only to the fields it names. A resize.set without fit that starts a new target gets contain, so contain must be in fits. With resize.max, a target must name both width and height: with one side, the core derives the other from the aspect ratio of the image as it reaches the resize stage, and that side has no bound. annotate.fill: false and the palette cover the fill of a path and the background of a text as well as the fill of a rectangle or an ellipse.

Two ways to configure ​

Compose plugins yourself with configure():

ts
import { defaultPlugins, filterPlugin, cropPlugin } from '@sealpixel/plugins';

const plugins = defaultPlugins.map((p) => {
  if (p.id === 'filter')
    return filterPlugin.configure({
      presets: ['grayscale', 'sepia', { name: 'brand', label: 'Brand', matrix: BRAND_MATRIX }],
      defaultStrength: 0.8,
    });
  if (p.id === 'crop') return cropPlugin.configure({ aspects: [{ label: 'crop.aspect.square', value: 1 }], enforce: true });
  return p;
});
editor.plugins = plugins;

Or pass a pluginOptions map and let the editor apply it to the default plugins:

html
<sealpixel-editor plugin-options='{"filter":{"presets":["grayscale","sepia"]},"crop":{"rotation":false}}'></sealpixel-editor>
tsx
<SealpixelEditor src={file} pluginOptions={{ filter: { presets: ['grayscale', 'sepia'] }, crop: { rotation: false } }} />
vue
<SealpixelEditor :src="file" :plugin-options="{ filter: { presets: ['grayscale', 'sepia'] }, crop: { rotation: false } }" />
svelte
<SealpixelEditor {src} pluginOptions={{ filter: { presets: ['grayscale', 'sepia'] }, crop: { rotation: false } }} />
astro
<SealpixelEditor src="/photo.jpg" pluginOptions={{ filter: { presets: ['grayscale', 'sepia'] }, crop: { rotation: false } }} />
ts
createRenderer({
  plugins: defaultPlugins,
  pluginOptions: { filter: { presets: ['grayscale', 'sepia'] }, crop: { rotation: false } },
});

Unknown keys, unknown plugin ids and values outside the schema throw at configuration time. The map wins over a hand-configured plugin with the same id.

A configuration that the plugin would reject later also throws at configuration time, with the key that is wrong:

  • A finetune.ranges entry must stay inside the op range of its parameter (gamma 0.1..10, exposure -3..3, the others -1..1). A slider past it writes values that no edit log parser accepts.
  • With enforce, every default must pass the constraints: finetune.defaults only for offered controls and inside their ranges, fill.default in the palette, the watermark defaults (with anchor br, scale 0.2 and opacity 0.6 when not set) in anchors, scaleRange and opacityRange, the annotate.defaultStroke in widthRange and the palette, and each resize.presets entry inside max.

Without this, the editor would dispatch a default operation that its own options reject when an image loads, and the defaults of the other plugins would not apply either.

Try it ​

The filter offers two built-in presets and one custom matrix; the crop is square only, without rotation. Edit the JSON below the editor.

Round avatars ​

ts
cropPlugin.configure({ shape: 'circle', reset: false, enforce: true });

shape: 'circle' fixes the aspect to 1, shows a round mask in the crop gizmo and writes mask: 'circle' into the crop operation. The core keeps only the inscribed circle with an anti-aliased edge and makes the outside transparent, identically in the browser and on the server; PNG and WebP exports keep the transparency, JPEG flattens onto the background colour. Because the mask lives in the edit log, a saved log renders the same everywhere without knowing the option. reset: false removes the "Reset crop" button (and, with enforce, rejects crop.reset), so a signup flow cannot lose its round shape; with reset allowed, resetting a circle crop restores a full round crop instead of dropping the mask.

The frame at the edge of a rotated image ​

ts
cropPlugin.configure({ outside: 'allow' });

The crop rectangle lives in the bounding box of the rotated image, which is larger than the image, so at an angle a frame can reach area the image does not cover; fill paints it. With the default outside: 'forbid' the crop tool keeps the frame on the picture: a handle drag stops at the turned image's edge and slides along it, and a rotation that would carry the frame off the image shrinks it about its centre. allow lets the frame reach the box, for a passe-partout or a tilted print on a coloured background. The option shapes the UI only; the log carries rect and rotation either way, and a host that writes them itself decides for itself.

Defaults become operations ​

Options such as filter.defaultPreset, finetune.defaults, crop.defaultAspect, fill.default and watermark.defaults.source are applied when a source loads with an empty edit log. The editor dispatches the corresponding operations, so the defaults are visible in the log and travel with it. A saved log is never altered.

Locked watermark ​

ts
watermarkPlugin.configure({
  lock: true,
  defaults: { source: { kind: 'text', text: '© ACME', font: 'font.roboto', color: [1, 1, 1, 1] }, anchor: 'br', opacity: 0.5 },
});

With lock, the tool shows the watermark as fixed, every watermark.set that deviates and every watermark.clear is rejected, and export or a server render fail while the watermark is missing or altered. Register the same options on the server for the guarantee to hold.

anchors, text, image, scaleRange and opacityRange shape the tool. Like the options of the other plugins, they reject operations only with enforce: true. The lock applies with or without enforce.

Reference ​

The options reference lists every option with type, default and description, generated from the schemas.

Third-party plugins ​

definePlugin({ options: { schema, defaults, describe }, validate, validateDocument, initialOps }) gives your plugin the same surface. See Writing a plugin.