Hi
There are various ways to do this. We are generally thinking about changing the state from A to B for a given parameter or set of parameters. While there are many ways to do this, let's keep to the things you are already exploring = using behaviors.
The basic motion behaviors act on the total set of parameters for that function, so grow will act on the total scale and does not consider the ratio across x and y to keep it in proportion.
When we want to give instructions to specific parameters independently, we use the parameter behaviors. Of these, the ramp behavior is most often employed to change a parameter from A value to B value.
Set ramp on the x scale and another ramp on the y scale
Trim these to half the duration of your project. Name them X in and Y in, and then duplicate each one, move it to the end of the project and name them X out and Y out
Behaviors are the general topic here. They are very contextual and how we set them up is all going to depend on the animation we want to do. In this case I am running each behavior half the project duration and using the start and end offsets to set the beginning frame and end frame of each animation. In other situations, we would just trim the behaviors to set the duration. In this case - because we are moving from a higher value to a lower value - if we trim - the layer will snap back to the original state at the end of the behavior.
Note in the screen shots the start and end offset values - end offset for the In animations and start offset for the out animations.
Generally - the end offset counts frames backward from the last frame of the behavior - and the start offsets count frames forward from the first frame of the behavior.
Start offsets delay the beginning of the animation.
End offsets make the end of the animation happen sooner.
In this case here, my project is 5 seconds at 30 fps.
The in behaviors run for 75 frames from 0 to 74 and the out behaviors run for 75 frames from 75 to 149
The end offset on the in is set to 45 - so 75 less 45 leaves 30 frames/1 second for the animation.
The start offset on the out is set to 45 - so the animation has 30 frames to run on the other side - animating in the last 30 frames of the behavior.
To the in behaviors, leave the start value at zero and set the end value to determine the final state of the parameter. In this case, for the y I set the end value to -5 and for the x the end value to minus 10 to keep proportion.
Now for the out behaviors, I set the start value to match the end value of the in behaviors.
The in animations moves from state A to B, while the out animations move from state B to A. Note that this is not a golden rule - as I noted before, how we configure the behaviors all depends on the animation we want to do and the functions we want to publish for the user in FCP.
I have the curvature of all behaviors set to 100 to give an ease in ease out style. Unfortunately, the ramp behavior is limited to this for animation style. To get more easing options, we can have other methods with other behaviors, especially the link behavior with the mix slider - but I will stick to just ramp behaviors here.
You can do the same with ramp behaviors on the width and height.
Once you explore this and get it working, I thin, if you are making a template to use in Final Cut Pro, then you will want to be able to publish something to set the size of the border in FCP. The solution would be to put the in animation end values and the out animation start values on a slider widget - to unify them into 1 parameter and then publish the slider. Let's look at that later when you get to that point.
This is a good exercise to get you familiar with the ramp behaviors. It is really important to note that ramp behaviors are just 1 way to get it done.
You mentioned keyframes before. That should work just fine. If it was getting messed up, then we need to look at your layer order and location of layers in the timeline - something was not correct there.
However - if we want to publish controls to FCP - keyframing a parameter directly is not the way - because if you publish a keyframed parameter - FCP will ignore the keyframes. Keyframing through a behavior and then rigging is the way to employ keyframes in a way that can then be published - but that is something to look at once you become familiar with regular behaviors.