Ae

Dynamic Split-Flap Display (Loki Disney+)

Hard

Just a heads up, the video tutorial code incorrectly includes “this.” as part of the expressions. If you’re using AE CC it will break. Just don’t include “this.” where is might say to, and you will be fine. The tutorial below has been updated to be correct….

 

Thanks for helping me hit 5,000 subscribers. Loki Season 2 just came out, so it’s time I finally tackled one of the most surprisingly complex dynamic builds I have attempted to date, just for you.

The split flap display.

It’s that iconic look of a display synonymous with airports, train stations, and that one demon clock from Groundhog Day. Ahh, shh! More recently you may have seen it in the trailer for the Netflix mini-series Bodies, or more likely… in what we’re basing our build off today… Loki.

If you didn’t catch my previous Loki motion graphics build, we created the timeline slider often seen with the split flap display, here’s the link for that one.

In this video though, we are making a dynamic split flap display in After Effects that emulates the look we see in the series.

There were a number of ways to make this work in Adobe After Effects, but you know me, I like to give you builds that result in an unprecedented level of control, so let’s highlight what is going to be unique about what we build today.

This will be a long tutorial but at the end of it all we will have one powerful split-flap display creation.

1st Composition - Letters

We’ll start with a new Composition and call it “Letters”. We’re going to make it portrait, so width 1080px and height 1920px. Set the framerate to your usual, we’ll go 25. We’ll make the duration 16 seconds and set the background to black.

We’re going to create a new text layer, type “W” as the letter for our text layer and for this I will be using the Google Font Bebas Neue. Now let’s scale the font size up until it’s almost filling the whole screen. Make sure our text alignment is centred, and we’ll make the colour white. Let’s position our letter in the centre of the composition.

Next comes our first expression. We’ll go to the Source Text property of our text layer and holding ALT we’ll click on the stopwatch and type the following.

Code Snippet
sourceText
value = String.fromCharCode(timeToFrames(time));
1st Composition - Letters continued

You’ll see the letter disappear, but if you start scrubbing through the timeline of your comp you will see characters start to flash through. This expression uses the current frame of our composition and uses it as the Unicode code point to present a character. Each character has a Unicode code point. We limited our selection to 400 unicode characters as that is how many frames our composition has, but if you were to use a font that had non-english characters, such Hanja or Kanji you would need to make your composition big enough to allow for all the associated Unicode codes.

Scrubbing through our composition let’s make sure all our characters present correctly within our space. If too many are falling outside of the bounds of the composition we should scale down and reposition our text layer slightly. Or we can split our layer for troublesome characters, such as the @ symbol. Going to that frame we can use Ctrl + Shift + D to split and duplicate our layer, then go to the proceeding A symbol and do the same, so that now we can take our @ symbol and scale it down to fit the confines of the composition.

2nd Composition - Flip Background

Next let’s create another composition called Flip Bg with the same dimensions as our previous composition. This composition will let us create whatever aesthetic we want for our split-flap display. For now, we’ll simply draw out a rounded rectangle and just give it a white stroke with no fill. But in the future we can customise this to be whatever style we want.

3rd Composition - Split Flap Display

Next we’re going to create our split flap composition. So, new composition and make it 1800px wide and 2200px high and call it “Split Flap”, and we’ll make it 1 minute and 20 seconds long. If your letters composition is going to be longer than 16 seconds, then this composition should have a duration that is five times whatever you make your “letters” composition.

Drag your Flip Bg composition and Letters composition into this new composition and have them centred with the letters composition on top. Duplicate both compositions, so two of each, and make all of them 3D layers. Rename one of the Letters Comps “Letters Top” and the other “Letters Bottom” and then do the same with the background comps with one as “Background Top” and one as “Background Bottom”. Parent the Letters Top to the Background Top and the same thing with Letters Bottom to Background Bottom. With the Background Bottom layer still selected, drag out a mask that selects the bottom of the composition and stops just below the centre of the current composition. Copy and paste this onto the Letters Bottom composition so they both have the same mask. Selecting the Background Top layer, drag out a mask to do a similar effect, stopping with the bottom edge just above the centre point of the current composition. Copy the mask to the letters top composition and now we have created the two halves of our split flap display.

