For purposes of character animation, imagine a library of pre-defined, keyframed actions which we could trigger whenever and as often as we want simply by dropping a layer marker where we want the animation begin. That would be pretty cool, right? So our goal here is to come up with a good way to trigger such animation snippets using markers. Ideally we'd like to be able to just drop a layer marker, use the name of the desired action as the marker comment, and have that trigger the desired animation. So, for example, if we dropped a layer marker with the comment "jump", that would trigger a previously defined action named "jump", and cause our character to jump.

There are a number of ways to approach this, but the best solutions require that an expression be able to retrieve the comment field of a layer marker. Fortunately that capability now exists in AE CS3. We'll also need to use the capability of accessing a marker by its comment field. For example, if you have a marker labeled "begin", you can get the time of that marker like this:

marker.key("begin").time

For demonstration purposes, we'll look at animating some simple expressive facial characteristics involving a character's eyes, eye lids, and brow. We'll define our different animation "actions" in precomps for each body part. Each action will be keyframed in these precomps with corresponding markers flagging the start of each animation. We'll use these precomps in our main "face" comp. We'll turn on time remapping for each of the precomps and apply a time remapping expression that will shift the time at each layer marker to the time of the corresponding action defined in the precomp.

Let's summarize. Our actions will be keyframed in precomps. The beginning of each action will be flagged with a marker with an appropriate comment. In our main comp, each precomp will be time remapped with an expression that adjusts the time so that markers applied in the main comp are synced up with the corresponding action markers in the precomp.

Once we have things wired up like this, we can animate our character simply by dropping layer markers in the main comp.

For simplicity and consistency, we'll create a layer in each precomp named "action" where the precomp's named markers will reside. We'll also set things up such that each precomp retains its name as a layer in the main comp (that is, it hasn't been renamed). These two design decisions will allow us to create an expression that will work for any precomp without modification. Just copy and paste, baby.

There's one other loose end we'll need to take care of. Since each precomp will define multiple actions in succession, we need to make our expression smart enough that when we trigger an action, the playback of that action stops before running into the next action.

Let's take a look at a couple of screen shots of how this looks once we get it set up.

What you're looking at in the illustration above is the composition for one of the character's body parts, in this case the brow. Note that the brow actually consists of three separate parts: the left eybrow, the right eyebrow, and the frown (wrinkles in the forhead). You'll notice that the top layer is a null that we have named "action" where we have placed layer markers naming each defined action. The actions were created by keyframing the position and rotation properties of the eye brows, and the tanget positions of a Bezier Warp effect applied to the frown. The keyframes at time zero define the resting or "norm" position. The other actions are given descriptive names. For example "norm>raise" moves the brow from the normal to a raised state, while "raise>norm" does just the opposite.

It's important to note that the timing relationship between actions in this comp is, for the most part, irrelevant. The timing of the actions will be established by the markers placed in the main comp. Let's take a look at the main comp.

The main comp contains the body part precomps. On each body part precomp layer, we have placed markers (with names matching the actions defined within that precomp) where we want the actions to occur. We are free to trigger an action whenever we want by simply dropping a marker on the appropriate precomp layer and giving it a name that matches an action.

For each body part precomp in the main comp, time remapping is turned on and the expression has been applied to the time remapping property. Let's take a look at the expression.


action = comp(name).layer("action");
 
n = 0;
if (marker.numKeys > 0){
  n = marker.nearestKey(time).index;
  if (marker.key(n).time > time){
    n--;
  }
}
 
if (n == 0){
  0
}else{
  m = marker.key(n);
  myComment = m.comment;
  t = time - m.time;
  try{
    actMarker = action.marker.key(myComment);
    if (action.marker.numKeys > actMarker.index){
      tMax = action.marker.key(actMarker.index + 1).time - actMarker.time;
    }else{
      tMax = action.outPoint - actMarker.time;
    }
    t = Math.min(t, tMax);
    actMarker.time + t;
  }catch (err){
    0
  }
}

Character animation "actions", triggered by layer markers.