Here’s a problem. A fairly straightforward problem. We have a layer and we want it to orbit some point, but we want it to stay upright (meaning we don’t want the rotation to be affected).

**The Simple (and Potentially Messy) Solution**

The first solution is pretty simple. Make a null, place the null exactly where you want your layer to orbit around, parent your layer to the null, and rotate that null, baby! And to make sure the layer stays upright, we negate the null’s rotation by simply adding an expression into the orbiting layer’s Rotation property. We pick-whip the null’s Rotation property and multiply it by -1. It’ll look something like this:

`thisComp.layer("Null 1").transform.rotation*-1`

Easy peasy! And if you want to be able to animate the rotation of your layer, you can add the “value” to your expression. (More on adding *value*.) Like so:

`(thisComp.layer("Null 1").transform.rotation*-1)+value`

I should note: adding the parentheses around the first bit isn’t entirely necessary. Order of operations, don’t ya know. Math. Ever heard of it!? (You disgust me.)

So, why is this thing “potentially messy”? I’ll tell you why. I’ll tell you EXACTLY why…. once I’m finished building up the suspense….

I’ve started thinking about the use of expressions in big networks of layers. My hesitation to use the above solution stems from the fact that it takes two layers to work– so, you’re doubling the layer count of any comp made of a bunch of these layers. Also, you couldn’t really use this solution for something like the Center property of a Circle Effect (or similar effect that has a Center property). There’s an expression for that.

**The More Math-y Solution**

The second solution to this problem is based on the cyclical nature of **Math.sin()** and **Math.cos()**. Both return values between -1 and 1, but the wizardry happens in the fact that these waves are offset in such a way– when given 0 as an input– **Math.sin()** returns a 0, and **Math.cos()** returns a 1. Illustrated below.

If we pass a rotation value into these two expressions (using an Angle Control), we can mimic the effect of rotating a center null. Let’s add an Angle Control to our layer, and call it *driver*. We’ll also need to add a Slider Control, and it will be called *size*. And here’s the expression we’ll put into the Position property of our layer:

`s=effect("size")("Slider");`

d=degreesToRadians(effect("driver")("Angle"));

h=Math.sin(d);

v=-Math.cos(d);

([h,v]*s)+value

I’ll pick it apart piece by piece. We first set up our variables for the Expression Controls (*size* and *driver*). *size* is going to function as the radius of the circle around which our layer will be moving. Because **Math.cos()** and **Math.sin()** use radians to calculate their values, we have to convert the degrees from our Angle Control (*driver*) to radians. The next part– where we set up *h* and *v–* is where the magic happens.

The stuff in variable *h* is responsible for how the layer is moving horizontally. For *h* we feed our *driver* values into **Math.sin()**. Variable *v* is only responsible for how the layer moves vertically. For this, we’re feeding the values of *driver* into the** Math.cos() and multiplying that by negative one**. (The layer will move in the opposite direction of *driver*, if we don’t have the negative here.)

Before we multiply our expression by *size*, we get a layer–as we drag our *driver* control– that travels in a circle which has a radius of 1. Controlling the circle’s radius is as simple as multiplying by *size*. When *size* is 100, the circle has a radius of 100, for example.

To put it all together, we’re just dumping *h* and *v* in a Position array (where *h* is our x property and *v* is our y), multiplying by our size…. and then….!?!?! What is this? Adding *value*? What the fudge-factory, Steve!? The circle we’re traveling around, when we add *value*, is centered AT THAT LOCATION. So, when we punch 960 and 540 into the x and y Position properties (respectively), we get a circle, centered at [960,540], with a radius of whatever *size* happens to be. And another fun thing: we can parent this layer to another layer without the fear of it getting all whacky. Also, your layer’s Anchor Point, Scale, and Rotation properties will act just how you’d expect them to. There’s nothing crazy going on. (So, calm yourself. You’re making me nervous.)

Go forth! Make circles. Get dizzy.

**EXTRA 3D FUN-ZONE
**

Because each dimension in our expression is controlled discretely, it’s absolutely possible to dump *h* and *v* into a Position array that has the third dimension (after you make your layer a 3D layer, of course). You could feed *v* into the z property of the array to have the layer orbit in the fashion of something like Saturn’s rings. “…but, Steve, there’s no up or down in space!” you exclaim in a stupid, whine-y voice. Fine. It’s like a hula hoop. Get over yourself. The expression would look like this:

`s=effect("size")("Slider");`

d=degreesToRadians(effect("driver")("Angle"));

h=Math.sin(d);

v=-Math.cos(d);

([h,0,v]*s)+value

You’ll notice we just have to include a zero to keep the place of the dimension that isn’t using **Math.sin()** or **Math.cos()**. In the above case, the y-dimension will be 0. And the same rules apply as before. All of your other Transform properties will function like normal. Parenting won’t give you any unexpected results. Remember: if you find that your *driver* values are making your layer orbit in the wrong direction (as seen in the gif above), you can remove the negative on **Math.cos()**.

Away with you. (My Gist link for this expression: https://gist.github.com/thatsmadden/d31503aa3b4e03a76d3f)