Copy link to clipboard
Copied
Greetings all,
I'm looking to try to simplify something I typically do in AfterEffects by hand that's extremely tedious. Basically, I want to try to create a key-frame-able dropdown. Here's the scenario:
One of the motion graphic effects that I use for my podcast is movable talent windows (kind of like when you're watching the news and they do a splitscreen with two people in different places, and the windows change size and position). I've got all the window sizes and positions mapped out in an Excel spreadsheet for easy reference, but it gets tedious having to go through and change everything if I have to adjust any of said sizes or positions.
This may not even be possible, but what I'm looking for is a way to have a dropdown menu that specifies different layouts (i.e. "Splitscreen x2 Even," "Right Video x3 Even," and so on), and have all the other layers look at that and adjust their size and position accordingly. That way if I do have to change a size or a position, all I have to do is change the master (maybe have a set of sliders on some control layers, each with a name corresponding to a different layout). In my vision, the individual layers would be keyed to pull the value from the dropdown, and then pull slider values from a control layer corresponding to the name they see in the dropdown.
The question is, is there a way to key frame a dropdown selection to make it change, say over a span of a single second?
For an example of what I'm trying to simplify: https://youtu.be/UNAxqMYS8Jg?t=868
In order to do this I had to manually keyframe the sizes and positions for three windows, mine and my guest's, plus the large video window as it animates in from its off-camera position. This can be a little complicated when I just have one guest, but it's an even bigger challenge when I have multiple guests.
OK. I haven't tested this, but I think this is the edit necessary for my previous expression:
L = thisComp.layer("Dropdown Menu");
menu = L.effect("Dropdown Menu Control")("Menu");
moveTime = 1;
val = value;
if (menu.numKeys > 0){
n = menu.nearestKey(time).index;
if (time < menu.key(n).time) n--;
if (n < 2){
L1name = L.text.sourceText.valueAtTime(menu.key(1).time);
val = thisComp.layer(L1name).effect(name + " Position X")("Slider").value;
}else{
t = menu.key(n).time;
L1na
...
Copy link to clipboard
Copied
I was taking a shot in the dark at trying to figure out what to tell it to do, so maybe my syntax and/or logic isn't right. Does what I was trying to do with my modified version at least look right?
Copy link to clipboard
Copied
It's not clear to me what you're trying to do there, but in any case, it looks like your code would only have an effect if there were no keyframes on the menu control, which i"m guessing is not what you had in mind.
Copy link to clipboard
Copied
Right--not what I was thinking. (This was me experimenting with something I don't fully understand, so I'm not surprised I did it wrong.)
What I was aiming for was to get the expression to figure out what configuration the dropdown menu was calling for, then pull the name of the layer it was on, and (in this case) do two things when it saw a keyframe:
1) look back to see if the dropdown had a previous keyframe, and if so, figure out which layout it was calling for and pull the relevant information from that layer (in this case, I was looking to pull the number from the "X Position" slider), and then;
2) look at the current keyframe nearest to "time" and pull the same value from it, and as you described begin moving things as appropriate for a duration of one second (beginning at the time of the second keyframe). Repeat for any keyframes to follow.
From what I can piece together for the expression you shared, it looks like it does at least some of that, but I'm not seeing where I can point it at the property I want it to pull from. (I'm envisioning applying this or whatever expression we come up with to the X and Y transform properties of each camera input layer, along with the sliders for frame width and frame height).
Copy link to clipboard
Copied
I think we might be close. I think the mechanics of the expression pretty much does what you want, but additional stuff needs to happen to get to the actual position values necessary. Assume that the expression has access to the most recent and the previous keyframes and the source text associated with the times of those two keyframes, and see if you can work up the algortim to start with that info and navigate to the correct from and to position values. If you can do that, I think I can turn it into code.
Copy link to clipboard
Copied
This is the best I can come up with, let me know if this is what you were looking for:
Layers:
In this example: fetching the X position; in this scenario the expression we’re talking about would be applied to the transform.xPosition property of Camera Input Talent 1 (we’re assuming separate transformation properties for X and Y). The layers titled “Splitscreen x2 Even” and “Splitscreen x5 Even” have sliders on them for frame height, frame width, and X and Y positions. The X Position slider would have a name like “Camera Input Talent 1 Position X”
Here’s how I envision it working, with this expression applied to the transform X position property of “Camera Input Talent 1”:
If we can come up with a way to make this work for the X position, I can take that and adapt it to work for the Y position and the frame sizes too.
Copy link to clipboard
Copied
OK. I haven't tested this, but I think this is the edit necessary for my previous expression:
L = thisComp.layer("Dropdown Menu");
menu = L.effect("Dropdown Menu Control")("Menu");
moveTime = 1;
val = value;
if (menu.numKeys > 0){
n = menu.nearestKey(time).index;
if (time < menu.key(n).time) n--;
if (n < 2){
L1name = L.text.sourceText.valueAtTime(menu.key(1).time);
val = thisComp.layer(L1name).effect(name + " Position X")("Slider").value;
}else{
t = menu.key(n).time;
L1name = L.text.sourceText.valueAtTime(menu.key(n-1).time);
v1 = thisComp.layer(L1name).effect(name + " Position X")("Slider").value;
L2name = L.text.sourceText.valueAtTime(menu.key(n).time);
v2 = thisComp.layer(L2name).effect(name + " Position X")("Slider").value;
val = linear(time,t,t + moveTime,v1,v2);
}
}
val
Copy link to clipboard
Copied
I'll try it out and report back!
Copy link to clipboard
Copied
IT WORKS!!! You are totally getting a technical consultant credit for any product I make with this from now on. This is going to make my workflow SO much easier! I can't thank you enough for helping me crack this one.
Copy link to clipboard
Copied
Glad to hear it! Thanks for letting me know.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
One more question that might make this even easier: is there a way to pull an effect name? In other words, if I name a slider "Frame Width," is there a way similar to "thisLayer.name" to get it to recognize the name of the effect? What I'm thinking is this would make it even easier to copy and paste this expression across sliders (so if I'm using it with a "Frame Width" slider on a child layer, the expression will know to go through the layers like we already set up, but it'll pull the name of the slider it's being used on and look for a slider on the parent layer with the same name).
Copy link to clipboard
Copied
If you have an expression on a slider and you want to get the custom name of the slider control itself, you can do something like this:
thisProperty.propertyGroup(1).name, which goes up 1 level in the heirarchy to get the name.
Copy link to clipboard
Copied
Awesome--thank you!
Copy link to clipboard
Copied
While I was working up the expression, it occurred to me that if instead of this:
"Splitscreen x2 Even Positioin X"
you had used
"Splitscreen x2 Even X Position",
you could then construct the name like this:
temp = name + " " + thisProperty.name;
Copy link to clipboard
Copied
That's a good idea--and it's not hard to make that change, I've got a script that can go through expressions throughout a whole project and make adjustments. (It may be counterintuitive but when I do that and AfterEffects shows errors, I can follow those around and make changes to any layer or slider names as needed). Great tip!
Copy link to clipboard
Copied
Yeah, so maybe you end up with 2 flavors of the expression. One that builds the slider name using thisProperty.name and another that uses thisProperty.propertyGroup(1).name.
Copy link to clipboard
Copied
I have one followup question--so I've been able to get this to work exactly as we wanted it. This is the ultimate result that automatically pulls the property name of the slider:
L = thisComp.layer("Dropdown Menu");
menu = L.effect("Dropdown Menu Control")("Menu");
moveTime = thisComp.layer("Shape Dynamics").effect("Transition Duration")("Slider");
temp1 = " " + thisProperty.propertyGroup(1).name;
val = value;
if (menu.numKeys > 0){
n = menu.nearestKey(time).index;
if (time < menu.key(n).time) n--;
if (n < 2){
L1name = L.text.sourceText.valueAtTime(menu.key(1).time);
val = thisComp.layer(L1name).effect(name + temp1)("Slider").value;
}else{
t = menu.key(n).time;
L1name = L.text.sourceText.valueAtTime(menu.key(n-1).time);
v1 = thisComp.layer(L1name).effect(name + temp1)("Slider").value;
L2name = L.text.sourceText.valueAtTime(menu.key(n).time);
v2 = thisComp.layer(L2name).effect(name + temp1)("Slider").value;
val = linear(time,t,t + moveTime,v1,v2);
}
}
val
Seeing it in action I do have one question. When it animates between the two keyframes, it behaves as if it's using linear interpolation. It's not a huge deal but I do kind of miss the old way, which used an auto bezier. Is there a way to adjust this to end up with an equivalent of a bezier?
Copy link to clipboard
Copied
You could try replacing linear(time,t,t + moveTime,v1,v2) with ease(time,t,t + moveTime,v1,v2).
Copy link to clipboard
Copied
I will give it a try and report back! Thanks as usual Dan
Copy link to clipboard
Copied
As usual, it works perfectly! It's a small and subtle thing but it makes a HUGE difference! Many thanks as always Dan!
Copy link to clipboard
Copied
Copy link to clipboard
Copied
If you want to use the Automation Blocks tool to Time Remap Multiple Animations, you could have
one animation for each transition like "move from layout A to layout B". This rig would still require you to animate two sliders instead of one dropdown (one for picking the animation like "move from layout A to B" and one for the completion of that animation), but should work out of the box very easily.
Copy link to clipboard
Copied
This is a good suggestion but it won't work. This would require me to set up an exponential amount of animations; remember, I've got six windows (which could increase in number down the line) and to make this work I'd have to configure an animation preset for every single possible combination I might need. FAR too complicated for the end state I'm trying to reach.