We will now create the actual motion of our split flaps flipping through the letters. Let’s give all our layers the brightness & contrast effect and the CC Radial Blur Effect with the type set to Straight Zoom. Make sure motion blur is turned off for all layers and the composition. We instead use the CC Radial Blur effect to give a pseudo motion blur, as the actual motion blur processing can be intense once we start having multiples of this composition. So for performance we just omit it. Plus, I found this blur look ends up looking better in the context of the animation versus the actual motion blur that is generated.

Let’s set keyframes for the CC Radial Blur Amount, Brightness, Contrast, and the Mask Feather for every layer at Frame 0, Frame 2, Frame 3, and Frame 4. Let’s also keyframe the X Rotation of the two Background layers at the same intervals, so frames 0, 2, 3, and 4. To see all we have keyframed lets select all the layers and press U. Going back to frame 0, let’s set the X Rotation of the Background Bottom composition to -60 so it faces forward slightly, we’ll increase the radial blur amount to 50, set the brightness to 50, and for the mask feather set the second number to 400px. Selecting the Letters Bottom layer we will also set the CC Radial Blur amount to 50, the brightness to 50, and the second value of the mask feather to 400px. For the background top layer we will only change the mask feature value to make the second value 100px, and we will do the same for the Letters Top layer as well.

Going to frame 4 now, we will make the frame for the top part flipping down, so selecting the background top layer let’s change the X Rotation to 60 degrees. We will drop the brightness to -35 and increase the CC Radial blur to 50. Again we will adjust the second mask value to 400px. For the letters top layer we will do the same, increasing the second value of the mask feather to 400px, the cc radial blur amount to 50 , but for the brightness and contrast we will change both values, changing brightness to -75 and contrast to -50. For the letters bottom layer we only change the mask feather second value to 100px, and do the same for the background bottom layer as well.

Moving to frame 5 now let’s duplicate all our keyframes for every layer, so we will get keyframes up to and including frame 9. Scrubbing forward again to frame 10, we are going to only copy the keyframe from frame 0, for every keyframed property for every layer. Now, going through every keyframed property, we’re going to hold Alt and click on the stopwatch to add an expression, and we are going to type loopOutDuration() for every single one.

Back to frame 0 and on both the background layers we are going to right click and under time, select Freeze Frame.

Then for both the Letters Top and Letters Bottom layers we are going to right click and under time, select Enable Time Remapping.

We are going to write the same expression for both these Time Remap properties so selecting either letters layer hold Alt and click the stopwatch for the Time Remap property and type the following:

Code Snippet
timeRemap
valueAtTime(framesToTime(Math.floor
Math.floor(value)

A classic Math expression that takes a decimal number value and rounds it down to nearest whole number. e.g. 1.45 would round down to 1, and 2.9999 would round down to 2.

(timeToFrames(time)/5)));
3rd Composition - Split Flap Display continued

What this is doing is extending out how long we stay on each frame of our letters composition. If you remember, each frame in that composition was a new character. Now it will change every 5 frames instead of every single frame, meaning as we scrub through our timeline now we can see our split flap display flipping through characters and them being animated in and out.

Having finished in this composition, let’s toggle the visibility off on the background layers, but if we ever want to have a look with a background aesthetic to our split flap, we need only come into this composition and toggle those layers on again.

4th Composition - Assembling it together

Let’s now create our main composition. Select your usual resolution for video, in our case we’ll make it 1920px by 1080px and we’ll make the composition 30 seconds long.

