Script Preset Manager for After Effects: The Ultimate Script & Extension Installer
If you’ve ever managed multiple scripts, ScriptUI panels, and extensions for Adobe After Effects, you know the pain of navigating directories, copying files, and ensuring compatibility across different AE versions. The Script Preset Manager—an advanced After Effects script—solves all these headaches with an intuitive, feature-rich management panel.
What is Script Preset Manager?
Script Preset Manager is an ExtendScript-powered After Effects utility designed to streamline the process of installing, organizing, and managing scripts, ScriptUI panels, and CEP extensions. It offers a graphical user interface (GUI) to easily browse your files, select your target After Effects version, and batch-install items—all with real-time progress feedback and robust error handling.
Key Features
1. Batch Install Scripts, ScriptUI Panels, and Extensions
- Drag & drop or select multiple files/folders.
- Install standard scripts (
.jsx
,.jsxbin
), ScriptUI panels, or CEP extensions. - Installs to the correct After Effects directories automatically.
2. Multi-Version Support
- Detects installed After Effects versions automatically.
- Lets you choose the target AE version from a dropdown.
- Works with both Roaming and Program Files Adobe directories.
3. Intelligent UI Filtering
- Filter your file list by type: All, JSX, jsxbin, Extension.
- Items are color-coded: green for scripts, purple for ScriptUI Panels, blue for extensions.
- Clear type indicators like
Script:
,ScriptUI Panel:
, orExtension:
.
4. Real-Time Logging & Progress
- Progress messages update in real time.
- Status text changes color: blue for ongoing actions, green for success, red for errors/warnings.
- All messages are also centered for easy readability.
5. Persistent Preferences
- Remembers your last-used folder and filter.
- Stores your preferences in a local JSON file for convenience.
6. Robust Error Handling
- Informs you of skipped files (already exist), errors during copy, or installation completion.
- Warnings and errors are highlighted for quick troubleshooting.
7. Cross-Platform Folder Scanning
- Scans standard Windows directories for After Effects installations and extensions.
- Easily updatable for Mac support (just adjust paths).
How Does It Work?
The script creates a resizable floating panel with three main sections:
- Available Files/Folders: Pick a folder, filter and select scripts, ScriptUI panels, or extensions.
- After Effects Versions: Choose the target AE version for installation.
- Installed Items: View all currently installed scripts/panels/extensions for the selected version.
Bottom buttons provide quick actions for refreshing the installed list, batch installing your selections, and viewing an About dialog.
Example Workflow
- Select Folder: Click “Select Folder” and choose your scripts/extensions directory.
- Filter and Select: Use the dropdown to filter by item type, then select the desired items.
- Pick AE Version: Choose your After Effects version from the middle dropdown.
- Install: Click “Install Scripts”, “Install ScriptUI”, or “Install Extension” as appropriate.
- Monitor Progress: Follow real-time color-coded status updates and check the installed list.
Why Use Script Preset Manager?
- Saves Time: Batch operations mean you no longer have to manually copy files for each script or extension.
- Reduces Errors: Smart filtering and built-in checks prevent accidental overwrites or incorrect installations.
- User-Friendly: Color-coded UI, persistent preferences, and clear progress indicators make it accessible for all users.
How to Install
- Download or copy the script code.
- Save it as
ScriptPresetManager.jsx
(or.jsxbin
) in your After Effects Scripts folder. - Launch After Effects and run the script from the File > Scripts menu.
Pro Tip: You can dock the Script Preset Manager for a seamless workflow!
Final Thoughts
Script Preset Manager is a must-have for any motion designer or technical director working with After Effects. Whether you’re an individual with dozens of personal scripts or a studio maintaining a toolkit for a whole team, this script will save you hours and minimize headaches.
(function() {
// --- JSON Polyfill if needed ---
if (typeof JSON !== "object" || typeof JSON.stringify !== "function") {
if (typeof JSON !== "object") { JSON = {}; }
JSON.stringify = function(obj) {
if (obj === null) { return "null"; }
switch (typeof obj) {
case "number":
case "boolean":
return String(obj);
case "string":
return '"' + obj.replace(/"/g, '\\"') + '"';
case "object":
if (obj instanceof Array) {
var elements = [];
for (var i = 0; i < obj.length; i++) {
elements.push(JSON.stringify(obj[i]));
}
return "[" + elements.join(",") + "]";
} else {
var props = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
props.push('"' + key + '":' + JSON.stringify(obj[key]));
}
}
return "{" + props.join(",") + "}";
}
}
return "";
};
JSON.parse = function(str) { return eval('(' + str + ')'); };
}
// -----------------------
// Preferences Management
// -----------------------
var PREFS_FILENAME = "ScriptPresetManagerPrefs.json";
function getPrefsFile() {
var scriptFile = new File($.fileName);
var prefsFile = new File(scriptFile.path + "/" + PREFS_FILENAME);
return prefsFile;
}
function loadPreferences() {
var prefsFile = getPrefsFile();
if (prefsFile.exists) {
prefsFile.open("r");
var content = prefsFile.read();
prefsFile.close();
try { return JSON.parse(content); } catch(e) { return {}; }
}
return {};
}
function savePreferences(prefs) {
var prefsFile = getPrefsFile();
if (prefsFile.open("w")) {
prefsFile.write(JSON.stringify(prefs));
prefsFile.close();
} else {
alert("Error: Unable to open preferences file for writing.");
}
}
var userPrefs = loadPreferences();
// -----------------------
// Logging & Progress
// -----------------------
var logMessages = [];
var redPen, greenPen, bluePen, defaultPen;
function initPens(control) {
try {
redPen = control.graphics.newPen(control.graphics.PenType.SOLID_COLOR, [1, 0, 0], 1);
greenPen = control.graphics.newPen(control.graphics.PenType.SOLID_COLOR, [0, 0.5, 0], 1);
bluePen = control.graphics.newPen(control.graphics.PenType.SOLID_COLOR, [0, 0, 1], 1);
defaultPen = control.graphics.newPen(control.graphics.PenType.SOLID_COLOR, [0, 0, 0], 1);
} catch (e) {
// Fallback: do nothing if setting pen fails.
}
}
// progressText will use its pen color based on log type.
function logMessage(message) {
logMessages.push(message);
progressText.text = message; // Update progress area text.
// Determine color:
if(message.match(/(Error|Skipped)/i)) {
try { progressText.graphics.foregroundColor = redPen; } catch(e) {}
} else if(message.match(/Installed\b/i)) {
try { progressText.graphics.foregroundColor = greenPen; } catch(e) {}
} else if(message.match(/Installing/i)) {
try { progressText.graphics.foregroundColor = bluePen; } catch(e) {}
} else {
try { progressText.graphics.foregroundColor = defaultPen; } catch(e) {}
}
// Force UI to update so progress text changes in real time.
win.update();
}
// -----------------------
// Helper functions
// -----------------------
function scanVersions(folderPath, filterFunc) {
var folder = new Folder(folderPath);
var versions = [];
if (folder.exists) {
var subFolders = folder.getFiles(function(f) {
return f instanceof Folder && filterFunc(f.name);
});
for (var i = 0; i < subFolders.length; i++) {
versions.push(subFolders[i].name);
}
}
return versions;
}
function arrayContains(arr, item) {
for (var i = 0; i < arr.length; i++) { if (arr[i] === item) { return true; } }
return false;
}
function compareVersions(a, b) {
var aParts = a.split(".").map(Number);
var bParts = b.split(".").map(Number);
if (aParts[0] !== bParts[0]) { return aParts[0] - bParts[0]; }
return (aParts[1] || 0) - (bParts[1] || 0);
}
// A folder qualifies as an extension if it contains a subfolder "CSXS" or an "index.html" file.
function isExtensionFolder(folder) {
var csxs = new Folder(folder.fsName + "/CSXS");
var indexHtml = new File(folder.fsName + "/index.html");
return csxs.exists || indexHtml.exists;
}
// Recursive folder copy.
function copyFolder(sourceFolder, targetFolder) {
if (!targetFolder.exists && !targetFolder.create()) {
logMessage("Error: Could not create folder " + targetFolder.fsName);
return false;
}
var items = sourceFolder.getFiles();
for (var i = 0; i < items.length; i++) {
var sourceItem = items[i];
var targetPath = targetFolder.fsName + "/" + sourceItem.name;
if (sourceItem instanceof Folder) {
var newTargetFolder = new Folder(targetPath);
if (!copyFolder(sourceItem, newTargetFolder)) { return false; }
} else if (sourceItem instanceof File) {
if (!sourceItem.copy(targetPath)) {
logMessage("Error: Copy failed for " + sourceItem.name);
return false;
}
}
}
return true;
}
// -----------------------
// Base Folders & Versions
// -----------------------
var username = $.getenv("USERNAME") || "username";
var aeRoamingBase = "C:\\Users\\" + username + "\\AppData\\Roaming\\Adobe\\After Effects";
var cepExtensionsBase = "C:\\Users\\" + username + "\\AppData\\Roaming\\Adobe\\CEP\\extensions";
var roamingVersions = scanVersions(aeRoamingBase, function(name) { return /^\d+(\.\d+)?$/.test(name); });
var aeProgramPath = "C:\\Program Files\\Adobe";
var programVersions = scanVersions(aeProgramPath, function(name) { return /After Effects/.test(name); });
var combined = roamingVersions.concat(programVersions);
var aeVersions = [];
for (var i = 0; i < combined.length; i++) { if (!arrayContains(aeVersions, combined[i])) { aeVersions.push(combined[i]); } }
if (aeVersions.length === 0) { aeVersions = ["24.0", "24.1", "24.2", "24.3", "24.4", "24.5", "25.0", "25.1", "25.2"]; }
aeVersions.sort(compareVersions);
// -----------------------
// Create UI
// -----------------------
var win = new Window("palette", "Script Preset Manager", undefined, { resizeable: true });
win.preferredSize = [1100, 700];
var mainGroup = win.add("group", undefined);
mainGroup.orientation = "row";
mainGroup.alignChildren = ["fill", "fill"];
var currentSelectedFolder = null;
// Left Panel: Available Files/Folders.
var leftPanel = mainGroup.add("panel", undefined, "Available Files/Folders");
leftPanel.orientation = "column";
leftPanel.alignChildren = ["fill", "top"];
leftPanel.margins = 10;
var btnSelectFolder = leftPanel.add("button", undefined, "Select Folder");
var fileFilterDropdown = leftPanel.add("dropdownlist", undefined, ["All", "JSX", "jsxbin", "Extension"]);
if(userPrefs.lastFilterIndex !== undefined) {
fileFilterDropdown.selection = fileFilterDropdown.items[userPrefs.lastFilterIndex];
} else {
fileFilterDropdown.selection = 0;
}
var fileList = leftPanel.add("listbox", undefined, [], { multiselect: true });
fileList.preferredSize = [400, 300];
// Middle Panel: After Effects Versions.
var midPanel = mainGroup.add("panel", undefined, "After Effects Versions");
midPanel.orientation = "column";
midPanel.alignChildren = ["fill", "top"];
midPanel.margins = 10;
var versionList = midPanel.add("dropdownlist", undefined, aeVersions);
if (versionList.items.length > 0) {
versionList.selection = versionList.items[versionList.items.length - 1];
}
// Right Panel: Installed Items.
var rightPanel = mainGroup.add("panel", undefined, "Installed Scripts, Panels & Extensions");
rightPanel.orientation = "column";
rightPanel.alignChildren = ["fill", "top"];
rightPanel.margins = 10;
var loadedList = rightPanel.add("listbox", undefined, [], { multiselect: false });
loadedList.preferredSize = [400, 300];
// Progress Area.
var progressGroup = win.add("group");
progressGroup.orientation = "row";
progressGroup.alignChildren = ["fill", "center"];
var progressText = progressGroup.add("statictext", undefined, "Progress: Idle");
progressText.preferredSize.width = 600;
progressText.alignment = "center"; // Center text
// Initialize pens with progressText.
initPens(progressText);
// Bottom Buttons.
var buttonGroup = win.add("group");
buttonGroup.orientation = "row";
buttonGroup.alignment = "center";
var btnRefresh = buttonGroup.add("button", undefined, "Refresh");
var btnInstallScripts = buttonGroup.add("button", undefined, "Install Scripts");
var btnInstallScriptUI = buttonGroup.add("button", undefined, "Install ScriptUI");
var btnInstallExtension = buttonGroup.add("button", undefined, "Install Extension");
var btnAbout = buttonGroup.add("button", undefined, "About");
// Category Colors.
var greenColor, purpleColor, blueColor;
try {
greenColor = fileList.graphics.newPen(fileList.graphics.PenType.SOLID_COLOR, [0, 0.5, 0], 1);
purpleColor = fileList.graphics.newPen(fileList.graphics.PenType.SOLID_COLOR, [0.5, 0, 0.5], 1);
blueColor = fileList.graphics.newPen(fileList.graphics.PenType.SOLID_COLOR, [0, 0, 1], 1);
} catch (e) {}
// -----------------------
// UI Event Handlers
// -----------------------
btnSelectFolder.onClick = function() {
var selectedFolder = Folder.selectDialog("Select the folder containing items (scripts, panels, or extensions)");
if (selectedFolder) {
userPrefs.lastSourceFolder = selectedFolder.fsName;
savePreferences(userPrefs);
currentSelectedFolder = selectedFolder;
fileList.removeAll();
var items = selectedFolder.getFiles("*");
var filter = fileFilterDropdown.selection.text;
userPrefs.lastFilterIndex = fileFilterDropdown.selection.index;
savePreferences(userPrefs);
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item instanceof File) {
// Replace %20 with space.
var fileName = item.name.replace(/%20/g, " ");
if ((/\.jsx$/i.test(fileName) || /\.jsxbin$/i.test(fileName)) &&
(filter === "All" ||
(filter === "JSX" && /\.jsx$/i.test(fileName)) ||
(filter === "jsxbin" && /\.jsxbin$/i.test(fileName)))) {
var listItem = fileList.add("item", "Script: " + fileName);
listItem.file = item;
listItem.itemType = "script";
try { listItem.graphics.foregroundColor = greenColor; } catch(e) {}
}
}
else if (item instanceof Folder) {
if (isExtensionFolder(item)) {
if (filter === "All" || filter === "Extension") {
// Decode the folder name as well.
var folderName = item.name.replace(/%20/g, " ");
var listItem = fileList.add("item", "Extension: " + folderName);
listItem.file = item;
listItem.itemType = "extension";
try { listItem.graphics.foregroundColor = blueColor; } catch(e) {}
}
} else {
var potentialFiles = item.getFiles(/\.(jsx|jsxbin)$/i);
if (potentialFiles.length > 0) {
if (filter === "All" || filter === "JSX" || filter === "jsxbin") {
// Decode the folder name as well.
var panelName = item.name.replace(/%20/g, " ");
var listItem = fileList.add("item", "ScriptUI Panel: " + panelName);
listItem.file = item;
listItem.itemType = "scriptFolder";
try { listItem.graphics.foregroundColor = purpleColor; } catch(e) {}
}
}
}
}
}
if(fileList.items.length === 0){
alert("No items matching the filter were found in the selected folder.");
}
}
};
function refreshInstalledList() {
loadedList.removeAll();
var version = versionList.selection ? versionList.selection.text : aeVersions[aeVersions.length - 1];
var baseFolder = aeRoamingBase + "\\" + version;
var foldersToCheck = [ "Scripts", "ScriptUI Panels", "Scripts\\ScriptUI Panels" ];
for (var i = 0; i < foldersToCheck.length; i++) {
var folderPath = baseFolder + "\\" + foldersToCheck[i];
var folder = new Folder(folderPath);
if (folder.exists) {
var items = folder.getFiles();
for (var j = 0; j < items.length; j++) {
if (items[j] instanceof File && (/\.jsx$/i.test(items[j].name) || /\.jsxbin$/i.test(items[j].name))) {
var decodedName = items[j].name.replace(/%20/g, " ");
loadedList.add("item", foldersToCheck[i] + ": " + decodedName);
}
}
}
}
var extFolder = new Folder(cepExtensionsBase);
if (extFolder.exists) {
var extItems = extFolder.getFiles();
for (var k = 0; k < extItems.length; k++) {
if (extItems[k] instanceof Folder && isExtensionFolder(extItems[k])) {
var decodedFolderName = extItems[k].name.replace(/%20/g, " ");
var listItem = loadedList.add("item", "Extension: " + decodedFolderName);
try { listItem.graphics.foregroundColor = blueColor; } catch(e) {}
}
}
}
}
// Batch install helper for Script and ScriptUI Panels.
// Updated batchInstall function with final message in green and centered.
function batchInstall(files, targetFolderName) {
if (!files || files.length === 0) {
alert("No files selected for installation.");
return;
}
var targetVersion = versionList.selection ? versionList.selection.text : aeVersions[aeVersions.length - 1];
var targetBaseFolder = aeRoamingBase + "\\" + targetVersion;
var targetFolder;
// For ScriptUI Panels, install under Scripts\ScriptUI Panels.
if(targetFolderName === "ScriptUI Panels") {
targetFolder = new Folder(targetBaseFolder + "\\Scripts\\" + targetFolderName);
} else {
targetFolder = new Folder(targetBaseFolder + "\\" + targetFolderName);
}
if (!targetFolder.exists) {
if (!targetFolder.create()) {
alert("Failed to create target folder: " + targetFolder.fsName);
return;
}
}
var installedCount = 0, skippedCount = 0;
for (var i = 0; i < files.length; i++) {
var listItem = files[i];
if (!listItem || !listItem.file) continue;
// Only process files (not folders).
if (listItem.file instanceof Folder) continue;
var sourceFile = listItem.file;
var targetFilePath = targetFolder.fsName + "/" + sourceFile.name;
var targetFile = new File(targetFilePath);
if (targetFile.exists) {
skippedCount++;
logMessage("Skipped (already exists): " + sourceFile.name);
continue;
}
logMessage("Installing " + sourceFile.name + " to " + targetFolderName + "...");
if (sourceFile.copy(targetFilePath)) {
installedCount++;
} else {
logMessage("Error installing: " + sourceFile.name);
}
}
// Set final progress message to green and ensure it is centered.
progressText.text = "Installation complete for " + targetFolderName + ".";
try { progressText.graphics.foregroundColor = greenPen; } catch(e) {}
win.update(); // Force UI update
refreshInstalledList();
alert("Batch install complete. Installed: " + installedCount + ", Skipped: " + skippedCount +
" file(s) to " + targetFolderName + " for version " + targetVersion + ".");
}
function batchInstallExtensions(files) {
if (!files || files.length === 0) {
alert("No extension folders selected for installation.");
return;
}
var installedCount = 0, skippedCount = 0;
for (var i = 0; i < files.length; i++) {
var listItem = files[i];
if (!listItem.file || !(listItem.file instanceof Folder)) continue;
if (!isExtensionFolder(listItem.file)) continue;
var sourceFolder = listItem.file;
var targetFolder = new Folder(cepExtensionsBase + "/" + sourceFolder.name);
if (targetFolder.exists) {
skippedCount++;
logMessage("Skipped (extension exists): " + sourceFolder.name);
continue;
}
logMessage("Installing extension " + sourceFolder.name + "...");
if (copyFolder(sourceFolder, targetFolder)) {
installedCount++;
} else {
logMessage("Error installing extension: " + sourceFolder.name);
}
}
alert("Batch extension install complete. Installed: " + installedCount + ", Skipped: " + skippedCount + " extension(s).");
refreshInstalledList();
}
btnRefresh.onClick = function() {
refreshInstalledList();
logMessage("Installed items list refreshed.");
alert("Installed items list refreshed.");
};
btnInstallScripts.onClick = function() {
var sel = fileList.selection;
var filesToInstall = (sel instanceof Array) ? sel : [sel];
// Install Scripts into the Scripts folder.
batchInstall(filesToInstall, "Scripts");
};
btnInstallScriptUI.onClick = function() {
var sel = fileList.selection;
var filesToInstall = (sel instanceof Array) ? sel : [sel];
// Install ScriptUI Panels into Scripts\ScriptUI Panels.
batchInstall(filesToInstall, "ScriptUI Panels");
};
btnInstallExtension.onClick = function() {
var sel = fileList.selection;
var filesToInstall = (sel instanceof Array) ? sel : [sel];
batchInstallExtensions(filesToInstall);
};
btnAbout.onClick = function() {
alert("Script Preset Manager\nVersion 1.0\n\nThis tool installs scripts, ScriptUI panels (installed under the Scripts folder), and extensions for After Effects.\n\nIt features progress logging (with blue text for progressing messages, red for warnings/errors, and green for successful installations), user preferences, and enhanced error handling.\n\nLeft section items display their type: 'Extension: ExtensionName', 'Script: ScriptName', 'ScriptUI Panel: ScriptUI Panel Name'.\n\nProgress and warning messages are centered in the panel.");
};
fileFilterDropdown.onChange = function() {
if (currentSelectedFolder) {
fileList.removeAll();
var items = currentSelectedFolder.getFiles("*");
var filter = fileFilterDropdown.selection.text;
userPrefs.lastFilterIndex = fileFilterDropdown.selection.index;
savePreferences(userPrefs);
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item instanceof File) {
var fileName = item.name;
if ((/\.jsx$/i.test(fileName) || /\.jsxbin$/i.test(fileName)) &&
(filter === "All" ||
(filter === "JSX" && /\.jsx$/i.test(fileName)) ||
(filter === "jsxbin" && /\.jsxbin$/i.test(fileName)))) {
var listItem = fileList.add("item", "Script: " + fileName);
listItem.file = item;
listItem.itemType = "script";
try { listItem.graphics.foregroundColor = greenColor; } catch(e) {}
}
} else if (item instanceof Folder) {
if (isExtensionFolder(item)) {
if (filter === "All" || filter === "Extension") {
var listItem = fileList.add("item", "Extension: " + item.name);
listItem.file = item;
listItem.itemType = "extension";
try { listItem.graphics.foregroundColor = blueColor; } catch(e) {}
}
} else {
var potentialFiles = item.getFiles(/\.(jsx|jsxbin)$/i);
if (potentialFiles.length > 0) {
if (filter === "All" || filter === "JSX" || filter === "jsxbin") {
var listItem = fileList.add("item", "ScriptUI Panel: " + item.name);
listItem.file = item;
listItem.itemType = "scriptFolder";
try { listItem.graphics.foregroundColor = purpleColor; } catch(e) {}
}
}
}
}
}
}
refreshInstalledList();
};
versionList.onChange = function() {
refreshInstalledList();
};
win.onResizing = win.onResize = function() {
this.layout.resize();
};
refreshInstalledList();
win.center();
win.show();
})();