Overview

Often times we need to position elements in a grid. Maybe a sequence of images or videos, or a pattern. If we set out to do it manually, it can quickly become a pain. Even though After Effects allows you to calculate basic algebra in any numerical input field, facilitating manual positioning, it becomes incredibly tedious when faced with hundreds of items. In this part of our AE Grid Series, we’ll go over a method to setup a basic grid of items using expressions, enabling us to make instant changes to the grid layout using custom controls.

Here's an example of what we are going to build, but you can apply this technique to any layer you want:

Dynamically change the grid columns and spacing!
Dynamically change the grid columns and spacing!

Let’s get started!


Initial Setup

We are going to build a grid of numbers that will help us visualize what we are doing.

  1. Open After Effects and create a 1000px square comp.
  2. Create a Layer > New > Null Object. This will be our control layer. Rename it to something useful like "Grid Control".
  3. With the new Null selected, add 3 new Slider controls from the effects panel, rename them as follows, and set these values:
    • Columns: 10
    • Horizontal Spacing: 100
    • Vertical Spacing: 100
Slider controls in the Null Effect Controls Panel.
Slider controls in the Null Effect Controls Panel.

Building The Grid

  1. Create a Layer > New > Text and place it below our Grid Control layer.
  2. Go to the text source of the new text layer, toggle the expression field, and type index-1. Note: index returns the layer position within the comp. We want our grid to start with 1 but the current index is 2 since the first layer is our Null controller. We therefore need to subtract by 1.
  3. Now toggle the expression field for the anchor point and add the following to lock the anchor point to the center of the text layer:
l = thisLayer.sourceRectAtTime();
[l.left + l.width/2, l.top + l.height/2];

Note: Locking the anchor point is necessary to prevent any offsets. No matter the changes we make to the text later on (e.g. size, paragraph alignment, word length, etc.), the layer will remain in place. You can read more about how this expression works here: GFX Hacks: Anchor Point Expressions.

  1. Now for the main part, toggle the position expression field of the text layer and insert the following:
col = thisComp.layer("Grid Control").effect("Columns")("Slider");
sp_x = thisComp.layer("Grid Control").effect("Horizontal Spacing")("Slider");
sp_y = thisComp.layer("Grid Control").effect("Vertical Spacing")("Slider");

x = sp_x * ((index - 2) % col) + sp_x/2;
y = sp_y * Math.floor((index - 2) / col) + sp_y/2;
[x,y]
  1. Duplicate the text layer as many times as you want. Based on the values we gave to our sliders in the Grid Control, you'll see that with every new item the position is offset by 100px on the x axis up to the 10th item. The 11th item is then placed under the 1st item with an offset of 100px in the y axis. And so on... Play around with the slider controls to see the changes in real time. Note: The more the items in the grid, the slower AE will get so watch out!

Read on if you're interested in the math. Every step is explained...


How It Works

What's going on here? In the first three lines of the expression we are simply linking to the slider controls we created earlier. Note: Make sure to change the paths (or use the pickwhip) if you named those sliders differently than in this example.

col = thisComp.layer("Grid Control").effect("Columns")("Slider");
sp_x = thisComp.layer("Grid Control").effect("Horizontal Spacing")("Slider");
sp_y = thisComp.layer("Grid Control").effect("Vertical Spacing")("Slider");

The next two lines cover the math for the grid, where the x variable holds the horizontal position, and the y variable holds the vertical position.

x = sp_x * ((index - 2) % col) + sp_x/2;
y = sp_y * Math.floor((index - 2) / col) + sp_y/2;

To better understand how this works we have to look at the grid as rows and columns.

Rows and columns on a 10x10 grid.
Rows and columns on a 10x10 grid.

Note: If you want to follow along with the explanation you can modify the text source expression so that the grid of numbers starts at 0 instead of 1. Simply subtract the index by 2: index-2.

Horizontal Spacing (Columns)

x = sp_x * ((index - 2) % col) + sp_x/2;

To calculate the x position of each item we multiply our defined horizontal spacing by the layer's index. Since our text layer is below the Grid Control Null, it's index is 2. But we want the first index to be 0 as that is the starting position of our grid both in x and y, so that [x,y] = [0,0]. To achieve this we simply subtract 2 from our layer's index: index - 2. So in our example, we've set our horizontal spacing slider at 100. If we therefore multiply the first item's index (now index 0) by 100 the result is 100 * 0 = 0. The second item's x position will be 100 * 1 = 100. The third item's x position will be 100 * 2 = 200, etc.

This is what we have so far:

x = 100 * (index - 2);
Each new item is offset by 100px in the X axis, starting from [0,0].
Each new item is offset by 100px in the X axis, starting from [0,0]

The position of the first item is [0,0] but as a result, it partially falls outside the comp in both axis. Let's correct this with an offset, using our defined horizontal spacing. In our example, since we fixed our text layer's anchor point at it's center, we actually calculate the spacing to span 50px on either side of the anchor point, totalling 50px + 50px = 100px. So we only need to offset by a half of our horizontal spacing value (from the left margin). So now we have:

x = 100 * (index - 2) + 100/2;
50px offset from the left margin in the X axis.
50px offset from the left margin in the X axis

