This repository holds officially licensed NarraLeaf Studio plugins. Anything merged here is distributed under the NarraLeaf name, so submissions are reviewed for behaviour and permissions, not just for whether they build.
See the plugin authoring guide for how to build a plugin. This document covers the process for getting one merged.
If you are proposing a new plugin, open an issue first describing what it does and which permissions it needs. It is better to hear "this belongs in your own repository" before you write it than after.
You do not need to publish here to write a Studio plugin. Studio installs from any local folder — this repository is for plugins the NarraLeaf team maintains and vouches for.
-
Fork, then branch from
develop. All pull requests targetdevelop;masteronly moves through release merges. -
Copy
template/toplugins/<your-plugin-id>/. The directory name must equal theidinmanifest.json— CI enforces this. -
Build and validate locally:
cd plugins/<your-plugin-id> corepack enable && yarn install && yarn typecheck && yarn build cd ../.. node scripts/validate.mjs <your-plugin-id> node scripts/generate-index.mjs
-
Commit
yarn.lockand the regeneratedindex.json. -
Open the pull request.
A pull request is mergeable when:
- The directory is self-contained. Its own
package.json,yarn.lock, andnode_modules. No workspace membership, no reaching into another plugin's files, no shared root dependencies. yarn.lockis committed. Without it neither reviewers nor the release runner build what you built.- Versions agree.
manifest.jsonversion==package.jsonversion. index.jsonis regenerated. CI fails on drift. Never hand-edit it.- Everything registered is declared. Every blueprint node and widget type
passed to a
register*call must appear incontributesand be prefixed with your plugin id, or Studio throws at load. - Permissions are minimal. Every entry in
permissionsneeds a reason in the pull request description. Filesystem and API permissions get the most scrutiny — plugins are not sandboxed, so an approved permission is real trust. - An icon, if you ship one, is square.
manifest.jsonmay declare"icon": "icon.png"— a package-relative path to the thumbnail Studio shows beside your plugin in the Launcher list, installed and store alike. It must be.png,.webp,.jpgor.jpeg(no SVG — it is a document that can carry script; no GIF — an animating row is not yours to impose), square, between 64x64 and 512x512, and at most 512 KB. Your build script has to copy it intodist/the way it copiesmanifest.json; the template's already does.scripts/validate.mjschecks every rule, and Studio refuses to install a package whose icon is missing or out of bounds. Declaring one is optional: a plugin without an icon gets the monogram tile Studio draws from its name, which is a perfectly good place to stay. - Host modules stay external. Never bundle
react,react-dom, ornarraleaf-studio/*. The host supplies them through an import map; bundling React produces a second, broken instance. The template'sbuild.mjsalready handles this. yarn typecheckpasses.
Semver, per plugin:
- patch — fixes with no change to node types, pins, or params.
- minor — new nodes, widgets, or optional pins.
- major — removing or renaming a contributed type, removing a pin, or changing what an existing node does to an existing graph.
Renaming or removing a contributed type breaks every saved graph that uses it. Studio marks such nodes as missing rather than silently dropping them, but the project still needs manual repair — treat it as a major change and say so in the pull request.
Maintainers merge to develop, then to master. Releases are cut from master
by pushing a <plugin-id>@<version> tag; the release workflow refuses to publish
if the tag, manifest.json, and index.json disagree. See
README.md.
scripts/lib/plugins.mjs contains a port of Studio's manifest validator
(src/shared/utils/pluginManifest.ts), and scripts/lib/image.mjs a port of its
icon rules (src/shared/constants/pluginIcon.ts plus
src/shared/utils/{pluginIcon,imageDimensions}.ts). If Studio's validation rules
change, update the ports in the same change — otherwise CI accepts manifests that
Studio rejects at install, which is the worst possible failure mode for a
registry.
Run the tooling's own tests with node --test scripts/lib/*.test.mjs. They carry
the icon rules in particular, because no plugin here ships an icon and the code
would otherwise never execute until a contributor's did.