
▲ 195 r/AfterEffects
Hey, I asked Gemini to write me a script to select fills and strokes with similar colors and it works so well. I'm sharing the code.
Create a Text Document.txt file wherever, copy the code inside, and save it as "SelectSameColor.jsx", make sure to delete the .txt at the end of the file name. Now you can run the script from After effects - File - Scripts - Run script file...
(function() {
var comp = app.project.activeItem;
if (!comp || !(comp instanceof CompItem)) {
alert("Please open and select an active composition first.");
return;
}
var selectedLayers = comp.selectedLayers;
if (selectedLayers.length !== 1) {
alert("Please select exactly ONE Shape Layer to search within.");
return;
}
var activeLayer = selectedLayers[0];
if (!(activeLayer instanceof ShapeLayer)) {
alert("The selected layer must be a Shape Layer.");
return;
}
// Grab the current selected property to use as our source color
var selectedProperties = activeLayer.selectedProperties;
var targetColor = null;
// Try to find a color property the user has highlighted manually
for (var i = 0; i < selectedProperties.length; i++) {
var p = selectedProperties[i];
if (p.propertyType === PropertyType.PROPERTY && (p.matchName === "ADBE Vector Fill Color" || p.matchName === "ADBE Vector Stroke Color")) {
targetColor = p.value;
break;
}
}
// Helper to recursively gather all color properties inside this layer
function getAllColorProperties(targetProps, results) {
for (var i = 1; i <= targetProps.numProperties; i++) {
var prop = targetProps.property(i);
if (prop.propertyType === PropertyType.PROPERTY) {
if (prop.matchName === "ADBE Vector Fill Color" || prop.matchName === "ADBE Vector Stroke Color") {
results.push(prop);
}
} else if (prop.propertyType === PropertyType.INDEXED_GROUP || prop.propertyType === PropertyType.NAMED_GROUP) {
getAllColorProperties(prop, results);
}
}
}
var allColorsInLayer = [];
getAllColorProperties(activeLayer.property("Contents"), allColorsInLayer);
if (allColorsInLayer.length === 0) {
alert("No Fill or Stroke colors found inside this layer.");
return;
}
// Fallback: If you didn't click a specific color property, default to the first one found
if (!targetColor) {
targetColor = allColorsInLayer[0].value;
}
// --- POPUP DIALOG FOR TOLERANCE PREFERENCE ---
var promptWindow = new Window("dialog", "Color Similarity Sensitivity");
promptWindow.orientation = "column";
promptWindow.alignChildren = ["center", "top"];
var textGroup = promptWindow.add("group");
textGroup.add("statictext", undefined, "Enter matching tolerance (0% - 100%):");
// Defaulting to 2% which safely catches tiny math variations but remains strict
var inputField = textGroup.add("edittext", undefined, "2");
inputField.characters = 5;
var buttonGroup = promptWindow.add("group");
var cancelBtn = buttonGroup.add("button", undefined, "Cancel", {name: "cancel"});
var okBtn = buttonGroup.add("button", undefined, "Match Colors", {name: "ok"});
if (promptWindow.show() !== 1) {
return; // User clicked cancel
}
// Parse user input and convert to a normalized 0-1 range
var userTolerance = parseFloat(inputField.text);
if (isNaN(userTolerance) || userTolerance < 0 || userTolerance > 100) {
alert("Please enter a valid percentage between 0 and 100.");
return;
}
var normalizedTolerance = userTolerance / 100;
// --- EXECUTE THE MATCHING ---
app.beginUndoGroup("Select Color with Tolerance");
// Array color comparison using the dialed tolerance
function colorsMatch(colorA, colorB, tolerance) {
// Evaluate Red, Green, and Blue channels individually
for (var i = 0; i < 3; i++) {
if (Math.abs(colorA[i] - colorB[i]) > tolerance) return false;
}
return true;
}
// First, clear any current internal property selections so we start clean
for (var k = 0; k < selectedProperties.length; k++) {
selectedProperties[k].selected = false;
}
// Select every property within tolerance inside the timeline
var matchCount = 0;
for (var c = 0; c < allColorsInLayer.length; c++) {
if (colorsMatch(allColorsInLayer[c].value, targetColor, normalizedTolerance)) {
allColorsInLayer[c].selected = true;
matchCount++;
}
}
app.endUndoGroup();
})();
u/CMDR_NICOTOR — 3 days ago