4 Min. read

Photoshop Plugins With UXP: Scripting

The previous post in the series provided a general overview of UXP, Adobe’s new extensibility platform for Creative Clouds apps. Let’s now look at a simple script, how to run and debug it, as well as how scripts can be used to show simple UI to the user.

A simple script

UXP scripts are written using modern JavaScript, powered by the V8 engine. Here’s an example of a script that creates a new document and adds a text layer to it:

const { app } = require("photoshop");
 
const doc = await app.createDocument({ width: 600, height: 600 });
const layer = await doc.createTextLayer({ contents: "Hello world!", fontSize: 32, position: { x: 100, y: 100 }});

I’m really a fan of how expressive modern JavaScript can be. Most commands triggered on the Photoshop side, like app.createDocument above, are asynchronous and should be awaited for completion. Because scripts run in a modal context, await can be used freely throughout the script.

To run the script, just save it with the .psjs extension and double click the file. This should yield the following mind-blowing result:

A screenshot of the Photoshop document created by the script, with the "Hello world!" layer visible

Requiring modules

UXP exposes a require function that works similarly to the one in NodeJS (with some limitations). A few built-in modules provide access to UXP, OS and app features. Some of the most useful modules include:

  • uxp: provides common features shared by all apps that support UXP plugins (with the caveat that not all features may be supported by all apps!).
  • fs: provides a NodeJS-style file system API (with some limitations compared its NodeJS counterpart).
  • shell: provides access to the underlying OS shell, with functions to open folders in file explorer or launch processes.
  • photoshop: Photoshop specific APIs. These include the app namespace that provides DOM-like access to Photoshop features, the imaging namespace that exposes methods to work with layer pixels and others.

DOM vs. BatchPlay

The DOM API is still a work in progress, so only a subset of the commands available in Photoshop are currently exposed via the DOM. The official docs provide an up-to-date list of all the available functionality.

BatchPlay — an evolution of ExtendScript’s executeAction — can be used to access features that aren’t available via the DOM yet. More information about BatchPlay is available in the docs and in this in-depth three part tutorial by Davide Barranca.

Debugging

The UXP Development Tool by Adobe provides a centralized way to debug scripts and plugins for all apps that support UXP. The tool can be installed using the Adobe Creative Cloud launcher.

A screenshot of the UXP Developer Tool connected to Photoshop, showing a list of plugins that can be loaded and debugged

To make the tool work correctly with Photoshop, Development Mode should be enabled in Photoshop’s settings:

A screenshot of the Photoshop settings dialog, with the Development Mode checkbox enabled

Clicking Debug Script in the UXP Development Tool and selecting the script file should now start the script in debug mode.

Showing a dialog

Scripts can show simple UI to the user via dialogs. The following example expands on the script above by showing a dialog through which the user can enter the text that’s added to the Photoshop document:

const { app } = require("photoshop");
 
async function getText()
{
    const dialog = document.createElement("dialog");
 
    // Input field and label
    const label = document.createElement("label");
    label.innerText = "What's on your mind?";
    label.style.color = "var(--uxp-host-text-color)";
    const input = document.createElement("input");
    input.type = "text";
    label.appendChild(input);
 
    const fieldset = document.createElement("fieldset");
    fieldset.appendChild(label);
    dialog.appendChild(label);
 
    // Okay button
    const button = document.createElement("button");
    button.innerText = "Okay";
    button.onclick = () => dialog.close();
    dialog.appendChild(button);
 
    // Show the dialog
    await document.body.appendChild(dialog).showModal();
 
    // Return the content of the input field when the dialog is closed
    return input.value;
}
 
const text = await getText();
const doc = await app.createDocument({ width: 600, height: 600 });
const layer = await doc.createTextLayer({ contents: text, fontSize: 32, position: { x: 100, y: 100 }});

The dialog itself is constructed similarly to how it would be done in a browser and can be shown by calling its showModal method. It’s important to await the returned Promise to prevent the rest of the script from running until the user closes the dialog.

A screenshot of the dialog created by the code above, with a text input field and an Okay button

UXP does an okay job at styling HTML elements to match the Photoshop UI. Better results could probably be achieved by using Spectrum Web Components instead of the default HTML input tag, though I find them to be somewhat overkill for simple UI.

Continue to the next post to learn how to create a plugin that adds a custom panel and a menu command to the Photoshop UI.