Creating your first UXP-based Photoshop plugin
In this tutorial, you will create your first own Photoshop plugin using UXP.
Prerequisites
To follow this tutorial, you need Photoshop v23 or above and the UXP Developer Tool (UDT). You can install both applications with the Creative Cloud Desktop app. You also need basic knowledge of HTML and JavaScript.
Step 1: Create the plugin
Open the UXP Developer Tool and click the "Create plugin..." button. In the dialog that opens, enter the following details:
Field | Value |
---|---|
Plugin Name | My first plugin |
Plugin Id | my.first.plugin |
Plugin Version | 1.0.0 |
Host Application | Adobe Photoshop |
Host Application Version | 23.0.0 |
Template | quick-layers-starter |
Click "Select Folder" and select a new, empty folder where you want to develop your plugin. The Developer Tool creates the necessary files in your selected folder and adds the plugin to the list of plugins.
You should now be able to see the following files in your selected folder:
icons
: a folder containing a set of icons for your pluginindex.html
: your plugin's entrypoint. This gets loaded when the plugin loadsmanifest.json
: a file containing the metadata you specified in UDT as well as a pointer to theindex.html
as an entrypoint.
As well as some other "meta" files like LICENSE
, README.md
, etc.
Step 2: Run the plugin
Open Adobe Photoshop and create some sample file you can use with your plugin.
To run your plugin within Photoshop, click the "•••" button on the right of your plugin's row within the UDT and select " Load". This loads your plugin in Photoshop and automatically opens the plugin's panel.
The quick-layers-starter template initially contains a panel with a "Populate Layers" button that allows you to populate a box within the panel with the layer names:
Let's take a look at what's going on in the background when running this plugin.
In the manifest.json
file, the "main"
field points to the index.html
file:
Copied to your clipboard{"id": "my.first.plugin","name": "My first plugin","version": "1.0.0","main": "index.html","host": [/* ... */],"manifestVersion": 4,"entrypoints": [{"type": "panel","id": "vanilla",// [...]"icons": [// [...]],"label": {"default": "Starter Panel"}}],"icons": [// [...]]}
When Photoshop loads the plugin, it loads the index.html
file specified here. The index.html
file, in turn, defines
our panel's UI:
Copied to your clipboard<!DOCTYPE html><html><head><script src="index.js"></script></head><style>/* [...] */</style><body><sp-heading>Layers</sp-heading><sp-body id="layers"> No layers </sp-body><footer><sp-button id="btnPopulate">Populate Layers</sp-button></footer></body></html>
As you can see, the index.html
file then loads the index.js
.
Note that while this looks like fairly standard HTML, the UXP environment is not a browser and only supports a subset of HTML/CSS/JS features. You can also see some custom components like <sp-heading>
, <sp-body>
, and <sp-button>
. These are so-called Spectrum UXP components that implement the Spectrum Design system and allow plugins to feel native in the surrounding Photoshop environment.
The index.js
file then sets up a click
listener on the "Populate
Layers" button and uses the Photoshop API to populate the <sp-body id="layers" />
element with the layer names:
Copied to your clipboardfunction showLayerNames() {const app = window.require("photoshop").app;const allLayers = app.activeDocument.layers;const allLayerNames = allLayers.map((layer) => layer.name);const sortedNames = allLayerNames.sort((a, b) =>a < b ? -1 : a > b ? 1 : 0);document.getElementById("layers").innerHTML = `<ul>${sortedNames.map((name) => `<li>${name}</li>`).join("")}</ul>`;}document.getElementById("btnPopulate").addEventListener("click", showLayerNames);
Note that you can use the window.require()
function to import various API modules, like require('photoshop')
in this
example.
Step 3: Adjust the plugin
We could call this good enough, but let's face it: This doesn't feel like you've built your own plugin. So let us at least add some customization to it by adding additional information about our layer to the output.
Have a look at the Layer
class API Reference. This page lists all the
properties and functions available on a layer object. You can choose whatever property you want, but for this tutorial,
we will just use the opacity: number
property.
Adjust the main.js
to also include the new property in the output:
Copied to your clipboardfunction showLayerNames() {// [...]const allLayerNames = allLayers.map((layer) => `${layer.name} (${layer.opacity} %)`);// [...]}// [...]
With your main.js
file saved, you need to reload the plugin to run the plugin including your changes. You can do this
by selecting the "••• > Reload" option in the UXP Developer Tool.
If you change anything in the manifest.json
file, you need to do a full reload of the plugin to reflect the changes.
To do this, first select "Unload" and then "Load" in the UXP Developer Tool.
Alternatively, you can also watch your plugin folder for changes to reload the plugin automatically whenever you change something. To do so, run the "Watch" option in your plugin actions menu in the UDT.
Back in Photoshop, when you click "Populate Layers" again, you should see that your property is now also included in the output:
Also, you may find the icon missing when docking the plugin panel in a toolbar. It can be resolved by changing "path"
field to the updated icon filename in manifest.json
. For example, "path": "icons/dark.png",
corresponds to following icon files
Next steps
You've now built your first own plugin. It doesn't look like much right now, but by taking a look at what's available in the API Reference, you can already do a lot of things with the knowledge of this tutorial, alone.
In the next tutorial, you'll learn how you can not only get information about your document, but actually make changes to it, as well.