3

I have a type effect that requires a couple of layers, one with the type, and another moving behind the letters as they appear (simulating the little text bubbles you get when typing on an iPhone). It's very tedious animating the position of the bottom layer to match the text, so I'm wondering if it's possible to use any javascript tools to measure the characters and drive the position value.

Currently I have an expression driving the opacity like this, to automatically turn the background off for spaces:

theOffset=thisComp.layer(1).text.animator("Animator 1").selector("Range Selector 1").offset;
if (thisComp.layer(1).text.sourceText.substr(theOffset, 1) == " " ){0} else {100}

and another that folows the text animator range selector so that I can retime if I want without having to nudge keyframes till doomsday:

theOffset=thisComp.layer(1).text.animator("Animator 1").selector("Range Selector 1").offset;
try {
    transform.position.key(theOffset + 1).value
}
catch(error){[-10000,0]}//effectively hide it on errors (like the index going out of bounds)

…but this relies on me going through and creating keyframes to match the spacing of all the letters in the text, and frankly I'd rather be doing something else with the time that takes. so I'm trying to find a string method that I could use like this:

xOffset = thisComp.layer(1).text.sourceText.substr(1, theOffset).getTextWidth()

but getTextWidth obviously isn't a valid method. Is there a JS method that can get the size of a string on screen? There seems to be several solutions for this when the client is a web browser, but I can't find any that work for AE expressions.

  • As you are asking for JavaScript, I'm assuming you are using ExtendScript and not the limited After Effects expressions you apply directly to layers? – PTS Nov 13 '14 at 10:24
  • No, I'm talking expressions. A lot of undocumented javascript creeps into expressions; for example many of the javascript string methods are there, like regex and so on. – stib Dec 19 '14 at 6:19
2

So you want the width of the whole text object no single characters? In that case you could use this: http://motionboutique.com/text-bounds-expresssion-580/ A tutorial plus sample project on how to get the bounding box of a text layer.

In case the link dies, here is the complete expression they use to determine the bounding box.

step = 1.0; // higher values speed things up (2 means two times faster) but reduce precision
L = thisComp.layer("MyTextLayer"); // text layer whose size must be evaluated

w = thisComp.width;
h = thisComp.height;
halfW = w / 2;
halfH = h / 2;
halfStep = step / 2;

left = w;
right = 0;
top = h;
bottom = 0;

// find left
found = false;
for (x = 0; !found && x < w; x+=step)
{
    if (L.sampleImage([x,halfH], [halfStep,halfH], true)[3] > 0)
    {
        found = true;
        if (x < left) 
            left = x;
    }
}
// find right
found = false;
for (x = w; !found && x >= 0; x-=step)
{
    if (L.sampleImage([x,halfH], [halfStep,halfH], true)[3] > 0)
    {
        found = true;
        if (x > right) 
            right = x;
    }
}
// find top
found = false;
for (y = 0; !found && y < h; y+=step)
{
    if (L.sampleImage([halfW,y], [halfW,halfStep], true)[3] > 0)
    {
        found = true;
        if (y < top) 
            top = y;
    }
}
// find bottom
found = false;
for (y = h; !found && y >= 0; y-=step)
{
    if (L.sampleImage([halfW,y], [halfW,halfStep], true)[3] > 0)
    {
        found = true;
        if (y > bottom) 
            bottom = y;
    }
}

/*"Size of text\n" + (right-left) + "x" + (bottom-top)*/
left + "," + top + "," + (right-left) + "," + (bottom-top)
  • Thanks for that. This looks like it samples the pixels to see if there's any opacity and determines the size that way. Good thinking outside the square. I'll have to test to see if it works on animated text. – stib Nov 14 '14 at 9:07
  • Expressions evaluate per frame so animation shouldn't be any issue. It will just slow your rendertime down a little as the sampleImage function is quite CPU heavy. – PTS Nov 14 '14 at 18:51
  • Expressions evaluate each time the frame is rendered. If you have motion blur on, the layer can get rendered dozens of time per-frame. So an expression that slows down the playback a little while you're working on it can suddenly become a beast when you turn on MB in the render. – stib Oct 26 '17 at 12:15
2

Looks like Adobe have come to the party on this one. A new update as of After Effects CC 2014.2 (13.2) has a sourceRectAtTime() method that does exactly what I'm wanting. To quote their blurb:

You can now read the rectangle bounds of a layer’s content, including the corrected bounds of a text layer, for any time in a composition. The sourceRectAtTime() method from the After Effects scripting API is now accessible in expressions as a read-only layer object attribute.

Yee-hah!

  • Oh cool finally. Thanks for updating the question with this info. – PTS Dec 21 '14 at 20:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.