shinsuke matsumoto's blog thing.


Sometimes we, AE users, want to nudge keyframes to precise frame in several reasons. For example, in case of you stretch the keyframes by dragging them with holding down Option/Alt key, some keyframes don’t line up to the frames (like the image below).
This time I share my code to tweak keyframes in those situation.

Drag Keyframes Sample
Seeing is always better than reading, right?

Okay, here’s the code for you. This one called “keyframeCorrect” is to nudge the keyframes between frames to the nearest frame. Please take a look.

[Script Code]

app.beginUndoGroup("Keyframe Correct");
var curComp = app.project.activeItem;
if(curComp != null && curComp instanceof CompItem){
    var selectedProps = curComp.selectedProperties;
    if(selectedProps.length > 0){
        var targetKeyframesData = new Array();
        for(var i = 0; i < selectedProps.length; i++){ if(selectedProps[i].numKeys > 0){
                targetKeyframesData.push([selectedProps[i], selectedProps[i].selectedKeys]);
            }
        }
        if(targetKeyframesData.length > 0){
            for(var j = 0; j < targetKeyframesData.length; j++){
                for(var k = 0; k < targetKeyframesData[j][1].length; k++){
                    correctKeyframe(curComp, targetKeyframesData[j][0], targetKeyframesData[j][1][k]);
                }
            }
        } else {
            alert("Select a keyframe at least.", "Keyframe Correct");
        }
    } else {
        alert("Select a keyframe at least.", "Keyframe Correct");
    }
} else {
    alert("Select a composition first.", "Keyframe Correct");
}
app.endUndoGroup();