First we’ll create a new text layer and this is going to be our reference layer for our split flap display. Let’s write a word, say “MEDIA WORKBENCH” in all capital letters. Centre the text to make it easy to read and just position it centre of the screen for now. Use the same font as you did the split flap display just to make it easier to read. On this text layer we’re going to add some expression controls.

  • First we’ll add a slider control and name it “Letter Tracking” and set it to 65.
  • Next add a slider control and name it “Starting Comp”.
  • Next add a slider control and name it “Max Comps”.
  • Next add a slider control and call it “Starting Frame”.
  • Next add a slider control and call it “Omit Start”.
  • Next add a slider control and call it “Omit End”.
  • Next add a slider control and name it “Ending Frame”.
  • Add one more slider control and name it “Random Start”.
  • Finally add a Checkbox control and name it “Center Text”.

Now lets bring in our Split Flap composition and scale it down quite a bit, I’ll go around 10%, and position it underneath our reference text layer. Let’s parent it to the reference layer. On this layer we’ll add two slider controls, calling one of them “Interpolation” and one of them “Seed”.

Let’s hit Enter on the layer to rename it, and let’s rename it to simply be, “0”.

Right click the layer and choose time, Enable Time Remapping.

It’s now time for writing some big expressions.

Let’s start with the Position property, find it by selecting the layer and pressing P. Hold ALT and click the stopwatch to start writing our expression. Here’s what we write…

Code Snippet
position
var numberOfLetters = parent.effect("Max Comps")("Slider");
var xPos = ((name - parent.effect("Starting Comp")("Slider")) - (numberOfLetters/2)) * parent.effect("Letter Tracking")("Slider");
value = [xPos,transform.position[1]];
4th Composition - continued

By using this.parent we are referencing the layer our split flap composition is parented to. This expression is going to reposition our split flap compositions to be spread out and centred, aligning to the anchor point of our text reference layer. At the moment we only have the one split-flap layer, but once we finish our expressions we will duplicate it a number of times and we will see this expression in action.

Next lets write the expression for the opacity. Selecting the layer lets press “T” to bring up Opacity, and like before hold ALT and click on the stopwatch. Let’s write our expression.

Code Snippet
opacity
var startingFrame =parent.effect("Starting Frame")("Slider");
var endingFrame = parent.effect("Ending Frame")("Slider");
var interp = effect("Interpolation")("Slider");
if(interp < startingFrame || interp > endingFrame){
value = 0;
}else{
value = 100;
}
4th Composition - continued

Here we see us using a conditional to look at the values of our Starting Frame slider and our Ending Frame slider, and if our Interpolation slider value falls outside of these two slider values, we make our opacity 0. Otherwise our opacity is 100.

Next we go to our Time remap property by toggling to find it, and holding ALT and clicking on the stopwatch we’ll write our next expression.

Code Snippet
timeRemap
value = framesToTime(effect("Interpolation")("Slider"));
4th Composition - continued

It’s easy to glean what this expression does. Our Interpolation slider will have an expression that results in a value that represents a specific frame in our split-flap composition, and so this expression is grabbing that value and converting it into a time value that the time remap property can use.

Finally we’re going to write our expression for our Interpolation slider. This expression comes in at 100 lines of code so we will edge our way through it bit by bit and cover what things do as much as we can.

Hold ALT, click the stopwatch for the “Interpolation” slider and let’s start.

First, we’re going to write two functions, the first is called “findChar” and we will use it to get an array of values related to a specific keyframe of the sourceText property of our reference text layer.

Code Snippet
Interpolation slider control
function findChar(keyIndex,parentLayer,currentNext,seed){
seedRandom(keyIndex + seed + parentLayer.index, true);
if(keyIndex == 0){
return [0 + random(0,framesToTime(parentLayer.effect("Random Start")("Slider"))),"",0];
}else{
var textSource = parentLayer.text.sourceText;
if( keyIndex > textSource.numKeys){
keyIndex--;
}
var keyStr = textSource.key(keyIndex).value;
var keyLetters = keyStr.length;
var keyTime = currentNext == 1 ? textSource.key(keyIndex).time - random(0,framesToTime(parentLayer.effect("Random Start")("Slider"))) : textSource.key(keyIndex).time + random(0,framesToTime(parentLayer.effect("Random Start")("Slider"))) ;
return [keyTime,keyStr,keyLetters];
}

}
4th Composition - continued

