Offset selected keyframes in ascending order in AE

Find out why the . goes before the /

Moderator: Paul Tuersley

Post Reply
Posts: 5
Joined: May 1st, 2015, 2:07 pm

Hi guys
I've been trying to create a script for offsetting keyframes in AE.
The problem is that I cannot make the keyframes to offset in ascending order. Visually each property that is above another property in the layer should be offset 2 keyframes to the right from the property below ( I tried sorting the properties by propertyIndex, but the indexes of the properties don't correspond to the ascending order, i.e. property with index 2 does not mean that it visually is situated above/below property with index 1 in the timeline. This is what happens:

Is there any way I can sort the properties in real ascending order, so that they always look like this:

Here is my code:

Code: Select all

var arr,ctr;
function offsetKeys()
         var curItem = app.project.activeItem;
          var selectedLayers = curItem['selectedLayers'];
          var ctro = 0;
          ctr = -1;
          arr = [];
         var allLayers = [];
          for(var g=0;g<selectedLayers.length;g++){
         allLayers.sort(function(a,b){return b.idx - a.idx}); //Sorting layers in ascending order
          for(var h=0;h<allLayers.length;h++){
            var lr = allLayers[h].lr;
            var props = lr.selectedProperties;

       var prop;
       for(var i=0;i<arr.length;i++){
           for(var k=0;k<arr[i].keys.length;k++)
            var idx = arr[i].keys[k];
            prop = idx.ma_pr;
            lay = idx.ma_lr;
            ctro = i*curItem.frameDuration*2; //offset keys with two frames
            var keyToCopy = idx.ma_key;
            var newTime = idx.ma_time + ctro;
            var keyToCopyValue  = idx.ma_value;
            var newKeyIndex = prop.addKey(newTime);
            prop.setSelectedAtKey(keyToCopy, false);
            prop.setValueAtKey(newKeyIndex, keyToCopyValue);

function describeOffsetKeys(lr,props){
   var tempA = [];
   for(var i=props.length-1;  i>=0 ;  i--){
        var prop = props[i];
        if (prop.propertyType == PropertyType.INDEXED_GROUP || prop.propertyType == PropertyType.NAMED_GROUP) describeOffsetKeys(lr,prop);
        else if (prop instanceof Property) {
            var selectedKeys = prop.selectedKeys;
            if (prop.canVaryOverTime && selectedKeys.length > 0) {
                    var inA = [];
                    for(var j=0;j<selectedKeys.length;j++){
                        var k = selectedKeys[j];
                        var obj = {} ;
                        obj.ma_time = prop.keyTime(k);
                        obj.ma_value = prop.keyValue(k);
                        obj.ma_key = k;
                        obj.ma_pr = prop;
                        obj.ma_lr = lr;
                    var prgr = prop;
                    while(prgr.propertyDepth > 2) prgr = prgr.parentProperty; //getting the actual property group property of  the current layer
                    inA.sort(function(a,b){return b.ma_time - a.ma_time});
    if(tempA.length > 0)
        tempA.sort(function(a,b){return b.pridx - a.pridx}); //Here I try to sort the properties in ascending order (bottom to top) but the indexes of the properties differ from the actual order in the layer
        for(var p = 0;p<tempA.length;p++){
Any help is much appreciated!
Posts: 4
Joined: March 6th, 2015, 6:33 am

how about using your script to generate expressions relative to the last layer ?
something like
thisComp.layer("your last layer").valueAtTime(time+(numLayers-index)*5/25)
Posts: 5
Joined: May 1st, 2015, 2:07 pm

Thanks themessers for your suggestion
Won't this offset the layers instead of the individual properties in each layer?
Posts: 5
Joined: May 1st, 2015, 2:07 pm

I just found the answer, after weeks of thinking over this. The problem was that each of the property is on a different depth. So, getting the just propertyIndex at the current depth of the property is irrelevant as it can be for example 3, but it's property depth is 5 and the outermost propertyIndex is 1. In that case lets say a property with index 2 and depth 2 and outermost index 2 seems with lower value, but visually it's below the previous property. So to get the total property index (to sum the whole depth path), we need to sum the property Index at each depth to the property(note that we are summing them as strings):

Code: Select all

var prgr = prop;
var idx = String(prgr.propertyIndex);
while(prgr.propertyDepth > 1) 
     prgr = prgr.parentProperty;
     idx = String(prgr.propertyIndex) + String(idx);
//highestDepth before each loop is reset to 0, because after we get the highest depth in the whole loop, we need to add zeros '0' to the smaller numbers
if(Number(idx) > highestDepth) highestDepth = Number(idx);
Post Reply