Welcome to the second part of the article about the After Effect / CSS 3D Transform transitions workflow : After Effects to CSS 3D workflow – Part 2 – Transposition.
Click here to see the main page of the article : http://www.turbodrive.tv/blog/css-3d-transitions-workflow-using-after-effects/

Part 2: After Effects transposition and JSON export

You should have the naming convention and the 3D scene structure in mind before continuing (otherwise, take a look at the first part).
This part will be dedicated to AE and coding JSX expressions and script (actually it’s Javascript).

3D Scene

Let’s create the CSS 3D Scene into After Effects : same containers and basic hierarchy to start.
I nest 3 compositions :

- stage composition
  └ interactiveContainer composition
    └ targetsContainer composition

For each composition size, I’ve chosen HDV 1280×720. I usually create my designs at this size. There are a several benefits :

  • it’s a 16:9 standard;
  • easy for adaptations (always think about multiple browser window sizes and ratios);
  • wide enough for a good resolution but not to much for working.

AE Focal Length to CSS Perspective equivalence

Although there is no real camera in CSS, there is the perspective property (http://www.w3schools.com/cssref/css3_pr_perspective.asp). It allows to define the distance between the view and the 3D elements. Actually it’s like the Zoom value in AE. The Zoom is also the same as the Focus Distance value (locked to Zoom by default) and directly related to the Focal Length of the camera. So if you wanna change a kind of Focal Length in CSS, your only option is to play with the perspective value.

Quick link to GreyscaleGorilla to see the focal length importance on the image and perspective distortion: http://greyscalegorilla.com/blog/tutorials/choosing-the-correct-focal-length-in-cinema-4d-cameras/

The perspective property in CSS has not been configured yet. Internally in Sprite3D.js, the default value is 800px. Let see how you can set up the value, relatively to a focal length value. To do that, start from the camera in After Effects.
Here I’m gonna set up the camera with a focal length of 28mm (wide angle). I like this value as it’s a good balance of a nice perspective / 3D feeling with only a slight geometry distortion.
This camera should be in the interactiveContainerAE, and remember, this camera must be stationary since the targetsContainer does the job of camera translations and rotations.

There are several ways to know the CSS perspective equivalence:

  1. In AE, in the Camera Settings panel, check the units are in pixels and take either the Zoom or Focus Distance (if Lock to Zoom checked)
  2. In AE again, when the camera is created, AE put it automatically at the right distance of the current content in the viewport. It allows to have 3D elements with Z position equals to zero looking the same as in 2D. It means this is the distance to have 3D elements in front of the camera with the exact same appearance as in 2D. In result, this value can be taken to calculate positions and scales and have pixel perfect elements, even at different distances from the camera.
    Anyway, take the Z position of the camera, it should be same as the Zoom value in the Camera Settings panel.
  3. Last but not least, you can calculate this distance (cssPerspective) with this formula (JS) :

I didn’t find out the formula used internally in AE, but adapted the equation from this good article : http://www.bobatkins.com/photography/technical/field_of_view.html.

I think this equation is the best way to get the CSS Perspective value. You can use it in your project to set up the CSS perspective or know the pixel perfect distance for a given viewport size (= browser window size) or focal length.
In my case, for a wide angle FCameraAE with a 28mm focal length, and a 1280×720 viewport size, the distance camera / targeted object is -995,56px.

SetRotateFirst() in After Effects

As you know, the setRotateFirst() method contributes to have a kind-of-camera (I’ve called it FCamera) in CSS. Since After Effects doesn’t deal with 3D transformations in same way as in CSS, you should recreate that behaviour for each of the involved compositions.


For each Sprite3D with setRotateFirst(false) I create 2 null objects in more than the comp as a 3d element itself. It’s the case for each FCamera targets (= targets3D). These should be created inside targetsContainer.

Let’s see the order of the transformation in CSS :

setRotateFirst(false) or default
└─> translate3d(x,y,z) rotateZ(rotZ) rotateY(rotY) rotateX(rotX);

And apply the same logic to our targets :

    ├── NULL [position and rotateZ]
    │   └── NULL [rotateY]                
    │       └── COMP [rotateX]        

setRotateFirst(false) setup

As you’re going to add dynamic expressions soon, for the moment it’s more simple to only configure one target3D. You’ll duplicate this set of layers composing a target3D later. If not, expect a bunch of copy/paste.

Here is a screenshot of the layers :

Take care about the value for each anchor point. It has to be {x:0, y:0, z:0} for all of the null objects in the project. Depending on the content (3D or 2D) of your targets3D, check or uncheck Collapse Transformation.


For the other elements with setRotateFirst(true), such as targetsContainer, it’s easier. Add only one null, as parent of the composition, it’s gonna manage the 3 rotation axis. The composition manages his own position itself.

      ├── NULL [rotationXYZ]
      │   └── COMP [position]

setRotateFirst(true) setup

TargetsContainer and its null must have an anchor point at {x:0, y:0, z:0}. The position will be dynamically modified later.

Serious setup

Now, the tricky part. I’m gonna recreate the Sure Target logic :

  • Adding one target3DController (null object) in interactiveContainer for controlling each target3D
  • Adding a slider to change the value of globalCamProgression
  • Scripting the interpolation function : calculating targetsContainer transformation based on the target3DControllers and the globalCamProgression value

Here is an overview, using the same kind of diagrams.


After Effects setup for FCamera and targets3D

1. target3DController for each target3D

In interactiveContainer, create a new null for each target3D (= null + null + composition). It’s better to give the same name to the nulls, composition and also the target3DController. In the diagram below, all of them are called “Page 1”.

2. link between target3DControllers and targets3D

It’s very useful to have the same name because you can use the value of the current name this.name to make easily a link between controllers and targetsContainers.
The target3DControllers controls targets3D from interactiveContainer. It’s pretty obvious since you see the results of the transition and FCamera from inside interactiveContainer, and nothing from inside targetsContainer. So, if you want to change the position or rotation of a target3D, you tweak the target3DController and never the target3D itself.

Let’s write the small expression for linking targets3D and controllers. Inside targetsContainer, you add these, or use the expression pick whip.

Null Object (position and rotationZ)

      – Position expression:
      – RotationZ expression:

Null Object (rotation Y only)

      – RotationY expression:

Composition (rotation X only)

      – RotationX expression:

When it’s done, you can finally duplicate these 3 layers for each targets3D you want (3 times in my case). Notice the AE alerts : when duplicated, AE increments the layer’s name. Since the expressions are related to the layer’s name, you should see linkage errors from broken expressions.


Just rename correctly each of the layers, and when it’s done, with the right target3DController and the right name, reactivate the expressions.


Finally, as you have duplicated the initiale composition (Page 1), you should replace each of the copy by the right composition (Drag and Drop + Option/Alt from the source to the comp you wanna replace, look at the gif above). In my case, I’ve 4 targets3D (12 layers : 8 nulls and 4 compositions) in targetsContainer and 4 targets3DControllers (4 nulls) in interactiveContainer, called : Page 1, Page 2, Page3 and Page 4.

3. Custom control / GlobalCamProgression Slider

Now come back in the interactiveContainer composition. You’re gonna link all the target3DControllers to FCamera ( = null+targetsContainer) and recreate the interpolation function you’ve seen in the first part.

To simplify this step, I’ve created a custom control, called “Custom TargetFCam”. It’s basically made from two types of controls :

  • a group of layer control, where you select the targets3DControllers involved in the FCamera transition.
  • a slider, which changes the globalCamProgression in the time.


For building my own custom controls, I use the BatchFrame tool online: http://www.batchframe.com/custom_controls/, or the new one http://www.batchframe.com/pseudo/custom-controls-creator.php). If you don’t know this and how to manage them, follow the instructions on the BatchFrame website.

Here is the code I put in PresetEffects.xml. There are 25 layers controls, change it depending on your needs.

Add this custom control to a new adjustment layer in interactiveContainer. I’ve called this layer “Pages And Camera Control”. Then, fill out the layer controls with all the target3DControllers you want. The order is important, and defined in which order the FCamera visits each of the targets.

Let’s code now!

Interpolation function for FCamera

This code is directly adapted from the JS version of the first part.
These main expression should to be written on the property “position” of the targetsContainer and on each of the 3 rotations properties of the null managing the targetsContainer rotations.

Here is the code for the common functions, commented :

For each of these properties, you get the value using the getValForProp() function. Add this line, following the functions seen just above :


      – Position return an array of 3 values [x, y, z] for the position :

Null Object

      – Rotation X:

      – Rotation Y:
      – Rotation Z:

Well! All the workflow is almost ready. Everything should be rightly plugged.
The transformations of each of the targets3D are controlled from the same place (interactiveContainer), and the targetsContainer should react when you move the globalCamProgression slider.
Make a try: add keyframes on the timeline for globalCamProgression and start a preview. The keyframes position on the timeline is not so important (just make it increasing, with values such as 1,2,3,4), in HTML this is interactive.

Moving the timeline’s playhead is the same as playing with the slider of range-input on the HTML page.

In the same way as the custom control “Custom TargetFCam”, I’ve also added another custom control of 50 independent layer controls. It allows to export objects3D freely placed in space, with the same setRotateFirst(false) behaviour, but without any link to the FCamera and the transitions. In this project, I used it for exporting the white cubes.

Export Target3D properties to JSON

You can manipulate the target3DControllers as you want to change the path or only if you wanna tweak the positions of the targets3D in space. When you’re satisfied, you can collect coordinates from each of the target3DControllers (and other objects controllers, like the white cubes, even if they don’t control camera’s targets) and you can come back to affect the Sprites3D into the HTML page.

After few tests doing back-and-forth between AE and JS, I looked for a way to automate data export. So I’ve written a JSX script. To make it work, yout must select the layer with the custom control “Custom TargetFCam” and then execute the script.
Take care, this script is made to work with the same custom controls as I’ve done (with match-name “Custom TargetFCam” and “3dLayer_Exporter”). Change it as you like if you want to export your properties from your own controls and layers.

The script is commented and pretty easy to read. Just notice how manipulate the After Effects hierarchy object and how to access the properties value. It’s a bit different than using expressions.
More details in the scripting guide : http://blogs.adobe.com/aftereffects/files/2012/06/After-Effects-CS6-Scripting-Guide.pdf


Your JSON file should look like this :

It’s done for the setup of the scene and the workflow !
In the next and last part, you’ll see how to adjust your CSS 3D Scene with the data loaded from the JSON file, change the viewport size depending on the browser window and a bunch of enhancements.