function correctKeyframe(theComp, targetProp, keyframeIndex){
    try{
        var originalTime, correctedTime, originalValue, keyInInterpolationType, keyOutInterpolationType, keyInTemporalEase, keyOutTemporalEase, keyTemporalAutoBezier, keyTemporalContinuous, keySpatialAutoBezier, keySpatialContinuous, keyInSpatialTangent, keyOutSpatialTangent;
        var prevKeyframeKeyInInterpolationType, prevKeyframeKeyOutInterpolationType, prevKeyframeKeyInTemporalEase, prevKeyframeKeyOutTemporalEase, prevKeyframeKeyTemporalAutoBezier, prevKeyframeKeyTemporalContinuous, prevKeyframeKeySpatialAutoBezier, prevKeyframeKeySpatialContinuous, prevKeyframeKeyInSpatialTangent, prevKeyframeKeyOutSpatialTangent;
        var nextKeyframeKeyInInterpolationType, nextKeyframeKeyOutInterpolationType, nextKeyframeKeyInTemporalEase, nextKeyframeKeyOutTemporalEase, nextKeyframeKeyTemporalAutoBezier, nextKeyframeKeyTemporalContinuous, nextKeyframeKeySpatialAutoBezier, nextKeyframeKeySpatialContinuous, nextKeyframeKeyInSpatialTangent, nextKeyframeKeyOutSpatialTangent;
        originalTime = targetProp.keyTime(keyframeIndex);
        if((originalTime / theComp.frameDuration) % 1 != 0){
            correctedTime = Math.round(originalTime / theComp.frameDuration) * theComp.frameDuration;
            originalValue = targetProp.keyValue(keyframeIndex);
            keyInInterpolationType = targetProp.keyInInterpolationType(keyframeIndex);
            keyOutInterpolationType = targetProp.keyOutInterpolationType(keyframeIndex);
            keyInTemporalEase =  targetProp.keyInTemporalEase(keyframeIndex);
            keyOutTemporalEase = targetProp.keyOutTemporalEase(keyframeIndex);
            keyTemporalAutoBezier = targetProp.keyTemporalAutoBezier(keyframeIndex);
            keyTemporalContinuous = targetProp.keyTemporalContinuous(keyframeIndex);
            if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                keySpatialAutoBezier = targetProp.keySpatialAutoBezier(keyframeIndex);
                keySpatialContinuous = targetProp.keySpatialContinuous(keyframeIndex);
                keyInSpatialTangent = targetProp.keyInSpatialTangent(keyframeIndex);
                keyOutSpatialTangent = targetProp.keyOutSpatialTangent(keyframeIndex);
            }
            if(keyframeIndex == 1){
                nextKeyframeKeyInInterpolationType = targetProp.keyInInterpolationType(keyframeIndex + 1);
                nextKeyframeKeyOutInterpolationType = targetProp.keyOutInterpolationType(keyframeIndex + 1);
                nextKeyframeKeyInTemporalEase = targetProp.keyInTemporalEase(keyframeIndex + 1);
                nextKeyframeKeyOutTemporalEase = targetProp.keyOutTemporalEase(keyframeIndex + 1);
                nextKeyframeKeyTemporalAutoBezier = targetProp.keyTemporalAutoBezier(keyframeIndex + 1);
                nextKeyframeKeyTemporalContinuous = targetProp.keyTemporalContinuous(keyframeIndex + 1);
                if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                    nextKeyframeKeySpatialAutoBezier = targetProp.keySpatialAutoBezier(keyframeIndex + 1);
                    nextKeyframeKeySpatialContinuous = targetProp.keySpatialContinuous(keyframeIndex + 1);
                    nextKeyframeKeyInSpatialTangent = targetProp.keyInSpatialTangent(keyframeIndex + 1);
                    nextKeyframeKeyOutSpatialTangent = targetProp.keyOutSpatialTangent(keyframeIndex + 1);
                }
            } else if(keyframeIndex == targetProp.numKeys){
                prevKeyframeKeyInInterpolationType = targetProp.keyInInterpolationType(keyframeIndex - 1);
                prevKeyframeKeyOutInterpolationType = targetProp.keyOutInterpolationType(keyframeIndex - 1);
                prevKeyframeKeyInTemporalEase = targetProp.keyInTemporalEase(keyframeIndex - 1);
                prevKeyframeKeyOutTemporalEase = targetProp.keyOutTemporalEase(keyframeIndex - 1);
                prevKeyframeKeyTemporalAutoBezier = targetProp.keyTemporalAutoBezier(keyframeIndex - 1);
                prevKeyframeKeyTemporalContinuous = targetProp.keyTemporalContinuous(keyframeIndex - 1);
                if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                    prevKeyframeKeySpatialAutoBezier = targetProp.keySpatialAutoBezier(keyframeIndex - 1);
                    prevKeyframeKeySpatialContinuous = targetProp.keySpatialContinuous(keyframeIndex - 1);
                    prevKeyframeKeyInSpatialTangent = targetProp.keyInSpatialTangent(keyframeIndex - 1);
                    prevKeyframeKeyOutSpatialTangent = targetProp.keyOutSpatialTangent(keyframeIndex - 1);
                }
            } else {
                prevKeyframeKeyInInterpolationType = targetProp.keyInInterpolationType(keyframeIndex - 1);
                prevKeyframeKeyOutInterpolationType = targetProp.keyOutInterpolationType(keyframeIndex - 1);
                prevKeyframeKeyInTemporalEase = targetProp.keyInTemporalEase(keyframeIndex - 1);
                prevKeyframeKeyOutTemporalEase = targetProp.keyOutTemporalEase(keyframeIndex - 1);
                prevKeyframeKeyTemporalAutoBezier = targetProp.keyTemporalAutoBezier(keyframeIndex - 1);
                prevKeyframeKeyTemporalContinuous = targetProp.keyTemporalContinuous(keyframeIndex - 1);
                nextKeyframeKeyInInterpolationType = targetProp.keyInInterpolationType(keyframeIndex + 1);
                nextKeyframeKeyOutInterpolationType = targetProp.keyOutInterpolationType(keyframeIndex + 1);
                nextKeyframeKeyInTemporalEase = targetProp.keyInTemporalEase(keyframeIndex + 1);
                nextKeyframeKeyOutTemporalEase = targetProp.keyOutTemporalEase(keyframeIndex + 1);
                nextKeyframeKeyTemporalAutoBezier = targetProp.keyTemporalAutoBezier(keyframeIndex + 1);
                nextKeyframeKeyTemporalContinuous = targetProp.keyTemporalContinuous(keyframeIndex + 1);
                if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                    prevKeyframeKeySpatialAutoBezier = targetProp.keySpatialAutoBezier(keyframeIndex - 1);
                    prevKeyframeKeySpatialContinuous = targetProp.keySpatialContinuous(keyframeIndex - 1);
                    prevKeyframeKeyInSpatialTangent = targetProp.keyInSpatialTangent(keyframeIndex - 1);
                    prevKeyframeKeyOutSpatialTangent = targetProp.keyOutSpatialTangent(keyframeIndex - 1);
                    nextKeyframeKeySpatialAutoBezier = targetProp.keySpatialAutoBezier(keyframeIndex + 1);
                    nextKeyframeKeySpatialContinuous = targetProp.keySpatialContinuous(keyframeIndex + 1);
                    nextKeyframeKeyInSpatialTangent = targetProp.keyInSpatialTangent(keyframeIndex + 1);
                    nextKeyframeKeyOutSpatialTangent = targetProp.keyOutSpatialTangent(keyframeIndex + 1);
                }
            }
            targetProp.removeKey(keyframeIndex);
            targetProp.setValueAtTime(correctedTime, originalValue);
            targetProp.setTemporalEaseAtKey(keyframeIndex, keyInTemporalEase, keyOutTemporalEase);
            targetProp.setInterpolationTypeAtKey(keyframeIndex, keyInInterpolationType, keyOutInterpolationType);
            targetProp.setTemporalContinuousAtKey(keyframeIndex, keyTemporalContinuous);
            targetProp.setTemporalAutoBezierAtKey(keyframeIndex, keyTemporalAutoBezier);
            if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                targetProp.setSpatialTangentsAtKey(keyframeIndex, keyInSpatialTangent, keyOutSpatialTangent);
                targetProp.setSpatialAutoBezierAtKey(keyframeIndex, keySpatialAutoBezier);
                targetProp.setSpatialContinuousAtKey(keyframeIndex, keySpatialContinuous);
            }
            if(keyframeIndex == 1){
                targetProp.setTemporalEaseAtKey(keyframeIndex + 1, nextKeyframeKeyInTemporalEase, nextKeyframeKeyOutTemporalEase);
                targetProp.setInterpolationTypeAtKey(keyframeIndex + 1, nextKeyframeKeyInInterpolationType, nextKeyframeKeyOutInterpolationType);
                targetProp.setTemporalContinuousAtKey(keyframeIndex + 1, nextKeyframeKeyTemporalContinuous);
                targetProp.setTemporalAutoBezierAtKey(keyframeIndex + 1, nextKeyframeKeyTemporalAutoBezier);
                if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                    targetProp.setSpatialTangentsAtKey(keyframeIndex + 1, nextKeyframeKeyInSpatialTangent, nextKeyframeKeyOutSpatialTangent);
                    targetProp.setSpatialAutoBezierAtKey(keyframeIndex + 1, nextKeyframeKeySpatialAutoBezier);
                    targetProp.setSpatialContinuousAtKey(keyframeIndex + 1, nextKeyframeKeySpatialContinuous);
                }
            } else if(keyframeIndex == targetProp.numKeys){
                targetProp.setTemporalEaseAtKey(keyframeIndex - 1, prevKeyframeKeyInTemporalEase, prevKeyframeKeyOutTemporalEase);
                targetProp.setInterpolationTypeAtKey(keyframeIndex - 1, prevKeyframeKeyInInterpolationType, prevKeyframeKeyOutInterpolationType);
                targetProp.setTemporalContinuousAtKey(keyframeIndex - 1, prevKeyframeKeyTemporalContinuous);
                targetProp.setTemporalAutoBezierAtKey(keyframeIndex - 1, prevKeyframeKeyTemporalAutoBezier);
                if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                    targetProp.setSpatialTangentsAtKey(keyframeIndex - 1, prevKeyframeKeyInSpatialTangent, prevKeyframeKeyOutSpatialTangent);
                    targetProp.setSpatialAutoBezierAtKey(keyframeIndex - 1, prevKeyframeKeySpatialAutoBezier);
                    targetProp.setSpatialContinuousAtKey(keyframeIndex - 1, prevKeyframeKeySpatialContinuous);
                }
            } else {
                targetProp.setTemporalEaseAtKey(keyframeIndex - 1, prevKeyframeKeyInTemporalEase, prevKeyframeKeyOutTemporalEase);
                targetProp.setInterpolationTypeAtKey(keyframeIndex - 1, prevKeyframeKeyInInterpolationType, prevKeyframeKeyOutInterpolationType);
                targetProp.setTemporalContinuousAtKey(keyframeIndex - 1, prevKeyframeKeyTemporalContinuous);
                targetProp.setTemporalAutoBezierAtKey(keyframeIndex - 1, prevKeyframeKeyTemporalAutoBezier);
                targetProp.setTemporalEaseAtKey(keyframeIndex + 1, nextKeyframeKeyInTemporalEase, nextKeyframeKeyOutTemporalEase);
                targetProp.setInterpolationTypeAtKey(keyframeIndex + 1, nextKeyframeKeyInInterpolationType, nextKeyframeKeyOutInterpolationType);
                targetProp.setTemporalContinuousAtKey(keyframeIndex + 1, nextKeyframeKeyTemporalContinuous);
                targetProp.setTemporalAutoBezierAtKey(keyframeIndex + 1, nextKeyframeKeyTemporalAutoBezier);
                if(targetProp.propertyValueType == PropertyValueType.TwoD_SPATIAL || targetProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL){
                    targetProp.setSpatialTangentsAtKey(keyframeIndex - 1, prevKeyframeKeyInSpatialTangent, prevKeyframeKeyOutSpatialTangent);
                    targetProp.setSpatialAutoBezierAtKey(keyframeIndex - 1, prevKeyframeKeySpatialAutoBezier);
                    targetProp.setSpatialContinuousAtKey(keyframeIndex - 1, prevKeyframeKeySpatialContinuous);
                    targetProp.setSpatialTangentsAtKey(keyframeIndex + 1, nextKeyframeKeyInSpatialTangent, nextKeyframeKeyOutSpatialTangent);
                    targetProp.setSpatialAutoBezierAtKey(keyframeIndex + 1, nextKeyframeKeySpatialAutoBezier);
                    targetProp.setSpatialContinuousAtKey(keyframeIndex + 1, nextKeyframeKeySpatialContinuous);
                }
            }
        }
    } catch(err){
        alert("Error at line # " + err.line.toString() + "\r" + err.toString());
    }
}

 