With this function we will pass it four parameters. keyIndex is a numerical value indicating which sourceText property keyframe we want to look at. parentLayer will be used to pass in this.parent, which is a relative way the layer we are working with sees the layer it is parented to. Our function is treated independent to our layer though, so calling this.parent within the function would not work, instead we have to pass it in in this way. currentNext is going to have either a value of 0 or a value of 1, and it relates to whether the keyframe we are looking at is either one that’s current or past, or whether it is the next upcoming keyframe in our timeline. Finally seed will take our seed slider control to give some control to the randomness that is introduced within the function.

This function will return us an array of the time of the keyframe, the actual string of the sourceText, and how many characters are in string.

Next we will write our second function, called “calculateValue”, which will take in the array the previous function gives us, plus some other parameters, and actually calculate the specific frame in our split-flap composition that matches the character at a specific position.

Code Snippet
Interpolation slider control
function calculateValue(keyArray,centered,currentNext,thisIndex,parentLayer){
var keyVal = -1;
var keyTime = keyArray[0];
var keyStr = keyArray[1];
var keyLetters = keyArray[2];
if(centered.valueAtTime(keyTime) == 0){
if(keyLetters > 0 && thisIndex < keyLetters){
keyVal = keyStr.charCodeAt(thisIndex)*5 + 2;
}
}else{
if(keyLetters > 0){
var modifiedIndex = thisIndex - (Math.ceil(parentLayer.effect("Max Comps")("Slider") / 2) - Math.ceil(keyLetters / 2));
if(modifiedIndex < keyLetters && modifiedIndex > -1){
keyVal = keyStr.charCodeAt(modifiedIndex) * 5 + 2;
}
}
}
if(keyVal == 162 || keyVal == -1 || (keyVal >= parentLayer.effect("Omit Start")("Slider") && keyVal <= parentLayer.effect("Omit End")("Slider"))){
keyVal = currentNext == 1 ? parentLayer.effect("Ending Frame")("Slider") + 1 : parentLayer.effect("Starting Frame")("Slider") - 1;
}
return keyVal;
}
4th Composition - continued

As parameters this function first takes in the keyArray that our previous function gave us, it takes in the centered checkbox control we created to be used in calculating position. Next we again have the currentNext parameter taking a 0 or 1 to know whether it’s a future keyframe or not, we pass in the parentLayer again, and we also pass in thisIndex, which will be how we know what split-flap composition is this current one in the context of all the others.

This function does a bunch of calculations, but will return us one number, the number of the frame of the character that this split-flap composition should be showing for the keyframe that our keyArray refers to.

Let’s leave our two functions at the bottom of the expression and start writing the rest of our expression above it, starting with some declarations, some of which will sound familiar.

Code Snippet
Interpolation slider control
var textSource = parent.text.sourceText;
var thisIndex =name - parent.effect("Starting Comp")("Slider");
var parentLayer = parent;
var centered = parentLayer.effect("Center Text")("Checkbox");
var finalval = 0;
4th Composition - continued

The textSource variable gives us a direct connection to the sourceText property of our parent layer, where our keyframes will be set. We also have parentLayer defined as this.parent to be used for all our other references including our functions. Finalval is going to hold the final value of our expression, and so we will define it here as 0 and then will set the value of our time remap property to be equal to finalval at the end of the expression to avoid any complications of no value being set.

Let’s write a conditional and add in our setting that value like so.

Code Snippet
Interpolation slider control
if(textSource.numKeys > 0){
}
value = finalval;
4th Composition - continued

Here we have a conditional ensuring that if we don’t have any keyframes set, we won’t try to do any of the code associated with them, instead value will equal finalval which is initially set as 0, or in other words, the first frame of our timeline.

