Skip to Content

Plugins

A plugin is a package — a plugin.json manifest plus an ES module — installed from a .zip or a folder, or from the registry.

Plugins are a hosted-build feature. In the open-source local edition (VITE_EDITION=local) the Plugins panel, the menu and the host itself are absent, and the registry is never contacted — a self-hosted editor makes no request to premation.com on account of plugins, ever.

This is not a stripped binary with a hidden switch, and it is deliberate: the registry, the review queue, the reporting path and the signed revocation list are the things that make running a stranger’s code in your editor defensible, and a build with none of them should not be offering the sandbox either.

A project containing plugin content still opens on a local build, keeps its custom layers, plugin effects and generated subtrees exactly as written, and saves back to the same bytes. Losslessness is the invariant — a build that quietly dropped what it could not run would turn “open this to look at it” into data loss.

Installing

Plugins ▸ Manage Plugins… opens the manager. From there:

The Add plugin button opens a menu:

Menu itemWhat happens
Install from a package…Picks a .zip or .mplugin you were sent or built yourself
Install from a folder…An unpacked folder — the one to use while developing
Download starter templateWrites out a complete working plugin: a command, a keyframe write and a panel
Download effect sample (blur)A second sample covering the half the starter does not — a two-pass Gaussian blur, as a real multi-pass GPU effect

Browsing the registry is the other route in, and picking a plugin there downloads it, verifies the signature, then sends it through the same package reader and the same consent screen a local file gets. A registry install is not a shortcut past the permission screen.

Before any code exists anywhere, the manifest is validated and a consent screen shows you what the plugin is asking to be allowed to do. Only after you accept does the entry module get loaded into its worker.

Installing registers the plugin’s commands immediately — no restart — and they appear in the command palette and the Plugins menu right away. Installs persist across reloads. Packages are signed, and the package’s digest is pinned in the registry’s metadata before the bytes move, so what arrives is checked against what was published rather than against itself.

Permissions

PermissionThe plugin can
scene:readSee layer names, structure and scalar properties
scene:proxyWrite only inside its own layer type’s generated subtree
scene:writeCreate, change and delete layers anywhere
animation:readRead keyframes and sample animated values
animation:writeCreate and change keyframes and expressions
assets:readRead the pixels of images already in the composition
assets:writeCreate images and place them as layers
net:fetchContact the hosts listed in the manifest — and only those
timelineRead the current time and move the playhead

Registering commands, showing notifications, opening the plugin’s own panel, reading composition settings and using the plugin’s own storage need no permission — none of those read project data or change it.

scene:proxy is the one to look for on a generator. A plugin that builds a subtree under its own layer only ever touches its own children, but before this permission existed it had to ask for scene:write — and that consent screen reads “create, change, delete and reparent layers”, which is indistinguishable from a plugin that could rearrange your whole project. A generator asking for scene:read + scene:proxy is asking for the narrow thing.

Consent is per permission, not one yes over the list. The install screen ticks everything the manifest asks for and you may untick any of it. You can change your mind later — Manage Plugins… → Permissions on the row — which restarts the plugin with the new set. A grant is always intersected with the manifest, so nothing can end up with more than it disclosed.

A refused call returns an error naming the missing permission rather than silently doing nothing, so a well-written plugin degrades deliberately instead of behaving strangely.

Why this is safe

Each plugin runs in a Worker sandbox that locks down its own globals before importing the plugin’s code.

Failure modeWhat actually happens
Plugin loops foreverThe worker stops answering a heartbeat and is terminated in about 12 seconds. The editor is untouched
Plugin tries to read your account token or AI keysThere is no localStorage in a worker realm
Plugin tries to phone homefetch, XMLHttpRequest, WebSocket and importScripts are replaced with throwing stubs before the plugin’s module is imported. A plugin that legitimately needs the network declares its hosts and asks for net:fetch — see Network access
Plugin tries to read the interface or forge clicksNo document, no window
Plugin deletes your projectIt needs scene:write, and it is one Ctrl/ + Z

Every host API call executes inside the command system, so anything a plugin changes is a single undo.

Panels

A plugin’s UI panel runs in a frame sandboxed without same-origin access, so it has an opaque origin and cannot read the editor’s document, cookies or storage. Its only way out is a message to its own plugin — not to the editor, and not to another plugin.

Panels have no network: inline scripts run, fetch does not, and a remote image is refused.

This design exists because downloading plugins from strangers is the normal distribution model for creative tools. “The user chose the file” is not a security control.

What a plugin can contribute

Four kinds of thing, all declared in the manifest and loaded lazily.

Commands and panels

The originals: a named command that appears in the Plugins menu and the command palette, and a panel that docks alongside Effects and Graph.

Layer types

