Tag Archives: CEP

HTML5 (CEP) Panels for After Effects: Fixes, hacks and workarounds

I’m collecting a bunch of handy little code snippets and solutions from various developers so they don’t get lost. Here are a few to get things started:

CEP 6.1 changes

CEP 6.1 (CC2015.1) includes changes to node.js implementation.

Adobe has posted a sample panel showing how to work in the new structure.

Command line switches

You can use Chrome’s command line switches to change panel behavior and/or limits, as well as for debugging purposes. Add them to your manifest.xml file, like so:


Need a really long console.log()?

From Bruce Bullis:

Here’s a fix to the Chrome Debugger’s unwillingness to scroll past 99 Console() items, for extensions running in current Adobe apps.

Install Styler – Chrome Web Store
Go to your debug page http://localhost:8001/ (or whatever port you’ve designated)
Click on Styler extension icon (to right of address box)
Add “html /deep/ * { min-width: 0; min-height: 0; }” to the css.

Shorter filepath to CEP cookies

Since CEP panels are really just browser windows, you can store settings in cookies. If you need to access those cookies directly, they live here:


H/T Zack Lovatt

Refreshing the panel without closing and reopening it

If you’re just working on your UI and not interactions with the host app, you can add a refresh link to your panel and save yourself a few clicks.

<a href="javascript:history.go(0)">Click to refresh the panel</a>

H/T Jonas Hummelstrand

Want to talk to a bunch of devs?

Join the Motion Design Artists Slack. We’re all figuring this out together and happy to help.



HTML5 (CEP) Panels for After Effects: two engines for the price of one

As I mentioned in my previous post, one of the keys to CEP panels is that they contain two distinct Javascript engines: the more modern one that runs and interacts with the panel UI (in what’s basically an embedded Chrome window), and the ExtendScript (JSX) engine, which is based on an older version of Javascript and interacts with the host application.

They’re asynchronous, which means they’re perfectly happy to ignore each other and run on their own thread at their own pace. But a UI that couldn’t talk to the host application wouldn’t be very useful, so this post is all about getting the two engines to work together.

Sending data from one to the other can sometimes feel a bit like this:

There are a few tricks to make it easier, though, and to make sure the data’s being sent at the right time.

Calling ExtendScript functions from Javascript

You’ll probably need to do this a lot. But I have good news: it’s easy!