The remainder of our code is all going to go inside the curly brackets of our conditional. The first half will be all about defining variables that are then used to find other values to define additional variables.

So here we go, inside the conditional.

Code Snippet
Interpolation slider control
var keyIndex = textSource.key(textSource.nearestKey(time).index).time > time ? Math.max(0,(textSource.nearestKey(time).index - 1)) : textSource.nearestKey(time).index;
var currentKeyArray = findChar(keyIndex,parent,0,effect("Seed")("Slider"));
var currKeyTime = currentKeyArray[0];
var nextKeyArray = findChar(keyIndex+1,parent,1,effect("Seed")("Slider"));
var nextKeyTime = nextKeyArray[0];
var startingFrame = parentLayer.effect("Starting Frame")("Slider").value;
var endingFrame = parentLayer.effect("Ending Frame")("Slider").value;
var omitStart = parentLayer.effect("Omit Start")("Slider").value;
var omitEnd = parentLayer.effect("Omit End")("Slider").value;
var currKeyVal = calculateValue(currentKeyArray,centered,0,thisIndex,parentLayer);
var nextKeyVal = calculateValue(nextKeyArray,centered,1,thisIndex,parentLayer);
if(nextKeyVal < currKeyVal){
var totalDist = (endingFrame - currKeyVal) + (nextKeyVal - startingFrame);
if(nextKeyVal > omitEnd || currKeyVal < omitStart){
totalDist = totalDist - (omitEnd - omitStart);
}
var interp = (totalDist > 0) ? linear
linear(x,xMin,xMax,yMin,yMax)

The Linear Expression interpolates values by calculating where “x” falls between “xMin” and “xMax” and then giving a result that is the value equivalently positioned between “yMin” and “yMax“.

(time, currKeyTime, nextKeyTime, 0, totalDist) : 0;
if(currKeyVal > omitEnd){
interp = interp - (omitEnd - omitStart);
}
if((currKeyVal + interp) > endingFrame - (omitEnd - omitStart)){
var currentKey = Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

((currKeyVal + interp) - endingFrame + startingFrame);
finalval = (currKeyVal + interp) >= omitStart ? Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currentKey + omitEnd - omitStart) : currentKey;
}else{
finalval = Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp);
}
if(finalval >= omitStart){
finalval = finalval + (omitEnd - omitStart + 1);
}
}else{
if(nextKeyTime>currKeyTime && currKeyVal != nextKeyVal ){
if(currKeyVal == startingFrame - 1 && nextKeyVal == endingFrame + 1){
finalval = currKeyVal;
}else{
var totalDist = nextKeyVal - currKeyVal;
if(currKeyVal <= omitStart && nextKeyVal >= omitEnd){
totalDist = totalDist - (omitEnd - omitStart);
}
if(totalDist > timeToFrames(nextKeyTime) - timeToFrames(currKeyTime)){
var interp = (totalDist > 0 && currKeyTime !== nextKeyTime) ? linear
linear(x,xMin,xMax,yMin,yMax)

The Linear Expression interpolates values by calculating where “x” falls between “xMin” and “xMax” and then giving a result that is the value equivalently positioned between “yMin” and “yMax“.

(time, currKeyTime, nextKeyTime, 0, totalDist) : 0;
}else{
var interp = (totalDist > 0 && currKeyTime !== nextKeyTime) ? linear
linear(x,xMin,xMax,yMin,yMax)

The Linear Expression interpolates values by calculating where “x” falls between “xMin” and “xMax” and then giving a result that is the value equivalently positioned between “yMin” and “yMax“.

(time, currKeyTime, currKeyTime+ framesToTime(totalDist), 0, totalDist) : 0;
}
if(currKeyVal > omitEnd){
interp = interp - (omitEnd - omitStart + 1);
}
finalval = Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp) >= omitStart ? Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp) + (omitEnd - omitStart + 1) : Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp);
}
}else{
finalval = currKeyVal;
}
}
4th Composition - finishing the Interpolation expression