[Quick Explanation]
Copy the code & past them into Adobe ExtendScript Toolkit. And in AE, select keyframes you want to adjust, then running the script. So keyframeCorrect script will nudge the keyframes to the nearst frame.

If you have a great script called “ft-Toolbar2” from aescripts, it’s ultra easy to use this script. Create the new button as Javascript in the setting menu in ft-Toolbar2, and then copy & paste the code into the command field like below. So you can nudge the keyframes you select with a click.

I know this is a bit long code and you might feel like it’s not smart. I think I can brush it up a little but this is a quick & dirty stuff for my practice. So don’t expect too much as always.

Anyway, I would much appreciate it if you could give me a feedback. So please don’t hesitate to get in touch with me if you find some errors or better ways. And if you have any request for the series, hit me up on my Twitter. And if you don’t have time to read my crappy article, please follow & check my codes on my GitHub Gist.

[Update]
Now you can download the simple button version of this script via Gumroad. It might be more useful if you don’t have great ft-Toolbar2 script.

 

[Tiny Inside Story]
A little while ago, talented mographer Ryan Woolfolk got in touch with me via twitter about script request. I think it’s nice to write code with his idea for my practice. He liked this tiny script, so I decided to share it in this series. Thank you Ryan for your idea!

Advertisements

6 Responses to “Crap Sharing for AE Scripting: keyframeCorrect”

    • beatgram

      Hope it’s useful for mographers to concentrate on keyframing. Please spread the word if you love it.

      Reply
  1. Yuan

    So useful. Thanks!
    I know it is really long for moving a keyframe via script.

    Reply
    • beatgram

      My pleasure! Yeah, it’s a bit complicated but worth doing for avoiding tedious tasks.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Basic HTML is allowed. Your email address will not be published.

Subscribe to this comment feed via RSS

%d bloggers like this: