Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Auto-Resizing Shape Layer/Rectangle (But With Multiple Lines Of Text)

Community Beginner ,
Dec 04, 2022 Dec 04, 2022

Hello!!

 

I've seen many tutorials on how to make a shape layer (usually a rectangle) auto-resize to fit a line of text in After Effects. However, is there an expression to make a shape layer respond to two or more lines of text, auto-resizing to fit whichever is the longest line of text?

 

If anyone knows an answer to this or a tutorial that I may have missed, that would be appreciated!

TOPICS
Expressions , FAQ , Scripting
3.1K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 04, 2022 Dec 04, 2022

It seems like sourceRectAtTime().width should give you the width of the longest line, so that part should be the same as for a single line.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 05, 2022 Dec 05, 2022

Pins & Boxes is your friend 🙂

 

Pins & Boxes can create "Pins" at the corners or edges of any layers, and these pins stay attached to the layer if it is changed (say if the text of a text layer is replaced, the layer is moved, scaled,...) In addition, Pins & Boxes can create boxes around arbitrary collections of pins. These boxes resize such that they always includeexactly  all the pins that belong to that box.
Hence, you can simply add pins to the corners of your two text layers and then create a box around all those pins.

You can also parent the second text layer to a pin of the first one, it you want the second text to stay attached to a corner of the first text, for example.

Mathias Möhl - Developer of tools like BeatEdit and Automation Blocks for Premiere Pro and After Effects
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 06, 2022 Dec 06, 2022

You can use sourceRectAtTime() to determine the size of each text layer, add the combined height and look for the widest layer. Using index instead of layer names this expression will give you the Rectangle Size for 3 text layers:

 

// Rectangle Path Size
// source layers 
src1 = thisComp.layer(index - 3);
src2 = thisComp.layer(index - 2);
src3 = thisComp.layer(index - 1);

// text size
tBox1 = src1.sourceRectAtTime();
tBox2 = src2.sourceRectAtTime();
tBox3 = src3.sourceRectAtTime();

// max width
tWidth = Math.max(tBox1.width, tBox2.width, tBox3.width).toFixed(2);

//  add leading 
lyrSpace = 30;

// total height
srcHeight = Math.ceil(tBox1.height + tBox2.height + tBox3.height + lyrSpace);
tHeight = srcHeight + lyrSpace;

// box size
txtBase = [tWidth, tHeight];

// padding control
roundPad = content("Rectangle 1").content("Rectangle Path 1").roundness;
hPad = 20;
vPad = 40;


box = [(hPad + roundPad)] + [txtBase[0], txtBase[1]];
x = box[0];
y = box[1] + vPad;

[x, y]

 

The hPad, vPad, and lyrSpace can be sliders.

 

The next problem you have to solve is the text layer position. Stack the second and third text layers using this expression:

 

srcLyr = thisComp.layer(index - 1);
srcScl = srcLyr.scale * .01;
srcPos = srcLyr.position;
srcRec = srcLyr.sourceRectAtTime();
srcH = srcRec.height;
srcT = srcRec.top;
lyrT = thisLayer.sourceRectAtTime().top;
srcOfst = (srcH + srcT) * srcScl[1];
linSp = 20;

[srcPos[0], srcPos[1] + srcOfst - lyrT + linSp]

 

The linSP can be a slider.

 

Add this expression to the shape layer position:

 

srcLyr = thisComp.layer(index - 3);
srcLyr.position

 

You also need to write expressions for Rectangle/Position, Rectangle/Roundness. This post is getting kind of long and confusing, so I just shared a project file that contains all of the expressions and something extra. You can save it as an animation preset. I have not compensated for different paragraph justifications on the text layers so they all need to match. 

 

I hope this helps.

 

Look for a tutorial series on sourceRectAtTime() that is going to demonstrate how to automate all kinds of text, shape, and ordinary layers.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 18, 2023 Jul 18, 2023

Hi Rick, 

 

This project file is almost working for me, but I has to much "stuff" I don't need. I hope you can help me out, because I don't see what I can delete without messing up the whole thing or to make it work better.

 

I just want a column with 1 to 3 lines of text. The lines are left aligned and the column must be centered to the middle of the composition. So, for example, if line 3 is the longest line, the column of text must be aligned to the center. The baseline of the lines is fixed, so I don't need any custom leading.

Can you please help me out?

 

See enclosed my AEP based on your AEP. 

Many thanks!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 18, 2023 Jul 18, 2023

I think that this is your design goal:

  1. Three equally spaced lines of text move up to their final position over a few frames
  2. Each line of text is revealed as it moves into position by an animated mask
  3. The stack of text layers needs uniform leading (space between the lines)
  4. The stack of text layers needs to be left justified and centered in the composition, no matter which line is longer

 

Let's take the design goals one at a time, starting with the first goal:

Step 1 - Moving text into position: Use keyframes or the time minus the layer in-point. I prefer expressions for this kind of move utilizing time minus the in-point. Because a mask or matte will reveal the text, the distance can be calculated by the height of the actual text using sourceRectAtTime().height. That part is pretty straightforward. You can add a bit of padding to height, then apply an expression like this to the anchor point to move the layers up just a little farther than they are high. By using the anchor point, you can still use a layer's height to stack them evenly.

 

h = sourceRectAtTime().height;
pad = 10;// extra distance for the move
yMove = h + pad;
t = (time - inPoint) / thisComp.frameDuration;
mov = 20; //number of frames for the move
newY = easeIn(t, 0, mov, - yMove, 0);
[value[0], value[1] + newY]

 

The move would start the text below the anchor point by the height of the text and move it up into its resting position without the expression. You could also multiply the layer's index by an offset value, keep all three text layers with the same in-point, and offset the timing by a specific value.

 

Step 2 - Animating a mask to reveal the text layer. Because the text moves up into position, you could move down the timeline until the text layer stops moving, carefully draw a mask that includes all of the text, then apply the Window/Create Nulls From Paths/Points Follow Nulls script. The created nulls would keep the mask from moving while the text moves into position. Your sample project has a little animation in the top right corner of the mask that you could control with a slightly modified copy of the Anchor Point expression text layer applied to the top right corner null. You could then shy the Null layers to keep the timeline clean. You could also tie the vertical position of the nulls to the text layer position so they would move with the layer. The simplest option would be to keyframe the mask as you did in your sample project.

 

Step 3 - Stacking the layer with uniform spacing is pretty straightforward. All you have to do is take the position of the first layer, add the distance between layers, then use the same expression again to stack the layers with universal spacing. A simple expression like this for the second and third layers would get them evenly spaced below and lined up with the top layer.

 

p = thisComp.layer(index - 1).position;
yOfst = 250; //space between layers
[p[0], p[1] + yOfst]

 

 Step 4 - Center the stack of layers horizontally and vertically in the composition. This is where sourceRectAtTime() comes into play again. You use it on the position property of the top layer. Adding the combined height of each layer plus the padding between layers allows you to center the layer stack vertically. That part is easy. Easier if you add a spacing slider to the top layer and use it for all three layers. Getting the X position is a little more complicated. You have to take find the layer with the maximum width. You can do that using :

 

Math.max(lyr1.width, lyr2.width, lyr3.width)

 

 

The expression applied to the top text layer that would center all three layers horizontally and vertically would look like this:

 

lyr1 = sourceRectAtTime();
lyr2 = thisComp.layer(index + 1).sourceRectAtTime();
lyr3 = thisComp.layer(index + 2).sourceRectAtTime();
w = Math.max(lyr1.width, lyr2.width, lyr3.width);
vSpace = 250 * 2;
h = (lyr1.top + lyr2.height + lyr3.height + vSpace)/2;
x = thisComp.width/2;
y = thisComp.height/2;
[x - w/2, y - h + lyr1.height]

 

If VSpae and pad were replaced with an Expression Control Slider on the top text layer, you could easily compensate for the height of any text layer. 

 

This will work with text of different point sizes as long as all text layers are left justified, the baseline shift is zero, and the point sizes are all the same. If you change the point of one of the layers, you will have to throw in sourceRectAtTime()top to maintain accurate vertical spacing and account for ascenders and defenders in the type.

 

I hope this gets you started.