As a final reference, here’s the entire expression for the time remap property in its entirety.

Code Snippet
Interpolation Slider Control - Full Code
var textSource = parent.text.sourceText;
var thisIndex = name - parent.effect("Starting Comp")("Slider");
var parentLayer = parent;
var centered = parentLayer.effect("Center Text")("Checkbox");
var finalval = 0;

if(textSource.numKeys > 0){
var keyIndex = textSource.key(textSource.nearestKey(time).index).time > time ? Math.max(0,(textSource.nearestKey(time).index - 1)) : textSource.nearestKey(time).index;
var currentKeyArray = findChar(keyIndex,parent,0,effect("Seed")("Slider"));
var currKeyTime = currentKeyArray[0];
var nextKeyArray = findChar(keyIndex + 1,parent,1,effect("Seed")("Slider"));
var nextKeyTime = nextKeyArray[0];
var startingFrame = parentLayer.effect("Starting Frame")("Slider").value;
var endingFrame = parentLayer.effect("Ending Frame")("Slider").value;
var omitStart = parentLayer.effect("Omit Start")("Slider").value;
var omitEnd = parentLayer.effect("Omit End")("Slider").value;
var currKeyVal = calculateValue(currentKeyArray,centered,0,thisIndex,parentLayer);
var nextKeyVal = calculateValue(nextKeyArray,centered,1,thisIndex,parentLayer);

if(nextKeyVal < currKeyVal){
var totalDist = (endingFrame - currKeyVal) + (nextKeyVal - startingFrame);
if(nextKeyVal > omitEnd || currKeyVal < omitStart){
totalDist = totalDist - (omitEnd - omitStart);
}
var interp = (totalDist > 0) ? linear
linear(x,xMin,xMax,yMin,yMax)

The Linear Expression interpolates values by calculating where “x” falls between “xMin” and “xMax” and then giving a result that is the value equivalently positioned between “yMin” and “yMax“.

(time, currKeyTime,nextKeyTime,0,totalDist) : 0;
if(currKeyVal > omitEnd){
interp = interp - (omitEnd - omitStart);
}
if((currKeyVal + interp) > endingFrame - (omitEnd - omitStart)){
var currentKey = Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

((currKeyVal + interp) - endingFrame + startingFrame);
finalval = (currKeyVal + interp) >= omitStart ? Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currentKey + omitEnd - omitStart) : currentKey;
}else{
finalval = Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp);
}
if(finalval >= omitStart){
finalval = finalval + (omitEnd - omitStart + 1);
}
}else{
if(nextKeyTime>currKeyTime && currKeyVal != nextKeyVal){
if(currKeyVal == startingFrame - 1 && nextKeyVal == endingFrame + 1){
finalval = currKeyVal;
}else{
var totalDist = nextKeyVal - currKeyVal;
if(currKeyVal <= omitStart && nextKeyVal >= omitEnd){
totalDist = totalDist - (omitEnd - omitStart);
}
if(totalDist > timeToFrames(nextKeyTime) - timeToFrames(currKeyTime)){
var interp = (totalDist > 0 && currKeyTime !== nextKeyTime) ? linear
linear(x,xMin,xMax,yMin,yMax)

The Linear Expression interpolates values by calculating where “x” falls between “xMin” and “xMax” and then giving a result that is the value equivalently positioned between “yMin” and “yMax“.

(time,currKeyTime,nextKeyTime,0,totalDist) : 0;
}else{
var interp = (totalDist > 0 && currKeyTime !== nextKeyTime) ? linear
linear(x,xMin,xMax,yMin,yMax)

The Linear Expression interpolates values by calculating where “x” falls between “xMin” and “xMax” and then giving a result that is the value equivalently positioned between “yMin” and “yMax“.

(time,currKeyTime,currKeyTime + framesToTime(totalDist),0,totalDist) : 0;
}
if(currKeyVal > omitEnd){
interp = interp - (omitEnd - omitStart + 1);
}
finalval = Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp) >= omitStart ? Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp) + (omitEnd - omitStart + 1) : Math.round
Math.round(value)

A classic Math expression that takes a decimal number value and rounds it to the nearest whole number, either up or down. e.g. 1.45 would round down to 1, and 2.6 would round to 3. A value of exactly .5 will round up to the next whole number.

(currKeyVal + interp);
}
}else{
finalval = currKeyVal;
}
}


}

