Skip to main content
New Participant
December 5, 2022
Question

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

  • December 5, 2022
  • 3 replies
  • 3381 views

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!

This topic has been closed for replies.

3 replies

Braniac
December 6, 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.

Known Participant
July 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!

Known Participant
July 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.

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. 


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!  

 

Mathias Moehl
Braniac
December 5, 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
Dan Ebberts
Braniac
December 5, 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.