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:

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.

FRONTLINE: Inside Assad’s Syria premieres Tuesday 10/27

I recently created the graphics for an upcoming FRONTLINE episode, Inside Assad’s Syria. It premieres next Tuesday at 10PM, and will be free to watch online after.

All eyes are on Syria as Russia’s military campaign intensifies, and as tens of thousands of refugees continue to flee the war-torn country for Europe.

What is life like for those who are left behind?


Free After Effects Script: Incremental Screenshot

I got lazy about exporting a title sequence, and put together a quick little After Effects script. It’s nothing fancy, but it works and might come in handy.  It saves still frames from your active comp’s work area on an incremental basis (e.g. one frame every x seconds), with a filename based on the topmost active text layer at that time.

Download Incremental Screenshot v.0.0.3
Drop this script in the folder you want to save to, adjust the settings at the top to your preference, then run it from File > Scripts > Run Script File.

Works in Windows on CC2015, assume it works elsewhere but I haven’t tested it. It probably won’t make your computer catch fire, but run at your own risk.

Also, thanks to renderTom for pointing me toward saveFrameToPng!

Why does Credits Are Due require AE CC2015?

I’ve had a bit of press and some very nice feedback on my new script (thanks everyone!). If you’ve bought a copy and want to show off things you’ve built with it, get in touch.

A couple people have asked why it’s only for CC2015, though. There are two big reasons:

Credits Are Due makes use of the new sourceRectAtTime() expression method. I love this feature: it lets you access the dimensions of layers with dynamic borders, which makes it possible for the text layers in Credits Are Due to know how much space to leave for their neighbors. The script essentially works by measuring all the layer heights, spacing things out accordingly, then scrolling the parent layer. (There’s also a cameo by my favorite little expression hack, setting posterizeTime() to a super-low value like .00001. This lowers the expression’s effective framerate to almost nothing, so you get live updates when the comp is edited without having to recalculate layer dimensions on every frame.)

But sourceRectAtTime() was added in the most recent update to After Effects CC2014 (13.2). So why can’t you use that version with Credits Are Due? Well, you can render your credits in it. But if you try to edit them, you’re gonna have a bad time. Every layer in the comp needs to scroll, so as soon as you add a new one that’s not yet linked, you’ll spend most of your time clicking through “expression disabled” popups. Even more fun: manually re-enabling all those expressions once the new layer’s been added to the scroll.

However, CC2015’s new expression handling means things Just Work. Expressions re-enable themselves automatically as soon as they’re able. No more popup error windows. I could probably add a bunch of checks to skip non-scrolling layers and make the math still work, but I want to keep the code to a minimum — expressions can be slow to calculate (though they do seem faster in 2015), and a couple hundred layers into a project you really start to notice. Temporarily disabling the scroll during setup seems a small price to pay for faster playback — particularly when you have a client standing over your shoulder making changes.

tl;dr: new stuff in CC2015 makes Credits Are Due work in a way that won’t make you want to stab yourself in the face. Which, when you’re already stuck making a credit scroll, is important.

Credits Are Due

Credits Are Due: New After Effects script in progress

I’m working on a new After Effects script for building responsive, easy-to-edit credit scrolls.

  • Dynamic layout: rearrange, restyle or reclassify existing elements,  or add new ones anywhere in the scroll, and everything will snap into place and update accordingly — and leave your custom text formatting alone.
  • Automatic arbitrary multicolumn layouts (say that five times fast)
  • Add images and footage as well as text
  • Scroll in whole-pixel increments
  • Change global scroll speed, position and element spacing
  • Speed up previews and rendering by auto-trimming layer duration to match on-screen visibility.

It’s still missing snazzy icons and the ability to grab existing elements by type (which I’m totally stealing from Layer Selector Toolbar), but everything else pretty much works.

Want to see it in action? Check out these incredibly dull screencasts:

Editing an existing sequence:

Includes cameo by world’s slowest layer trimmer, only outdone by my earlier version of said layer trimmer!

Creating a new sequence: 

You can also add text and image layers by any other method — once they’re in the comp, just assign them element types and they’ll scroll happily along.


This tool takes advantage of the recent changes to expressions in AE, so it requires CC2015 or the 13.2 version of CC2014. (And is much nicer to work with in 2015).

Credits are never fun, but this should take some of the pain out of the process. If you’re interested in beta testing, get in touch.

Documentary Animation | Motion Graphics | Design