My First After Effects Script

Having set myself the task of learning After Effects expressions, I of course got distracted and started learning Unity again, and probably some other things too. But for once, I managed to pull myself back and focus on After Effects again when I ran into a problem that forced me to learn something new (by far the best way of learning things).

Following on from my last post, I’ve been working on an animation that uses outlines, and again I needed them to stay consistent. Like last time, I planned on doing this with a simple expression which would be applied to each “Stroke Weight” property throughout the composition. Simple enough, but the problem was, well…

…there were a lot of them. 2952 to be exact. I’d thought maybe I could speed things up by just having one stroke for each layer, but that didn’t seem to work. That’s when I turned to ExtendScripts.

ExtendScripts are basically bits of code that control After Effects (or other Adobe programs). You can use them to automate processes that could otherwise take hours to do, especially repetitive things, like adding the same expression over and over again. They’re written in JavaScript, and Adobe offer their ExtendScript Toolkit which is a simple IDE that connects directly to other Adobe Software, so it’s ideal for testing.

Learning scripts

I already have a little programming experience, but if I hadn’t this would have been a great starting point. JavaScript is quite easy to write compared with the Java and C# that I’ve done before. There’s also some really great resources for learning:

David Torno’s ExtendScript tutorials were a really great starting point. He too hadn’t been a developer beforehand, and even includes some introductions to basic concepts of JavaScript in his first episodes. In just a few hours I had a grasp of how the After Effects Object Model works, and how to create basic scripts.

Aenhancers.com’s docs are also a life saver. Here you’ll find references to all the different classes and properties that After Effects has to offer. Aenhancers.com itself is also really useful; a forum full of other script writers who have shared their own work and experience.

How scripts (and After Effects itself) work

Learning scripts has given me a new view of After Effects. I guess it should be obvious, but as a piece of software, everything that you do in After Effects is represented as some kind of line of code somewhere. Normally we don’t see this, we just drop keyframes and layers and whatever else and we focus on the visual representation. But each of those keyframes and layers has a reference in the background, explained by the After Effects Object Model.

The After Effects Object Model

It’s a simple hierarchy of objects and items that exist within AE, allowing you to reference anything with scripts. For example, if I want to access the rotation of the first layer inside the active composition, I can refer to that as

1
app.project.activeItem.layer(1).property(“Transform”).property(“Rotation”);

It didn’t take long to get my head around how it works, and I was able to make my first script.

The script

Not happy with the idea of copying and pasting the same expression 2952 times, I decided to write a script that would do it for me. All it needed to do was find the “Stroke Width” property and set the expression.

The problem however, was that while we can find a property using the above hierarchy, that specific property could be almost anywhere. Shape layers have contents, contents have groups, sometimes groups have more groups; there was no direct path.

The solution was a script that would cycle through all of the properties looking for groups and adding them to an array. It would then check those groups for groups, and add those groups to the array, and it would do this continuously until it found single properties. Finally it would check the name of that property and if it was called “Stroke Width”, it added the expression.

Don’t worry, I’ve included the script below for your copying pleasure

So that was it! 57 lines of code and I could save myself who knows how many hours, and had it ready for any time I needed it.

I also found an expression from Adam Plouff which was an improvement on my own; overcoming the “Scale to 0” problem.

And it works!

And here’s the script…

Feel free to use it, play with it, change it up. It’s definitely not the most efficient script, so I’m open to suggestions of how to improve it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
app.beginUndoGroup("Stroke expression");
var layers = new Array();
var props = new Array();
var total;

//get selection
layers = app.project.activeItem.selectedLayers;
total = 0;

//loop through layers
for (i = 0; i < layers.length; i++){
var lyr = layers[i];

//if it's a shape layer...
if(lyr instanceof ShapeLayer) {

//loop through properties
for (p = 1; p <= lyr.numProperties; p++){
var prop = lyr.property(p);

//find contents and add to array.
if (prop.name == "Contents"){
props.push(prop);
}
}
}
}

//once all "contents" properties are found, cycle through array
filterProps();
alert(total + " expressions written!");

//cycles through all array items to find individual properties within nested groups
function filterProps(){
for (p = 0; p < props.length; p++){
var prp = props[p]

//if the property is a property group, add all of it's properties to the end of the array (other common groups excluded
if (prp.numProperties >= 1 && prp.name != "Material Options" && prp.name !="Transform" && prp.name != "Geometry Options"){
for(p2 = 1; p2 <= prp.numProperties; p2++){
props.push(prp.property(p2));
}
}
//if the property is a stroke width, add the expression.
else if(prp.name == "Stroke Width"){
prp = addExpression(prp);
total++;
}
}
}

function addExpression(prpt){
prpt.expression = "value / length(toComp([0,0]), toComp([0.7071,0.7071])) || 0.001;"
return prpt;
}

app.endUndoGroup();

Next steps

I’ve found this whole process pretty interesting and I can see a lot of potential in where I could go with it. There’s a few improvements I already have in mind that I think I’ll get started on straight away:

  • Create a user interface
  • An option to customise the expression being used
  • An option to choose which property is targeted
  • An option to apply a value instead of (or as well as) an expression; e.g. setting the initial stroke width
  • Maybe find a way to make it more efficient?

I’ll keep you updated!

Share
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.