value = finalval;

function findChar(keyIndex,parentLayer,currentNext,seed){
seedRandom(keyIndex + seed + parentLayer.index, true);
if(keyIndex == 0){
return [0 + random(0,framesToTime(parentLayer.effect("Random Start")("Slider"))),"",0];
}else{
var textSource = parentLayer.text.sourceText;
if( keyIndex > textSource.numKeys){
keyIndex--;
}
var keyStr = textSource.key(keyIndex).value;
var keyLetters = keyStr.length;
var keyTime = currentNext == 1 ? textSource.key(keyIndex).time - random(0,framesToTime(parentLayer.effect("Random Start")("Slider"))) : textSource.key(keyIndex).time + random(0,framesToTime(parentLayer.effect("Random Start")("Slider"))) ;
return [keyTime,keyStr,keyLetters];
}

}

function calculateValue(keyArray,centered,currentNext,thisIndex,parentLayer){
var keyVal = -1;
var keyTime = keyArray[0];
var keyStr = keyArray[1];
var keyLetters = keyArray[2];
if(centered.valueAtTime(keyTime) == 0){
if(keyLetters > 0 && thisIndex < keyLetters){
keyVal = keyStr.charCodeAt(thisIndex)*5 + 2;
}
}else{
if(keyLetters > 0){
var modifiedIndex = thisIndex - (Math.ceil(parentLayer.effect("Max Comps")("Slider") / 2) - Math.ceil(keyLetters / 2));
if(modifiedIndex < keyLetters && modifiedIndex > -1){
keyVal = keyStr.charCodeAt(modifiedIndex) * 5 + 2;
}
}
}
if(keyVal == 162 || keyVal == -1 || (keyVal >= parentLayer.effect("Omit Start")("Slider") && keyVal <= parentLayer.effect("Omit End")("Slider"))){
keyVal = currentNext == 1 ? parentLayer.effect("Ending Frame")("Slider") + 1 : parentLayer.effect("Starting Frame")("Slider") - 1;
}
return keyVal;
}
Explanation of Controls and Animating

Now in closing that property you will notice nothing is happening, everything is still blank. That’s fine. First let’s duplicate our split-flap composition a number of times. You will see the composition name will increment. Fix up the first one it creates to be 1 instead of 2 and then keep duplicating to get quite a few, let’s say 20 in total so up to a composition named 19.

Let’s now talk about the controls we added to the reference layer and what they let us do.

  • The “Letter Tracking” slider lets us set the spacing between all these split-flap compositions we just created.
  • The slider called “Starting Comp” refers to the number of the first split-flap composition attached to this reference layer. If we want to take this whole thing and duplicate it, After Effects will renumber all the duplicated split-flap compositions so rather than going through and renaming them all, we just change this slider value to be the value of the first split-flap composition in the new sequence.
  • Next we have the “Max Comps” slider and this refers to how many split-flap compositions are attached to this reference layer. A quick and easy way is selecting them all and the Info panel will tell us how many are selected, that’s the number we’re entering here.
  • The following four slider values are how we set what characters are accepted for our split-flap display. To find these values we will need to go back into our split-flap display composition and scrub through them. The “Starting Frame” value will be the first frame of the first character I want to accept. In this case my uppercase A first appears on frame 325 as seen under the timecode on the left of my timeline. So I will set my Starting Frame to 325.
  • We will come back to “Omit Start” and “Omit End”.
  • My “Ending Frame” value is going to be the last frame my last character appears on. So in this case my uppercase Z is last seen on frame 454.