(EDIT: I got kind of intrigued by this idea and made a sample comp for you to look at. It uses a slider to adjust the Spacing between layers, expressions to drive the masks on the second and third layers, and the distance between the keyframes on the top layer mask set the timing for the move.  Try downloading the file and see if you get some ideas.

 

If I get some time in the next few days, I will try setting this up so that Ascenders and Descenders in the text layers don't offset the centering by their height, and the text layers don't have to have the same font size.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 19, 2023 Jul 19, 2023

Rick! You are a hero! Spend the whole day searching for the answer and you just created the answer for me. Very happy with the results I got and the best part; I actually understand what is happening with your very detailed reply.  

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 19, 2023 Jul 19, 2023

Alright, no I want to add more lines - let's say to 5. Got it to work with the spacing, but I don't get it centered to the comp anymore. Tried to adjust the math/expressions, but I'm failing.  Would be really awesome if you help me out one more time!  

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 19, 2023 Jul 19, 2023

Don't know how I edit my posts, but I've found a small error. Once the text is changed to lowercase and you add for example a "g" in the first line the positioning is off. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 19, 2023 Jul 19, 2023

Ascenders and defenders will change the calculations slightly. I used code that I use to size and center a background layer with multiple lines. 

 

If you substitute the text layers .sourceRectAtTime.height with .text.sourceText.style.fontSize; you should be able to keep the top where it should be when the descenders are in the first line of the text. If you have descended characters (g, y, etc.) in all lines, the box will be centered. 

 

I don't have time to make it perfect for you now, but if you play with font size everywhere you are using sourceRectAtTime().width, you should be able to solve the problem. You'll still need to use SRaTime.width to keep the text centered.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 20, 2023 Jul 20, 2023

Try this comp. I used the text size to calculate height. Characters do not fill the entire design box, so the center will be off just a bit. You could add a trim Slider to fine-tune the vertical placement, but I think this solution would work well for most work. 

 

Here's the position expression for the First text layer :

hCntr = thisComp.width/2;
vCntr = thisComp.height/2;

l1 = thisLayer;
l2 = thisComp.layer(index + 1);
l3 = thisComp.layer(index + 2);
lyr1 = l1.sourceRectAtTime().width;
lyr2 = l2.sourceRectAtTime().width;
lyr3 = l3.sourceRectAtTime().width;
w = Math.max(lyr1, lyr2, lyr3)/2;

vSpace = thisComp.layer("First Text").effect("Spacing")("Slider");
h1 = l1.text.sourceText.style.fontSize;
h2 = l2.text.sourceText.style.fontSize;
h3 = l3.text.sourceText.style.fontSize;
h = (h1 + h2 + h3 + vSpace + vSpace)/2 - h1;

[hCntr - w, vCntr - h]

I made a couple of other adjustments to the second and third layers' position properties:

p = thisComp.layer(index - 1).position;
yOfst = thisComp.layer("First Text").effect("Spacing")("Slider"); //space between layers
[p[0], p[1] + sourceRectAtTime().height + yOfst]
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 20, 2023 Jul 20, 2023

Hi Ricky, 

 

Thank you so much for your help. It still jumps if delete all the descended characters in the second line.

 

What if we use "separate dimenions" on the position parameter and fix the height of the lines by hand and only center the text based on the longest line? That would do the trick for me and I am still be able to animatie the Y Position.  

 

Like to hear from you! Many thanks Rick

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 20, 2023 Jul 20, 2023

Sorry, it was late, and I forgot to fix the second and third text layers in the project I shared. I needed to use Font size instead of sourceRectAtTime on all the text layers to get consistent layer height values.

 

I also changed the first layer by taking 80% of the font size of the top layer's font height in the final calculation for the Y position to center the text layers. The box used to design fonts is almost never filled with the design. 80% of the Font Size is a pretty good ratio for Courier. You can see that in the Screen Capture I shared.

 

The Museo Sans font you used in your original sample comp is about 90%. You could add a slider to the compensation applied to the top layer font height to keep the three lines centered.

 

Naming "Y Adjust" and changing line 18 to add the slider value to the h variable instead of multiplying the height of the first layer by a percentage would allow you to easily animate the layer stack's vertical position.

 

Here are the modified Position Expressions. 

// Top Text layer
hCntr = thisComp.width/2;
vCntr = thisComp.height/2;

l1 = thisLayer;
l2 = thisComp.layer(index + 1);
l3 = thisComp.layer(index + 2);
lyr1 = l1.sourceRectAtTime().width;
lyr2 = l2.sourceRectAtTime().width;
lyr3 = l3.sourceRectAtTime().width;
w = Math.max(lyr1, lyr2, lyr3)/2;


vSpace = effect("Spacing")("Slider");
yAdjust = effect("Y Adjust")("Slider");
h1 = l1.text.sourceText.style.fontSize;
h2 = l2.text.sourceText.style.fontSize;
h3 = l3.text.sourceText.style.fontSize;
h = (h1 + h2 + h3 + vSpace + vSpace)/2 - h1 + yAdjust;

[hCntr - w, vCntr - h]

The second and third text layers also fixed the AEP.

RickGerard_0-1689855107588.gif

A Testing Font Size ratios comp in the included AEP shows you the difference between font size and sourceRectAtTime.height with different fonts. The ratio changes when you add fonts with descenders and other letters, punctuation, and numbers. It was kind of interesting to play with.

 

I almost never separate dimensions because you lose the ability to modify a motion path using the Pen tool or the vector handles. There are so many other properties that use arrays that it is no problem for me to stick with the normal Position array.

 

This comp should let you use different font sizes on different layers, allow you to animate the vertical position of the layer stack using a slider on the first text layer, and control the timing of the slide in animation by adjusting the timing of the keyframes on the first text layer's mask. The mask on the second and third text layer will always match the first mask so there is only one mask you need to animate.

 

This was a fun exercise for me, and some of it is going to be in a new tutorial series I'm putting together on automating animation using expressions. 

 

My Quick Tips Playlist. Enjoy. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 20, 2023 Jul 20, 2023
LATEST

Hi Rick, 

 

Again many thanks for you detailed explanation and help. Nice to see we got both what we wanted! Wish you all the best with creating the tutorial series!  

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines