What reverse-engineering the Wiggle() function taught me about computational nondeterminism, quantum mechanics, and the inherent humanity of randomness
Like any good design program, Adobe After Effects is its own universe governed by its own laws. There is no gravity, only anchor points. There is no inertia, only keyframes beyond the playhead. There is a third dimension, but you have to open a separate window to control it.
It’s a motion design program often described as a cross between Photoshop and Premiere Pro, though it follows neither the naming conventions nor organization of either. You can layer various elements within a file, known as a composition, and leave keyframes at various points along a timeline to make transformational changes to the layers. But much like its brethren Adobe programs, it’s needlessly, gorgeously complicated. There’s a motion graph that requires knowledge of linear, quadratic, and bézier interpolation. There’s a secret settings menu that you can only access with a special key command that allows you to override export settings. There’s a drop-down option for each layer transformation in which you can write lines of JavaScript. (This part, to me, has always been hilariously clunky.) They show up in monospace font and look completely out-of-place from the world in which the rest of the program exists. But the first time I used one, JavaScript was so daunting that a single line of it, executed simply and perfectly, made me feel like an accidental genius.
This first line of code — wiggle(a, f); — is still my most-used expression to this day. (There was even a brief stint, as an Adobe contractor, in which I wrote a tutorial on how to use it.) When applied to a layer’s position, the expression would move this layer a “random” number of pixels away from its original location. Provided a multiplier (a) and frequency (f), you could customize this motion to be more or less dramatic. Applied to scale or rotation, you could resize or reorient an object in a similarly unpredictable fashion. And with slight modifications or additions to the code, you could add a frame rate, set a duration, and even create a seamless loop. But the part that made it great was the randomness, the only part you couldn’t control, the small thrill of an unexpected outcome. In a program in which a designer is in charge of every small decision, it is freeing to leave some things up to chance.
But at some point within the blur of edits and exports, I realized that the effect wasn’t always changing. Sometimes, two exports of a Wiggle would start to look identical. And the questions began to arise: Was the wiggle effect truly random? How does a computer even define randomness? Is a composition in After Effects predetermined?
This weekend, I was bored enough to find out.
Determinism, digitally and otherwise
Outside the world of computers, determinism is a philosophical view that has long enchanted authors and philosophers. Hear Cassius in Shakespeare: “The fault lies not in our stars, but in ourselves.” Then Dostoevsky’s Grand Inquisitor: “Nothing has ever been more insufferable for man and for human society than freedom!” And Vonnegut’s Slaughterhouse Five, “All moments, past, present and future, always have existed, always will exist.” It is a question central to the meaning of life to wonder if our futures are inevitable or controllable at the hands of society, God, or some greater force of logic beyond our comprehension.
The question seems so large that it becomes overwhelming, but fortunately I will only be answering the smallest sliver of it today, the sliver being: does determinism touch the Adobe Creative Cloud motion design program After Effects?
Within statistical probability, determinism describes processes in which the results can be predicted beforehand, with proper knowledge. Nondeterminism becomes a synonym for random. And when applied to computers, these terms become a dividing line for number generators. There is a deep rabbit hole down which to fall here, and at the bottom lies the murky truth: on a computer, there is really no such thing as true randomness.
(Note: True randomness does, in fact, exist in the form of quantum phenomena. Which, as far as I know, is not embedded in Adobe After Effects, so I will not be discussing it.)
Two ways to be random
Randomness, for the purposes of this experiment, will be defined as a string of values without a perceivable pattern. Because this is useful for a lot of applications, most programming languages are built to include randomness as a function. (Which I've known since my early days in Scratch.)
After Effects was written in C and C++. In this language, randomness — often in the form of a rand() function — is crafted using a “pseudo-random” number generator (PRNG). The program generates a value using a seed number and an algorithm, specifically written to lack a noticeable pattern.
There is, however, a nondeterministic number generator in C++ as well. It’s called random_device, and it uses stochastic processes to generate something generally believed to be the most random set of values computers can achieve. These processes take pre-existing sets of externally-controlled numbers — the stock market, map coordinates, live image data, a bacteria sample — and form a complex algorithm based off of them. This is an example of a true random number generator (TRNG). (Random.org, often thought to be the most random generator in existence, uses atmospheric noise.) Even the most complex TRNGs are drawn from existing data. The variable that makes the output ‘random’ is the time at which a user ran the command.
Schrödinger’s composition
My hypothesis was that After Effects used a PRNG to create its ‘random’ sequences, Wiggle included, using “time” as an offset variable or seed to ensure variety between multiple effects within the same composition. This would create the effect of randomness for any productive purpose, but if rendered infinite times, would create the same result every single time.
In keeping with the theme of fate, I decided to test the theory with stars. With five points and valleys, they were a good shape with which to notice visual differences in motion in four cardinal directions. I created a five-second-long composition and imported the star, centered perfectly within the square frame. Then, I applied the wiggle effect as seen below.
f = 4; a = 15; posterizeTime (f); wiggle (f, a)
Wiggle() can take up to five variables, only the first two of which are mandatory. In this example, a is the amplitude, or “craziness” of the wiggle and f is the frequency (which, through the posterizeTime() expression, also becomes the frame rate). I decided to use a low frame rate to make the differences in each movement more stark. But also, selfishly, because that’s often how I use it in my own videos. It just looks cooler this way.
The first export of the video was the Control Star. All further videos would be compared to this one after the study was complete by overlaying them with a multiply effect (also in After Effects) and looking for overlap between the two. To make things visually easy, the Control Star was blue and all later stars were yellow so that the overlap between both appeared green.
I always use Adobe Media Encoder to export my animations from After Effects, but I did test different export programs beforehand to make sure this wasn’t altering the appearance of the wiggle. As I had hoped, exporting directly from AE or screen-recording the composition straight from the program yielded the same result as sending it to AME.
I conducted a series of tests on my yellow stars. I compared the control star to... (1) one whose composition had been copy-and-pasted (2) one whose layer had been copy-and-pasted (3) one whose entire string of JavaScript was deleted and manually retyped (4) one who was created after shutting down After Effects, opening a new file, and restarting with the same parameters.
I had assumed that, somewhere along this journey, I would end up with a different outcome between these trials that would allow me to further hypothesize the specific variables that crafted Wiggle's backend code. After all, there were new “instances” of applying the wiggle effect in each one of those tests. But unfortunately, none of these methods resulted in anything other than the exact same dance. Insanity is doing the same thing over and over and expecting different results. Using After Effects is doing the same thing over and over and actually getting them.
By this point, I had enough data to make a rough estimate of how the effect was built in C/C++. Since the wiggle’s array of variables doesn’t change with a new implementation, one can assume there is some kind of predetermined list of pseudo-random values from which the expression pulls. I use the word “list” quite generally, since it is likely that instead of hard-coding an array [1, 5, 2, 4, 9, 0, 4, 8, 8, etc.] that After Effects uses some kind of formula to determine the next number [xn + 2, xn - 2, repeat, etc.].
This falls firmly in the basket of a PRNG, but it left me wondering: if a pseudo-random number generator is meant to be altered by a seed, why wasn’t mine changing? It was time for the second stage of the test: having multiple wiggle effects within the same composition.
The fault in my stars
One of the first tests I conducted was to copy-and-paste a new wiggling star within the same layer. At the time that I did this, I noticed something peculiar, but I was at such an early stage of exploration that I didn’t realize until later that it would become the crux of my discovery.
The fascinating detail was this: I’d paste the new star on top of the old one — and, as one might hope from a program designed to include multiple wiggle effects — the new star landed in a new position than the first. However, when I deleted the control star, the new star bounced back into the position of the first one.
It was perplexing at first. Why would the seed change at first, but revert to its old behavior once there wasn’t another star to contrast it with? Was there some kind of built-in failsafe that would change the effect in the presence of other effects, in order to maintain an appearance of randomness? Was it possible that the seed was number of wiggle effects in a composition?
I began adding useless layers to the project: first more stars with wiggle effects, but then null layers, solid colors, unmoving squares, text boxes. Every single one of them altered the position of the control star. I began to wonder if the independent variable was number of layers (n).
When I duplicated the background layer, though, nothing changed. It was only when I added a new layer on top of a star that its behavior switched. And because After Effects counts layers from the top down, things started to make sense. Invigorated, I tried moving the star upward in the layer panel, placing it on top of some of my unnecessary test objects. One, two, three times: and each time, it shifted positions as I had expected. A shaky understanding — literally — emerged: The seed value was not number of layers (n) but instead index within that number (i).
From a design standpoint, this would make sense as a function of Wiggle: no two shapes can be on the same level within the layer panel, and so each wiggle will always be unique if defined by its index.
I was able to confirm this with anonymous commenters on AE help forums. In a 2018 post, one user had created an animation and attempted to move static layers to interact with a wiggling one. The only problem was, every time he’d make a new object, everything would shift positions. But instead of embarking on a two-thousand-word quest to analyze the inner workings of Wiggle, this query was solved by one commenter casually mentioning that the Wiggle algorithm is based on the layer index (“and a few other things.”)
Unhelpfully, he ended his comment with, "read the help on this subject," even though no such help existed after hours of searching. But helpfully, he referenced seedRandom(). You can use alter the wiggle effect with this string in order to freeze it with its initial array of variables. (School of Motion has a great explanation of how you can enter “index” as a variable here to maintain some variety across multiple layers, though at that point, you're basically rewriting the Wiggle effect as it is designed in the first place.)
Conclusion
In practice, the only real takeaway is that it’s never going to make a difference to export something with the Wiggle effect multiple times “to see if it turns out cooler.” It will not be cooler. It is always going to be exactly the same, unless you add more layers to the composition.
But in theory, this was an interesting foray into the world of computational nondeterminism and the way in which machines fabricate randomness. Even though programmers have achieved something so complex as to seem random, the fact that it isn’t truly drawn from nothing is a fascinating field in which nature will always win. “God may play dice with the universe,” someone said on Stack Overflow. “But they are the best dice in the universe.”
This isn’t to say that After Effects’ dice are rigged, but more that it doesn’t have hands; it asks you to roll for it every time you add a layer to your composition. In a way, there is a comfort in knowing there’s one game we will always win. If I learned one thing at all, it is that there is nothing more human than being truly random.
If you made it all the way to the end, thanks for reading. Feel free to share more knowledge here about computational nondeterminism, quantum mechanics, or Adobe After Effects.
Thank you!