There’s a special function, evalScript(), included with CEP’s CSInterface.js library that enables you to call both embedded ExtendScript and functions saved in a separate file. It’s good practice to separate them (and means you won’t have to do all your AE scripting within quotes!).

  1. Include your .jsx file in CSXS/manifest.xml, like so:
  2. You need to reference the CSInterface library in order to use its functions, so make sure you have
     var csInterface = new CSInterface();

    at the top of your .js file.

  3. Now you can use csInterface.evalScript() to call:
    • Embedded ExtendScript:
      csInterface.evalScript('app.project.items.addComp("Sample", 1920, 1080, 1, 1, 23.976)');
    • An external ExtendScript function:
      Include the function in your JSX file, like so:

      function addSampleComp() {
           app.project.items.addComp("Sample", 1920, 1080, 1, 1, 23.976);

      Then call it from the JS side:


Sending data from Javascript to ExtendScript

Let’s get fancier.

Note the quote marks surrounding  the ExtendScript code above. The Javascript engine sees each of those code snippets as one big string. If you need to pass the value of a Javascript variable to ExtendScript, you’ll need to concatenate strings around the variable:

var compName = "Sample";
csInterface.evalScript('app.project.items.addComp("' + compName + '", 1920, 1080, 1, 1, 23.976)');

Note that the inner (double) quotes are still there! ExtendScript strings need to be in quotes too, so you end up with quotes within quotes. This is one of the first things I check when debugging — it’s easy to forget to include the inner quote marks.

What about functions with multiple arguments?

csInterface.evalScript('setFilepath("' + pathType + '","' + result + '")');

Hmm. But I need to send a lot of data.
Pass an object of any size using JSON.stringify().

csInterface.evalScript('initRecording(' + JSON.stringify(recData) + ')');

You don’t need to parse the object on the JSX side before accessing it.

Calling Javascript functions from ExtendScript

I cheated a bit with the last example. In my actual script, that line looks a little different:

csInterface.evalScript('initRecording(' + tracktype + ',' + JSON.stringify(recData) + ')', setRecVars);

There’s a second, optional part to .evalScript(). In this example, setRecVars is a callback function. That means the Javascript engine waits for ExtendScript to complete whatever it needs to do, then lets the Javascript engine know it’s done, and that it can go ahead and execute that function.

You can call a function you’ve declared elsewhere in your script, like I’ve done in this example, or you can add a one-off anonymous function.

function callbackFunction(){
     // Do some stuff
csInterface.evalScript('someFunction()', callbackFunction);


csInterface.evalScript('someFunction()', function(){
     // Do some stuff

I’m not going to go too in-depth on callbacks here, but they are vital to CEP panel development. Not only can you do things like change your UI based on the comp you just created, you can chain a bunch of these functions together and pingpong your way across the JS-JSX divide.

Sending data from Extendscript to Javascript

The simplest method is to return a single value, and handle it with a callback function, as above.

When you need to transmit more information, things get trickier. The official documentation suggests an elaborate process involving the use of the plugPlugExternalObject library to dispatch events with payloads. You can ignore those recommendations, and simply send send data from JSX to JS as stringified JSON.

Well, I say “simply” but there are two big caveats:

  • JSON isn’t built into ExtendScript, so you’ll need to download the library and include it at the top of your JSX file:
#include "../js/libs/json2.js"
  • Much more confusingly, JSON.stringify() doesn’t like packing up “circular values” — values that refer to other values. For example, if you’ve shortened app.project.activeItem to a variable called theComp, sending  the JS engine a reference to a layer as theComp.layer(index) won’t work. Fortunately, Michael Delaney figured out a solution:
// Michael Delaney's fix to strip out circular functions
        function (data, out) {
            var e, k, results;
            if (out === null) {
                out = {};
            if (!data) {
                return void 0;
            if (typeof data === 'object') {
                results = [];
                for (k in data) {
                    if (k === "theComp" || k === "parentFolder" || k === "source") {
                        if (data[k]) {
                            out[k] = data[k].id;
                return results;
            } else {
                return data;

This function replaces circular references with their specific ID values. Run your outgoing object through it before returning your data object as JSON, and it should work.

return JSON.stringify(data);

On the JS side, handle the JSX data by using JSON.parse() to parse the result in the callback function. Here’s a simple example that notifies the user if an error occurred and changes a variable:

function endRecording(result) {
    returnedData = JSON.parse(result);
    if (returnedData.warning !== undefined) {
    ready = returnedData.ready;


Referring to another file from ExtendScript

I’ll add one last thing as a bonus, because it took me way too long to figure this one out.

Say you have a preset saved as an .ffx file in the same directory as your JSX file. You’d think you could just use .applyPreset(File(“presetfile.ffx”)), right?


There’s a weird quirk of CEP panels where, when you call its functions via JS, your JSX file doesn’t know its own directory. This shouldn’t be this hard, but here’s my super awesome workaround (note sarcasm):

On the JSX side:

var presetFile;
function setJSXpath(pathdata) {
      presetFile = File(pathdata + "presetfile.ffx");

On the JS side (which does know its directory):

var JSXpath = (window.location.href.substr(0, location.href.lastIndexOf("/") + 1) + "jsx/").toString();

csInterface.evalScript('setJSXpath("' + JSXpath + '")');

Not elegant, but it works.¯\_(?)_/¯


Getting started with HTML5 (CEP) Panels for After Effects

I’ve spent a lot of time over the past few months messing around with HTML5 panels in After Effects. There’s so much cool stuff you can do with them, but I’ll be honest: they’re also a lot more work to get working than standard scriptUI panels. That goes for both developers (“What is this ‘manifest file’ you speak of? Wait, there are two asynchronous Javascript engines running at the same time? And how the heck do I package this thing for distribution?”) and end users (“You mean I actually have to install this version-specific extension instead of just copying and pasting a file into a folder? And that process might involve the command line?”)

That sounds like a lot more work.

It is. So why would you want to bother?

Because you can hook into any of hundreds of thousands of Javascript and node.js libraries. You can connect your AE comps to external data or even hardware. You can build elaborate, lively UIs that are way more interactive than scriptUI panels. And everything you learn about building said pretty UIs is transferable to general web design; you’re not working in some weird specialized language. You can even make panels that span multiple CC apps — and make the apps talk to each other through them.

That sounds awesome. What are the drawbacks?

There’s very little documentation for these panels in general, and almost nothing After Effects-specific. (Though I’m trying to help by posting this.) A decent chunk of the existing documentation is out of date, too.

There’s a lot of stuff that works in one Adobe app but not others, or that only works in one version of AE. Not only are they incompatible with any pre-CC versions of AE, there are different versions of CEP (the Common Extensibility Platform, the framework the panels run on) for each application release.

There are a lot of things that seem like they should be easy to do but require workarounds. Even getting a totally blank panel to show up takes work, and possibly a registry edit.

And you’re going to have to learn a lot about callback functions.

So you still want to make one, huh? Here’s how to get started.

These panels have a standard structure and a couple required files. You can build the whole thing from scratch, copy one of Adobe’s sample panels, or use a template generator. You’ll want to give the project one of those reverse-URL-style names, e.g. com.yourname.panelname.

You’ll end up with a structure that looks roughly like this:


For AE to be able to see your panel you need a manifest.xml file. This is where you specify which applications it’s for (and which versions thereof), where CEP should look for your ExtendScript files, and other basic-but-important stuff like what your panel is called and how big it should be.

Beyond that, if you’ve ever done website design things should look pretty familiar structurally: an index.html file that loads external Javascript and CSS files.

One of the other key pieces you’ll need is a Javascript library called CSInterface.js. Remember when I said there were two engines running at once? Well, CSInterface is the bit that enables the Javascript engine that runs the panel UI to talk to the ExtendScript engine that runs the AE commands. They’re entirely separate, which is both good (you can do two things at once!) and bad (sending data back and forth can be tricky!).

My development setup (Adjust to your own needs as necessary, there’s no one “right” way to work):
  • Bitbucket/SourceTree: Unlike GitHub, Bitbucket private repositories are free for up to five users. Version control is really important, as there are so many moving parts that I find myself breaking things on the regular.
  • Bracketsit’s a nice text editor to develop in, and has a very useful extension by David Deraedt called
  • Creative Cloud Extension Builder that will create CEP extension templates for you. Once I’ve created a new panel, I move it from the directory AE wants it in to where I’ve set up my Bitbucket repository, then use Link Shell Extension to create a symbolic link from there back to the CEP folder. That way, I don’t have to deal with permissions issues, but AE still sees the extension. (Note: I’m on Windows; you can do something similar on OSX with different tools.)
  • Bootstrap as an HTML/CSS/JS UI framework. The Cyborg theme gets you pretty close to something Adobe-ish (Adobish?), though I’ve had to customize a lot of elements — panels usually need to be much more compact than websites. Bootstrap is widely used and well-documented, so almost anything you want to do with it is a quick Google search away.
  • Chrome for remote debugging (Safari used to work, but is no longer an option with CEP 6). Since I’m only making an AE-compatible panel, my .debug file looks like this (replace the extension ID with your own panel’s name):
    <?xml version="1.0" encoding="UTF-8"?> 
     <Extension Id="com.yourname.yourpanel">
     <!-- AfterEffects -->
     <Host Name="AEFT" Port="8092" />

    And hey, with remote debugging you can test CSS edits in Chrome’s dev tools and watch your panel update live in AE!

  • ExtendScript Toolkit for debugging the AE side of the code
  • Trello to track my progress

Okay, now that I’ve made a panel, how do I open it in AE? I put the folder in the right place, but it’s not showing up under Window > Extensions!

By default, unsigned extensions are hidden.  Here’s how to show them. You’ll need to do this for each version of AE/CEP you’re developing for.

Are my end users going to have to edit their registries, too?

Let’s hope not. But making sure they won’t have to means more work for you.

Once you’ve created a finished panel, you can pack it up into a signed ZXP file using ZXPSignCMD. Follow Davide Barranca’s excellent tutorial for this process. Really, go read his entire blog. There’s a ton of good stuff in there.

There are a few options for installation, some more automatic than others:

  • Distribute your panel via Adobe Add-Ons
  • Use Adobe’s command line installer
  • Use ZXPInstaller, a drag-and-drop version of the command line installer. Works well for me, even though it seems to think AE panels are Photoshop panels. It still puts them in the right place.
  • Bundle PS-Installer with your script. This will require some customization to make it work with After Effects, as it is Photoshop-specific.

Note: DO NOT use Adobe Extension Manager to install panels. It has been discontinued, and it puts AE extensions in the wrong place. While we’re at it, you may see references to Extension Builder 3. Don’t use that either. It has also been discontinued, and doesn’t support AE.

Further reading, because this post is already 1100 words long:

You’ll want to bookmark Adobe’s offical documentation: https://github.com/Adobe-CEP/CEP-Resources

There’s lots of good stuff in the cookbooks, and the links at the bottom are worth a read as well.

Hopefully that’s enough info to get you started. Panels are cool, once you’re through all these extra bits!

Next up: sending data back and forth. This is where it gets fun.