David Unaipon Ngarrindjeri man and early hacker

The global object in After Effects

It’s all about the $.

One of the undocumented expression language feature in After Effects is the global object, also known as $. And it turns out that $ can bring you happiness…

$ is a mysterious “Helper Object” that is available to extendscript and used to do things like find the current version of the application, or what the user’s name is. But it also appears to be available for use in expressions. This turns out to be very handy.

I’ve been researching the $ object and its members, but apart from accidentally discovering that there’s a blink() function for strings (hilariously it works, but not in the way that anyone who ever had a geocites account thinks), I haven’t found too much to get excited about.

In the scripting world, for example $._ADBE_LIBS_CORE.getCurrentUser gives you all sorts of data about the current user’s Creative Cloud account. That doesn’t work in expressions. So what is $ actually good for?

Think Globally

Because $ is a global object, it’s available to all expressions. And since it’s Javascript we can just hot-glue properties and methods on to it whenever we like. Here’s an example: the source text of the text layer is controlled by a variable on the solid layer.

screenshot of After Effects showing expressions

So on the solid layer we have this expression:

$.myVar = "It Works!"

In the above code we assign a property to the global variable just by initialising it. I always find it weird how you can do that, but you can. So now the $ global variable has a property called myVar which has the value "It Works!".

The next line, value is just there to avoid an expression error, it simply sets the value of the property to whatever the property was going to be anyway. You can see it’s on the position property, but the function we define has nothing to do with position, in fact it returns a string of text.

On the text layer we have this expression:

if($.myVar){$.myVar} else {"nope"}

This checks to see that $.myVar has been defined and has a value (other than null, false or 0) and if so, it uses it as the source text of the text layer. If myVar was not defined the text layer would say nope.

This doesn’t do anything radically different than you could have achieved using expression control effects and a lot of pick-whipping, but it would be super convenient for global styles for a whole project. Say you had a colour pallette and you wanted to be able to update it easily. Just create an object like this

$.myStyle = {base: 
        {fill: [123,45,67], 
        stroke: [23,45,6],
        lineWidth: 3},
    accent: {fill: [255,128,12],
        stroke: [23,45,6],
        lineWidth: 3}

And of course you could make the global style object as complicated as you like: specify as many properties as you like, then call them up from expressions like this:

$.mystyle.base.fill; // returns [123,45,67]

It’s kinda like CSS for AE. I originally didn’t think it was that useful, but that seems like a pretty exciting development. But here’s where I think it gets really fun (ok, I’ve got a low threshold for my definition of fun):

Here comes the Func

Because you can pass a function as a variable in JavaScript, you can do something like this:

multiple text layers in after effects controlled by a single function

Here, the variable myFunc is a function that takes one parameter foo. All of the text layers are duplicates of each other, but because the function is executed independently on each one, it returns different results. This is the expression that creates the global function:

$.myFunc = function(foo){
	seedRandom(foo.index, timeless=true);
	return "index: " + foo.index + 
	", red solid index: " +	index + 
	", random: " + Math.round( Math.random(index* 100));

The parameter foo is expecting a reference to a layer (I should have named it better, I know) and returns a string with: the index of the layer referred to by foo (specified by foo.index), the index of the layer where the function is defined (just index), and a random number.

In the text layer the variable foo is assigned the value thisLayer which is a reference to the text layer itself. So foo.index equates to thisLayer.index. This is necessary because if we just used index as demonstrated by the next line, it returns the index of the layer where the function is defined. So this is important. Any function that uses properties of a layer needs to be explicitly told what layer it’s referring to.

Similarly the random number is different on each one because the seed is foo.index, which evaluates differently on each layer.

One function to rule them all

So as you can see each layer is evaluating the function separately to achieve different results—but they’re all using the same function. If I change the expression on the red solid they will all update their behaviour instantly without me having to copy and paste new expressions. This is a massive time saver for procedural animation where you might have scads of layers with hard-to-get-at properties controlled by expressions.

Some caveats

  • This is a rather experimental approach, and may get patched out of existence in updates of AE, so don’t rely on it to fly your aeroplane or run your nuclear weapons system.
  • If you use an expression like $.myVar = time you would expect $.myVar to equal the current time of the composition. Not so. The value of $.myVar in that code is set at the point the expression is evaluated, and not refreshed when the playhead moves. If you want to use time you’ll have to use it in a function. A trivial example: $.compTime = function(){return time}
  • variables persist when they’re deleted or renamed. At least until you close After Effects. This can cause weirdness and means that you could accidentally delete a variable that you’re using in another layer and it will keep working until the next time you open up the project, when it will be mysteriously broekn.


This page does mention the $ object and notes that there are three supported uses,

  • $.build – returns the build of After Effects,
  • $.engineName – the name of the expression engine, which in the current build turns out to be torq/v8, the Javascript engine from Chromium, surprise surprise and
  • $.global – which obviously needs further investigation

So if I look at the members of $.global this is what I get:

Object, Function, Array, Number, parseFloat, parseInt, Infinity, NaN, undefined, Boolean, String, Symbol, Date, Promise, RegExp, Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, JSON, Math, console, Intl, ArrayBuffer, Uint8Array, Int8Array, Uint16Array, Int16Array, Uint32Array, Int32Array, Float32Array, Float64Array, Uint8ClampedArray, DataView, Map, Set, WeakMap, WeakSet, Proxy, Reflect, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, unescape, eval, isFinite, isNaN, SharedArrayBuffer, Atomics, WebAssembly, thisComp, value, effect, ProxyBase, _makeProxy, __add, __sub, __mul, __div, __unprepareContext, __prepareContext, Comp, Footage, Group, Layer, Camera, Light, Effect, Mask, Property, PathProperty, TextProperty, MarkerProperty, Key, MarkerKey, Custom, Project, $, thisLayer, thisProperty, __internal_expression_state, constructor, __defineGetter_, _defineSetter_, hasOwnProperty, _lookupGetter_, _lookupSetter_, isPrototypeOf, propertyIsEnumerable, toString, valueOf, __proto, toLocaleString

I got all hot and bothered when I saw console in there, and using $.global.console.log("hello"); works, in that it doesn’t throw an error, but I can’t find where the console it logs to is. It’s not the text in the info window like I was hoping, and it’s not the console in ESTK. Drat.

Interestingly all the variables that I’ve defined in any expression turn up inside the $.global object, except if they were defined with let. However calling these variables like $.global.myvar doesn’t return anything.

to be continued…

If you’re wondering who the image at the top of the page is, it’s David Unaipon, Ngarrindjeri man, Australia’s Da Vinci, and old-school hacker. He’ll be recognisable to Australians as the bloke on the $50 note, hence the connection: hacker and dollars. This blog is written on the stolen lands of the Wurundjeri people of the Kulin Nation, where sovereignty was never ceded. Always was, always will be.

Leave a Reply

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