Great! Now we can keep duplicating our text layers, but we'll encounter a problem... The items, after the 10th one, keep being pushed in the x position past the comp width. In fact, the 11th item's position x (after the offset) will be 100 * (index - 2) + 100/2 = 100 * 10 + 50 = 1050 — greater than the current comp width of 1000px. We need those items to wrap back to the next row after the last column is reached.

That's where the modulus operator comes in: %! In essence, it allows us to find the remainder of a division. An example is if we want to find the remainder of 10 / 4. The closest integer to 10 that is less than 10 and divisible by 4 is 8 (8 / 4 = 2). If we subtract the product from our dividend we get the remainder: 10 - 8 = 2.

In our example we've set the number of columns at 10 — this number is our dividend. This operation is useful to us since the results always wrap. So once the 10th item is reached: (11 - 2) % 10 = 9 the 11th item will wrap back to 0: (12 - 2) % 10 = 0.

The modulo operation in detail

In computing the modulo operation, represented by the percent % symbol, actually represents this equation: a - floor(a / b) * b. So in our example, when calculating the remainder of the 10th item (with index 11 - 2 = 9), we use: 9 % 10 = 9 - floor(9 / 10) * 9.

The floor() method rounds down the content of the parenthesis (called arguments), so we get: floor(9 / 10) = floor(0.9) = 0. In conclusion, the result is: 9 - 0 * 9 = 9.

Note: due to the order of operations in algebra, where the multiplication is prioritized over the subtraction, this equation should be read as: 9 - (0 * 9) = 9.

So for the 11th item (with index 12 - 2 = 10) the remainder is: 10 % 10 = 10 - floor(10 / 10) * 10 = 10 - (1 * 10) = 0.

If we duplicate the text layers now we won't notice a difference after the 10th item as they then start to overlay each other. Let's move on to the vertical spacing to separate the rows.

Vertical Spacing (Rows)

y = sp_y * Math.floor((index - 2) / col) + sp_y/2;

Calculating the y position works similarly to calculating the x position: by using the index of the layers to step increment the spacing.

Let's commence by multiplying our defined vertical spacing by the layer's index, and applying the offset — this time from the top margin.

y = 100 * (index - 2) + 100/2;
A 50px stacked offset is applied to each new layer.

What we get is a diagonal since the vertical spacing value is directly multiplied by the index, that increments with each layer: 100 * 0 = 0, 100 * 1 = 100, 100 * 2 = 200, and so on...

To correct this we need to divide the index by the number of columns. This way we get 100 * (0 / 10) = 100 * 0 = 0 for the first layer (index 0), 100 * (1 / 10) = 100 * 0.1 = 10 for the second layer (index 1), etc...

This causes a 10px step increment in the y position with every new layer, so we still get a diagonal pattern. What we want is to force the step to happen on every 11th item instead of on every single item. We accomplish this by using the floor() function to round a decimal value down.

Note: Notice the Math before the method floor(). Math is a Javascript object that holds a variety of maths methods. Since floor() is a method that belongs to Math we have to specify both in that order. For a complete list of supported functions see: Mozilla Developer Network - Math

In our example we'll use this function to round down the decimal results that we get from dividing the index by the number of columns. In practice, we now have Math.floor(0.1) = 0 for index 1, Math.floor(0.2) = 0 for index 2 and the result will be 0 for every other layer until the 11th. In fact, for layers 1 to 10, the decimals we get from dividing the index by the number of columns are: 0.0, 0.1, 0.2, 0.3...0.9 — each of those rounded down will result in 0. Dividing with the 11th layer's index instead (index 10), we'll get 10 / 10 = 1.0, so from there until the 20th layer (index 19 where we get 19 / 10 = 1.9, the y position will always be 100 * Math.floor(1.0...1.9) = 100px. From index 20 to 29: 100 * Math.floor(2.0...2.9) = 200px, and so on...

y = 100 * Math.floor((index - 2) / col) + 100/2;
A grid of 100 items.
A grid of 100 items.

Conclusion

We've looked at how to quickly build a dynamic grid of items using the power of expressions in After Effects. You can apply those expressions to any type of layer, although in our example, the spacing will be the same for each item. In our next AE Grid Series article, we'll explore how to create responsive grids, that adjust their size to always fill the comp — creating a mosaic.


Additional Resources

Further reading on anchor points:

Anchor Point Expressions in After Effects
A quick tutorial on using the sourceRectAtTime function in After Effects to fix the anchor point of a layer to a specific point. Especially useful when working with text or shape layers. Lower thirds anyone?

Understanding the modulus operator:

Understanding The Modulus Operator %
I understand the Modulus operator in terms of the following expression: 7 % 5This would return 2 due to the fact that 5 goes into 7 once and then gives the 2 that is left over, however my confus...

List of all Javascript Math function, including Math.floor():

Math
Math is a built-in object that has properties and methods for mathematical constants and functions. Not a function object.

Other articles in our AE Grid Series:

AE Grid Series - Graphic Hacks
Our AE Grid Series explores how to build different kinds of dynamic grids in After Effects using the power of expressions.