Before we look at the last slider controls, I think it’s about time we started seeing this come to life. We need to set a keyframe for our sourceText property, so let’s go to the 2 second mark in our timeline and click the stopwatch for the source text property of our reference layer. You will see our word “MEDIA WORKBENCH” appear, and if you playback from the starting frame you should see the split flap compositions start to flip through letters in order to introduce the word by the time the keyframe is reached.

Going back to our controls, clicking the checkbox for “Center Text” will result in our text appearing in the center of all our split flap compositions instead of left-aligned. You can get some cool effects keyframing this checkbox. The random start slider lets us set a range of frames that each split flap display can randomly start or end within. So some may start a little slower, or some may finish a little quicker. If we scrub our playhead to when we first see our letter “A” appear, and then increase the “Random Start” value you will see some disappear as they now start later. You can have individualised control over each letter through the “Seed” slider control we have on each split flap composition. Previewing this now gives a way more random and unique look. One thing to note is that this random frame range value shouldn’t go up to half your animation duration, otherwise it will mess up the resulting animation. For example with our 2 second animation we have here, it means our random start frame shouldn’t exceed 25 frames, what equates to 1 second.

Now finally, our Omit Start and Omit End slider controls. This lets us set a sub-section of characters to omit. Let’s give an example. Let’s set another keyframe for our source text property at 3 seconds andthen go to 5 seconds and set a keyframe by changing our text layer text to be “5000 SUBSCRIBERS”, all capital letters. Notice I do not have any numbers, as I did not include any number characters within my starting frame and ending frame.

We need to change our starting frame to include them. Back in our split flap composition our first number character appears at frame 240. Scrub through and you can see though there’s a couple symbols between our number characters and our letter characters that we don’t want to include. We use Omit Start and Omit End in a similar way to starting frame and ending frame, to define the section we wish to omit. In this case, frame 290 is when we first see the frame of a symbol we don’t want to include, so that is the value we will set for Omit Start. And scrubbing forward frame 324 is the last frame before we hit what was our starting frame of 325. So we will set Omit End to frame 324.

Let’s hide the visibility of our reference layer and preview what our animation looks like now. You can see it first animates in to our first word, flicking through both number and letter characters. It holds for a time and then animates to our second word keyframed at the 5 second mark.

Changing the Aesthetics

We can easily change the look of the split flap by going into the split flap composition and toggle on our flip top and flip bottom layers then go back to our main composition and use the letter tracking slider to adjust the spacing so they don’t overlap.

We can even go into our flip background composition to change the look again. In this case let’s change it from a stroke to a grey rounded rectangle with a ramp to give some definition, and we can even add an edge using a shape with a stroke and no fill and then apply the same ramp and adjust it to create some contrast.

Making it 3D

Making our split-flap display 3D is also easy. In our main composition let’s create a camera by going to Layer, New, Camera. Then we will select all our split flap compositions and toggle on 3D Layer and Collapse Transformations. Now our split flap displays are fully 3D and we can move the camera around to view the animation from different angles.

Conclusion

So that’s it, we have created our dynamic split-flap display. And we can easily change the look or make new words appear by just changing the source text keyframe of our text layer. If we want our text to animate our just change the text to be empty and the text will animate out up to that keyframe.

GET ACCESS TO THE PROJECT FILE FOR THIS TUTORIAL
I am getting the error "TypeError: Cannot read property 'effect' of undefined"

You have probably included “this.” in your expression. In the latest versions of AE CC, “this.” has been depreciated and will no longer work, instead it will break your code. Remove all instances of it and the error should disappear.

Grab some Merch

Express your inner creative outwardly whilst supporting all that we do...

View Merch store

Need some help

Run into an issue with one of the tutorials or is something not covered in the FAQ?

Contact and Support