Category Archives: Graphics

Personal projects and the occasional bit of commentary.

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:

<CEFCommandLine>
 <Parameter>--allow-file-access</Parameter>
 <Parameter>--allow-file-access-from-files</Parameter></CEFCommandLine>

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:

%localappdata%\Temp\

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.

 

IMAG0601

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:
     ...
     <Resources>
          <MainPath>./index.html</MainPath>
          <ScriptPath>./jsx/hostscript.jsx</ScriptPath>
     </Resources>
    ...
  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:

      csInterface.evalScript('addSampleComp()');

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);

vs.

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) {
        alert(returnedData.warning);
        return;
    }
    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?

NOPE.

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");
 }
targetLayer.applyPreset(presetFile);

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.¯\_(?)_/¯

cepheader

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:

CEP-structure

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"?> 
    <ExtensionList>
     <Extension Id="com.yourname.yourpanel">
     <HostList>
      
     <!-- AfterEffects -->
     <Host Name="AEFT" Port="8092" />
    
     </HostList>
     </Extension>
    </ExtensionList>

    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.

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!

handMade hand track nulls

Script in progress: a Leap Motion recorder for After Effects

I’ve been building a tool for recording 3D motion tracks, camera moves and hand gestures direct to the After Effects timeline with the Leap Motion.

There’s still a ways to go yet on development. I have to create the UI and tweak the hand puppet rig (and, um, make the hand tracker work with right hands…), but I think this is going to be a useful addon for both literal hand-animation stuff like UI demos and pre-animating gestures for Character Animator puppets, as well as more subtle things like organic camera shake.

The Leap is quite precise in its data — you can even tell different people’s hand tracks apart.

Hand:

Shaky camera move:

I’m thinking about calling it handMade. Good name?

Interviews

Generate quick interview backgrounds with Archimesh for Blender

Here’s a puzzle:

You’re working on a science documentary where all but one of the interviews were shot on green screen — in different locations, with different lighting setups, different cameras/lenses with different operators. Some of them are over or underexposed and the blown out or crushed areas of the footage are unrecoverable. No background plates were shot, and none of the stock imagery you have to work with matches the lighting or camera angles. Quick, make the interviews look like they’re in ten different locations yet belong in the same film. 

Solution: throw together a couple of CG “science” “labs”, and make ’em super blurry so no one can see how simple the geometry is.

GMO-interview-contact-sheet

(Note: these, and all the images in this post, are raw test outputs. The films haven’t been onlined or color corrected yet.)

I didn’t have a lot of time on this, but Antonio Vazquez’s Archimesh add-on for Blender makes it possible to build interiors very, very quickly.  Blender is definitely not my favorite 3D application, but there’s nothing like this add-on available for C4D. And Archimesh is free!

1. Enable three Blender add-ons: Archimesh, IvyGen and Sapling. Fake up some lab/office interiors with Archimesh (some great how-to videos here), then add some plants with the other tools. (Gotta have plants. It’s a documentary about plants, and these folks are pretty much all plant scientists. )

blender1

2. Export the geometry to C4D. Play with the materials, match camera angles and lighting to interviewees, then render out of focus. I only built a couple rooms for ten interviewees, just moved the camera around and changed the colors. It would be pretty trivial to adapt this setup for multicam interviews.

c4d1

int-BG

3. Composite and tweak color in AE. compositetest

As long as your final result is this blurry, your ivy can just be a bunch of square planes, and no one will ever know.

 

 

Iraq Map

Recent broadcast work: FRONTLINE: The Rise of ISIS

I designed a bunch of maps back in October for FRONTLINE: The Rise of ISIS. It’s free to watch online at the link. It got great reviews and I think is very much worth seeing, but a word of warning: this film contains some very graphic footage.

Mapping Arabic-speaking parts of the world turned out to be unexpectedly challenging: there are multiple ways to transliterate pretty much every place name, and good luck guessing which one your geolocation service has selected.

But there are perks to focusing on a region with such a long history. It was pretty cool finding ancient hand-drawn maps of Baghdad alongside OSM street data and satellite imagery.

Baghdad - Abu Ghraib v05

I learned a ton about QGIS working on this, too. I’d never done much with raster map data before, so this was basically Baby’s First Hillshade. In hindsight, as much as I like the final look there were definitely things I should have built differently — I ended up with a super-wonky workflow for adding new city points and one map in particular with insanely long render times.

Let’s hope the upcoming GEOlayers plugin for After Effects smooths out a lot of that process.