A plugin can contribute its own layer type, which behaves like a built-in one in the layer tree and the timeline and owns a generated subtree of ordinary layers beneath it. That subtree is what a project without the plugin still carries — the layers are real, so the file opens and renders; only the ability to regenerate them is missing.

The distinction that matters when using one: an edit you make by hand is preserved, and a regeneration replaces what the plugin generated. A plugin is told about the first and not the second, so hand-editing a generated child is supported rather than fought.

Effects

A plugin effect declares typed parameters and supplies a shader body — the host writes the pipeline, the uniform layout and the draw call. It is narrower than a native After Effects plugin on purpose: there is no JavaScript in the frame loop, so a plugin cannot make the renderer stutter, and the parameter layout is validated against a real GPU rather than trusted.

Plugin effects appear in their own Plugins folder in the Effects browser, labelled with the plugin’s name — two plugins may both ship a “Glow”.

A plugin effect needs the WebGPU tier. On the WebGL2 fallback it renders its input unchanged: not degraded, inert. A well-written plugin declares webgpu as required so it refuses to install rather than looking healthy and doing nothing — and the editor says which tier it is on in the viewport header.

Storage

Per-plugin storage, both global and per-project, needing no permission. It is the plugin’s own space — it cannot read another plugin’s, and it is not your project data.

Network access

A plugin that needs the network lists the exact hosts in its manifest and asks for net:fetch. It gets those hosts and nothing else.

The design decisionWhy
Hosts are declared, and exactA wildcard is a permission you cannot read on a consent screen
The request is made by the main processNot by the Worker and not by the panel, so there is no origin to abuse and no cookie jar to reach
The panel stays network-freeInline scripts run, fetch does not, a remote image is refused
DNS rebinding is handledA host that resolves to something else between the check and the request is the interesting attack, and it is the one a naive allowlist misses

The consent screen says the dangerous part out loud rather than listing a domain and hoping you infer it.

Supervision

MechanismBehaviour
Boot timeout8 seconds to activate, then stopped with a reason
HeartbeatPinged every 4 seconds; two unanswered pings terminate it
ErrorsSurfaced, never swallowed — a fatal shows in the manager row with a Restart button, and as a toast prefixed with the plugin’s name
LogPer plugin. Carries its own console output, every call the permission gate refused, and the crash that stopped it. Kept after the plugin dies, because that is when it gets read

A plugin that is installed but not running still appears in the menu, disabled, saying why. Nothing an installed plugin does is invisible.

Where a plugin shows up

ContributionWhere you find it
Registered commandsThe Plugins menu under the plugin’s name, and the command palette (Ctrl/ + Shift + P)
A panelWherever the manifest’s placement sends it, plus a Your plugin: Panel command
A layer typeThe layer-creation menu — Layer ▸ New
An effectA folder named after the plugin, in the Effects browser
NotificationsToasts, always prefixed with the plugin’s name
The packagePlugins ▸ Manage Plugins… — status, permissions, enable/disable, uninstall

A plugin’s row also carries, when they apply: whether its effects can draw on this renderer, a takedown notice (one marked malicious cannot be dismissed unread), and its security events — every signing-key rotation it has been through and how each one was authorised.

Nothing you click closes a plugin surface, and there is no ✕ on a plugin panel. A close button would mean “hide this until something else brings it back”, which is not a state you can reason about. Disabling or uninstalling the plugin is what removes it, and both are reversible from one place.

Disable is not uninstall. Disabling terminates the worker and unregisters the plugin’s commands but keeps the package. A panel never outlives its worker, so stopping a plugin closes its panel — a frame left on screen with nothing answering it reads as the editor being broken.

The registry

Browsing, installing and update checks go through the hosted registry. Publishers are namespaced, packages are scanned at publish time, and a reviewer queue sits behind the listings. You can browse it in the app, or on the web at premation.com/plugins — the listing is public so a plugin can be found, linked and evaluated before anyone signs up.

Building and publishing your own is its own guide: Publishing a plugin.

Updates

Checked only when you open the manager — never on a timer, never in the background. That is the editor asking the registry on the one screen where the answer is the point; it is not a plugin reaching anywhere. A failed check is silent, so working offline does not produce errors.

An update that asks for more permissions than you granted goes back through the consent screen instead of installing quietly.

When a plugin is withdrawn

Revocation is signed and fetched by the editor, so a plugin that turns out to be malicious stops being trusted on machines that already have it, rather than only disappearing from the listings.

You are told which plugin, and why, in the manager row — not silently left with something disabled. Your project keeps its content either way; the plugin is what stops running, not the layers it made.

Reporting one

Every plugin has a reporting path from its row in the manager. A report goes to the reviewer queue, which is a person, not a filter.

Last updated on