Copy link to clipboard
Copied
i'm trying to have Words highlight with an effect applied to a solid, which is assigned to the text layer, as they are spoken in a paragraph. i'm was planning to be using markers to trigger when each Word is said with this: https://www.youtube.com/watch?v=diaCkKp5lpY
Something kind of close was discussed here:
https://community.adobe.com/t5/after-effects-discussions/text-range-selector-position-value-expressi...
but i'm working with a weird way of highlighting text with an expression selector and i think the text box remains the same width (sourceRectAtTime()).
This is a better version that creates a tiny, off-screen mask when there's no text layer to proces (so the mask layer doesn't show up) and corrects a logic error:
pad = 10;
c = thisComp.layer("Scripture");
m = c.marker;
n = m.nearestKey(time).index;
if (time < m.key(n).time) n--;
if (n > 0 && n < index - c.index){
L = thisComp.layer(c.index + n);
r = L.sourceRectAtTime(time,false);
ul = L.toComp([r.left,r.top]);
ur = L.toComp([r.left+r.width,r.top]);
lr = L.toComp([r.left+r.width,r.top
...
Copy link to clipboard
Copied
So what's your question, exactly?
Copy link to clipboard
Copied
how can i put an effect on Words using an expression selector that uses the option of "based on words"?
something like this would be awesome:
https://www.youtube.com/watch?v=u7SxaTMgCJQ
Copy link to clipboard
Copied
maybe i could have an extra layer of paragraph text with the effect applied and then have a mask that sizes and positions based on which word needs to be highlighted? i have no idea how to do that. i would do this manually ...but i plan on doing this a whole lot with different paragraphs.
Copy link to clipboard
Copied
If I'm understanding what you're after, it sounds like you need a way to get access to the per-word animator value outside of the expression selector. I think the only possible way of doing that would be to detect it from the animated property assigned to the animator. I theory, that shouldn't be too tough to do, but whatever you animate affects how the text looks. I don't know that there's not a good solution for this, I just don't know what it would be.
Copy link to clipboard
Copied
i don't have to use an expression selector. i just need something based on markers. maybe i could use text exploder to get each Word on it's own text layer. but if i'm using saber ...that means i will have to create a new solid and assign a new saber effect to each new text layer. do you know of a way to automate doing that? i think i could then have a sub comp with the highlighted words that trigger on makers?
Copy link to clipboard
Copied
is there a way to use text exploder and then use those text layers with sourceRectAtTime() to make a mask set to markers?
Copy link to clipboard
Copied
I'm sure there's a magic combination that will do just what you want. I just don't have enough experience with Saber or Text Exploder to be much help.
Copy link to clipboard
Copied
good grief dude, i know you know how to do this, i've seen your responses on other questions. forget about saber or text exploder ...they are not important:
i think i need something that will set mask vertices on comp 2 incrementally with each new marker by marker.key(textIndex).time
so imagine a paragraph of text and i want the mask to be in the position over the Word spoken. so the position and size needs to be dynamic.
Copy link to clipboard
Copied
your code here is awesome ...but i'm new to after effects code https://community.adobe.com/t5/after-effects-discussions/sourcerectattime-from-multiple-layers/td-p/...
i don't know how to combine this with setting a mask to change size based on markers. that paragraph of text i mentioned ...picture each word being its own text layer.
Copy link to clipboard
Copied
select a composite in the timeline, hit ctrl+alt+t to do a layer/time/enable time remapping
click the stopwatch and paste this in to see code that works with markers ...it deals with markers that have comments but my project doesn't need to. the composite you just added that code to has a layer called "Markers" for a second set of markers to match ...well, that's what i think it is doing.
https://gist.github.com/animoplex/cecf1c64aec4f2733ecd0edbebf4786d
i just feel like this is a starting area to figure this problem out.
i need code to grab the first text layer's position and size and tell a mask on the composite where to position and size ...but after it does that, i need it to go to the next text layer and do the same thing.
Copy link to clipboard
Copied
If all your text words are one separate layers, you could have mask path expressions that build mask paths to fit the extends of the individular words, but the paths would have to already exist (createPath() has to be applied to an existing path) unless--you have a script do it. It might be simpler if you just assume you're going to need a script to assemble this thing for you.
Copy link to clipboard
Copied
The Words would just be dummy to know the position of size of the single mask i want to move around. can you give me an example of a mask using createPath() that then gets its shape changed and moved?
if i'm forced to assemble, is there a way to write something that would create a new solid that is already sized per text layer it finds?
Copy link to clipboard
Copied
I'm not sure exactly what you're asking for, but this path expression would find text layer "Text 2" and create a mask outline to fit that text layer. If you want it to outline a different text layer, you'd change the n = 2; line:
n = 2;
L = thisComp.layer("Text " + n);
r = L.sourceRectAtTime(time,false);
ul = L.toComp([r.left,r.top]);
ur = L.toComp([r.left+r.width,r.top]);
lr = L.toComp([r.left+r.width,r.top+r.height]);
ll = L.toComp([r.left,r.top+r.height]);
p = [fromComp(ul), fromComp(ur), fromComp(lr), fromComp(ll)];
createPath(p,[],[],true);
Copy link to clipboard
Copied
i really don't know what i'm doing, where does that code go? i get a createPath is not defined in a time remap expression.
Copy link to clipboard
Copied
Make sure you have a text layer named "Text 2", create a comp-sized solid, and click anywhere on the solid with the pen tool. Add the expression to the resulting Mask Path property on the solid.
Also, you'll probably have to change the mask mode from None to Add to see it.
Copy link to clipboard
Copied
Thanks, but then how would i have it trigger with markers if it isn't on a time expression?
Copy link to clipboard
Copied
OK, one step at a time. Now create a null layer named "Control" and put some layer markers on it. Make sure you have as many text layers (of various sizes and positions) named "Text 1", "Text 2" and so on, as Control has markers. Then change the mask path expression on the solid to this:
m = thisComp.layer("Control").marker;
n = m.nearestKey(time).index;
if (time < m.key(n).time) n--;
if (n > 0){
L = thisComp.layer("Text " + n);
r = L.sourceRectAtTime(time,false);
ul = L.toComp([r.left,r.top]);
ur = L.toComp([r.left+r.width,r.top]);
lr = L.toComp([r.left+r.width,r.top+r.height]);
ll = L.toComp([r.left,r.top+r.height]);
p = [fromComp(ul), fromComp(ur), fromComp(lr), fromComp(ll)];
createPath(p,[],[],true);
}else
value
Copy link to clipboard
Copied
Thank you very much. can you clue me in on how to add padding? i tried this but didn't work:
padding = 10;
ul = L.toComp([r.left+padding,r.top+padding]);
ur = L.toComp([r.left+r.width+padding,r.top+padding]);
lr = L.toComp([r.left+r.width+padding,r.top+r.height+padding]);
ll = L.toComp([r.left+padding,r.top+r.height+padding]);
Copy link to clipboard
Copied
I think I'd do it like this:
pad = 10;
m = thisComp.layer("Control").marker;
n = m.nearestKey(time).index;
if (time < m.key(n).time) n--;
if (n > 0){
L = thisComp.layer("Text " + n);
r = L.sourceRectAtTime(time,false);
ul = L.toComp([r.left,r.top]);
ur = L.toComp([r.left+r.width,r.top]);
lr = L.toComp([r.left+r.width,r.top+r.height]);
ll = L.toComp([r.left,r.top+r.height]);
p = [fromComp(ul)+[-pad,-pad], fromComp(ur)+[pad,-pad], fromComp(lr)+[pad,pad], fromComp(ll)+[-pad,pad]];
createPath(p,[],[],true);
}else
value
Copy link to clipboard
Copied
This is great ...can i ask you to add feather to it?
Copy link to clipboard
Copied
That's a separate property, so it would take its own expression, unless you have a script set everything up for you. Or, you could just do it by hand. It depends on where your workflow is headed with this thing...
Copy link to clipboard
Copied
oh, it doesn't have to be in code, so i just set them all to have the same amount of feather, thanks.
i don't want to rename every text layer, so i'm thinking of using your other code of something like this:
c = thisComp.layer("controller");
L = thisComp.layer(c.index+i);
is there a way to test what type of layer it is indexing?
Copy link to clipboard
Copied
You could use try/catch to differentiate based on a property that only that type of layer has, for example, you could do this to see if it's a text layer:
c = thisComp.layer("controller");
L = thisComp.layer(c.index+1);
try{
L.text.sourceText;
// end up here if it's a text layer
}catch(e){
// end up here if not text layer
}
Copy link to clipboard
Copied
is there a way to make it not care if the number of markers doesn't match the number of layers? i tried this but then it gives me nonsense about the pad varible:
pad = 10;
m = thisComp.layer("Scripture").marker;
n = m.nearestKey(time).index;
if (time < m.key(n).time) n--;
if (n > 0){
c = thisComp.layer("Scripture");
try{
L = thisComp.layer(c.index+n);
r = L.sourceRectAtTime(time,false);
ul = L.toComp([r.left,r.top]);
ur = L.toComp([r.left+r.width,r.top]);
lr = L.toComp([r.left+r.width,r.top+r.height]);
ll = L.toComp([r.left,r.top+r.height]);
p = [fromComp(ul)+[-pad,-pad], fromComp(ur)+[pad,-pad], fromComp(lr)+[pad,pad], fromComp(ll)+[-pad,pad]];
createPath(p,[],[],true);
}catch(e){
}
}else
value