Copy link to clipboard
Copied
Hey!
I'm working on an After Effects script that involves two main functions, Step 2 and Step 2.5, which I'm trying to merge. Individually, they work as intended, but integration has hit a snag, especially concerning properties with separated dimensions.
Step 2 (Universal Keyframe Detection & Expression Application): This part duplicates a layer and aims to apply a placeholder expression to any property with keyframes. However, it struggles specifically with properties that have separated dimensions (like "Position" into "X Position" and "Y Position"), not applying expressions as needed.
Step 2.5 (Handling Separated Dimensions and Orientation): Focused on properties with separated dimensions, this script part effectively duplicates a layer, clears keyframes, and applies expressions for separated dimensions and the "Orientation" property on 3D layers.
Challenge: The main issue arises when trying to integrate Step 2's broad keyframe handling with Step 2.5's specialized approach for separated dimensions and "Orientation." The expected seamless application of placeholder expressions to properties with separated dimensions (XYZ properties) in Step 2 does not occur, leading to errors like "property or a parent property is hidden."
Request for Advice: I need to create a unified script that can:
I'd greatly appreciate any insights on how to address the issue with separated dimensions in Step 2 or any tips for successfully integrating these functionalities.
Thanks for your support and guidance!
The below is script Step 2.0
#target aftereffects
(function createComprehensiveDelaySetupUI(thisObj) {
var scriptName = "Complete Delay Setup with Keyframe Removal";
function createUI(thisObj) {
var panel = (thisObj instanceof Panel) ? thisObj : new Window("palette", scriptName, undefined, {resizeable:true});
if (!panel) return null;
panel.add("button", undefined, "Apply Keyframe Removal", {name: "applyBtn"}).onClick = function() {
applyKeyframeRemoval();
};
panel.onResizing = panel.onResize = function() { this.layout.resize(); };
panel.layout.layout(true);
return panel;
}
function applyKeyframeRemoval() {
var comp = app.project.activeItem;
if (!comp || !(comp instanceof CompItem)) {
alert("Please select a composition.");
return;
}
var selectedLayers = comp.selectedLayers;
if (selectedLayers.length !== 1) {
alert("Please select exactly one layer.");
return;
}
app.beginUndoGroup(scriptName);
var baseLayer = selectedLayers[0];
var delayLayer = baseLayer.duplicate();
delayLayer.name = baseLayer.name + " Delay 01";
removeAllKeyframesAndApplyExpression(delayLayer);
app.endUndoGroup();
}
function removeAllKeyframesAndApplyExpression(layer) {
traverseProperties(layer, function(prop) {
if (prop.numKeys > 0) {
for (var k = prop.numKeys; k >= 1; k--) {
prop.removeKey(k);
}
prop.expression = "\"Placeholder expression for removed keyframes\"";
}
});
}
function traverseProperties(group, callback) {
for (var i = 1; i <= group.numProperties; i++) {
var prop = group.property(i);
if (!prop) continue;
if (prop.propertyType === PropertyType.PROPERTY) {
callback(prop);
} else if (prop.propertyType === PropertyType.INDEXED_GROUP || prop.propertyType === PropertyType.NAMED_GROUP) {
traverseProperties(prop, callback); // Recurse into groups
}
}
}
var myScriptPal = createUI(thisObj);
if (myScriptPal instanceof Window) {
myScriptPal.center();
myScriptPal.show();
} else {
myScriptPal.layout.layout(true);
}
})();
The script below is Step 2.5
#target aftereffects
(function createDelaySetupUI(thisObj) {
var scriptName = "Comprehensive Delay Setup for Separated Dimensions and Orientation";
function createUI(thisObj) {
var panel = (thisObj instanceof Panel) ? thisObj : new Window("palette", scriptName, undefined, {resizeable: true});
if (!panel) return null;
panel.add("button", undefined, "Apply Delay Setup", {name: "applyBtn"}).onClick = function() {
applyExpressionsToSeparatedPropertiesAndOrientation();
};
panel.onResizing = panel.onResize = function() { this.layout.resize(); };
panel.layout.layout(true);
return panel;
}
function applyExpressionsToSeparatedPropertiesAndOrientation() {
var comp = app.project.activeItem;
if (!comp || !(comp instanceof CompItem)) {
alert("Please select a composition.");
return;
}
var selectedLayers = comp.selectedLayers;
if (selectedLayers.length !== 1) {
alert("Please select exactly one layer.");
return;
}
app.beginUndoGroup(scriptName);
var baseLayer = selectedLayers[0];
var delayLayer = baseLayer.duplicate();
delayLayer.name = baseLayer.name + " Delay 01";
clearAndApplyExpressionIfKeyframed(delayLayer, "position");
if (delayLayer.threeDLayer) {
clearAndApplyExpressionIfKeyframed(delayLayer, "rotation");
handleOrientationIfKeyframed(delayLayer); // Handle Orientation for 3D layers
}
app.endUndoGroup();
}
function clearAndApplyExpressionIfKeyframed(layer, propName) {
// This checks for separated dimensions in position and rotation and applies expressions if they had keyframes
var dimensions = propName === "position" ? ['X Position', 'Y Position', (layer.threeDLayer ? 'Z Position' : null)] :
['X Rotation', 'Y Rotation', 'Z Rotation'];
dimensions.forEach(function(dimName) {
if (dimName && layer.transform[dimName] && layer.transform[dimName].numKeys > 0) {
var dimProp = layer.transform[dimName];
while (dimProp.numKeys > 0) {
dimProp.removeKey(1);
}
dimProp.expression = "\"Delayed expression for " + dimName + "\"";
}
});
}
function handleOrientationIfKeyframed(layer) {
// This function specifically handles the Orientation property for 3D layers
var orientationProp = layer.transform.orientation;
if (orientationProp.numKeys > 0) {
while (orientationProp.numKeys > 0) {
orientationProp.removeKey(1);
}
orientationProp.expression = "\"Delayed expression for Orientation\"";
}
}
var myScriptPal = createUI(thisObj);
if (myScriptPal instanceof Window) {
myScriptPal.center();
myScriptPal.show();
} else {
myScriptPal.layout.layout(true);
}
})();
Copy link to clipboard
Copied
I don't have the time to understand your issue in full detail, but if you run into issues, where you try to change expresssions or keyframes on hidden properties, maybe before doing this you can
- add a check if the property is a separation leader and also dimensions are separated and if this is the case, you process not the property itself, but the separation followers instead.
- analogously also check if the prop is a separation follower and dimensions are not separated (and in that case process the leader instead).