This is the first in what I think is going to be a series of posts about UXP — Adobe’s newest framework for writing plugins and scripts for Photoshop and other Creative Cloud apps.

This post provides a general introduction to the framework alongside some personal thoughts. Future posts will probably be shorter and cover specific development topics as I work on migrating my Expresso Exporter plugin from CEP to UXP.
A little bit of history
If you’ve ever attempted to write a Photoshop script or plugin you know that it can be quite a challenge. As far as I know of, there have been three main ways to extend Photoshop until now:
- ExtendScript: a JavaScript-like scripting language available in Photoshop and other Adobe apps since forever. It can be used to write scripts with simple UI. It’s very old and slow and haven’t received any significant update in a long time.
- CEP (Common Extensibility Platform): can be used to create custom panels and dialogs in Photoshop and other apps. Every CEP plugin runs in a hybrid browser (CEF) / NodeJS environment with support for fairly modern web technologies. Unfortunately, any interaction with the underlying app still needs to happen via ExtendScript, making plugins this weird monster made of different technology stacks.

- C++ Plugins (CSDK): native C++ plugins, also available in Photoshop since forever, are the go-to way to implement filters, file importer/exporters and generally everything that involve computation-heavy logic. Native plugins can also be included in CEP plugins, creating so called “hybrid” plugins.
(The list above doesn’t include the Generator framework or the Kevlar-based API for brevity.)
All these solutions are either old, slow, complex, scarcely documented or buggy and, generally, a pain to work with. There are tools — including some written by yours truly — that try to improve things, but maintaining rather complex plugins have always proven problematic.
All hail UXP
A couple of years ago Adobe presented the evolution of its extensibility platform, called UXP (Unified eXtensibility Platform). You can think of UXP as a mashup of ExtendScript and CEP. UXP supports JavaScript for scripting and HTML/CSS to create custom UI.

UXP is under active development and it’s supported, to various degrees, in Adobe XD, Photoshop and InDesign. It looks like the long term plan is to integrate UXP in most Creative Cloud apps. Adobe seems to be taking UXP development seriously — an approach that also shows in the very well written and up-to-date documentation available online.
UXP plugins can be packaged to .ccx
files and installed with a double click, making it finally easy to distribute plugins even outside of the Adobe Marketplace without requiring third-party tools or custom installers.

Scripts (using the .psjs
extension) can also be run directly by double clicking the file.
Scripting
The JavaScript side of UXP is powered by the Chromium V8 engine, which means all modern JavaScript features — such as Promises, async/await, lambas, modules, destructuring, etc. — are supported out-of-the-box. WebAssembly is supported as well.
On top of JavaScript’s standard feature set, UXP exposes APIs to access the file system, as well as OS and app-specific functionality. For Photoshop in particular, work is ongoing on a DOM-like API that provides access to Photoshop documents and features (similar to the one available in ExtendScript).
const { core, app } = require("photoshop");
// Create a new document, add a layer to it and log its name to console
await core.executeAsModal(async () =>
{
const myDoc = await app.createDocument();
const myLayer = await myDoc.createLayer();
console.log(myLayer.name);
});
Features that are not exposed via the DOM can be accessed via BatchPlay — an evolution of ExtendScript’s executeAction
.
Imaging API
As a game dev, things start to get really interesting with the Imaging API. The Imaging API allows to manipulate the pixels in a Photoshop document directly. This creates many interesting possibilities to write plugins that modify images on the fly or even create new images from scratch.
const { core, imaging } = require("photoshop");
// Gets the content of the currently selected layer in the active document
await core.executeAsModal(async () =>
{
const pixels = await imaging.getPixels();
console.log(`${pixels.imageData.width}x${pixels.imageData.height}`);
// We can do some processing on the pixels here, then "imaging.putPixels"
// can be used to put the pixel data back in the layer
});
Hybrid plugins
The Imaging API can potentially be even more interesting when paired with C++ logic. UXP recently gained support for hybrid plugins containing both C++ and JS/HTML in the same package.

This is different from what’s possible with CEP + CSDK (or even UXP + CSDK) in that the C++ code is distributed with and runs alongside the JavaScript code. Communication between the two happens via a API layer modeled against NodeJS N-API.
It should be possible to use native C++ code for performance-intensive tasks such as image processing (i.e. normalizing a normal map, inverting its channels, etc.), making it an interesting option for game dev.
(As a side note, this is what I’m currently trying out for the next iteration of Expresso.)
UI
UXP uses web technologies to create custom UI. Rendering is handled via a custom engine that promises better performance over the Chromium Embedded Framework used by CEP. Essentially, Adobe is building something that looks like a web browser, but isn’t web browser:
Keep in mind that UXP is not a browser. It’s a platform that provides the ease of using web technologies to build plugins/scripts for desktop applications. Hence, it does not support all the HTML/CSS capabilities you can use in a browser.
On one hand, this choice makes it possible to expose features that make it easier to build plugins. Most HTML elements, for example, render in a way that’s consistent with the rest of the Photoshop UI, while CSS media queries and global variables make theme-aware styling a breeze:
/* Common styles via CSS variables */
body {
background-color: var(--uxp-host-background-color);
color: var(--uxp-host-text-color);
border-color: var(--uxp-host-border-color);
font-size: var(--uxp-host-font-size);
}
/* Theme aware CSS media query */
@media (prefers-color-scheme: dark) {
body {
/* Dark color scheme styles */
}
}
On the other hand, this means that support for web standards in UXP isn’t that great and creates situations where CSS rules or JavaScript code simply don’t work. Adobe has been working on expanding support for web technologies over the past couple of years and seems committed to try and close the gap with web browsers (at least to an extent). We’ll see how that goes!
When it comes to UI frameworks, React is the only real safe choice for now since it’s being used internally by Adobe. Vue seems to be supported too, but I haven’t tried using it so far.
Where to go from here
Here’s some useful resources to get started with UXP development:
- UXP Documentation: official docs. Really well done with a lot of useful information.
- Adobe’s Tech Blog: news and tutorials from the horse’s mouth.
- Davide Barranca’s blog: lots of resources by a long time Photoshop plugin developer.
- Official Forum.