Initial commit

This commit is contained in:
Kyle Harter
2026-08-10 17:35:22 -04:00
committed by GitHub
commit a76c43c97e
35 changed files with 12121 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
node_modules/
docs/
+19
View File
@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "extendscript-debug",
"request": "attach",
"name": "Attach to ExtendScript Engine"
},
{
"type": "extendscript-debug",
"request": "launch",
"name": "Launch Script in ExtendScript Engine"
}
]
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Kyle Harter
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+53
View File
@@ -0,0 +1,53 @@
### Introduction to [script-name]
Introducing [script-name] - an easy-to-use After Effects script that helps to [complete a specific task]
Notable features include:
-
---
### Installing [script-name]
[script-name]**.jsxbin** must be placed in the Scripts directory in the After Effects
folder. That folder will be named “Adobe After Effects [version]” which has been
replaced with “AE” below.
Mac OS X
`/Applications/AE/Scripts/ScriptUI Panels`
Windows
`\Program Files\AE\Support Files\Scripts\ScriptUI Panels`
If After Effects was running when you installed the script, youll need to restart it. Also, youll need to allow After Effects to write files.
To do that follow this path: `Preferences > General > Check-off “Allow Scripts to Write Files and Access Network” > Close Preferences`
---
### Launching [script-name]
When properly installed, you will find **[script-name].jsxbin** under the File > Scripts menu in After Effects.
---
### [Insert Image of Script UI Panel if there is one]
---
### How to use [script-name]
- Step 1:
- Step 2:
- Step 3:
Thank you so much for getting [script-name]! I hope youll save time using this tool, and use that time to make your best work.
---
Feel free to write me, Kyle Harter, at **kylenmotion@gmail.com** if you run into any issues along the way. Thanks again! 
- Kyle Harter
BIN
View File
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
{
"labels": [
{"label": "HEADING", "prefix": "TEXT-HEADING"},
{"label": "SUBHEAD", "prefix": "TEXT-SUBHEAD"},
{"label": "EYEBROW", "prefix": "TEXT-EYEBROW"},
{"label": "BODY", "prefix": "TEXT-BODY"},
{"label": "BODYHEAD", "prefix": "TEXT-BODYHEAD"},
{"label": "CHART", "prefix": "TEXT-CHART"},
{"label": "DATA", "prefix": "TEXT-DATA"},
{"label": "GRAPH", "prefix": "TEXT-GRAPH"}
]
}
+13
View File
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "none",
"target": "ES3",
"noLib": true,
"checkJs": false,
"baseUrl": "./src",
"paths": {
"*": ["types/*"]
}
},
"include": ["src/**/*"]
}
+15
View File
@@ -0,0 +1,15 @@
{
"source": {
"include": ["src/library"],
"includePattern": ".jsx?$"
},
"opts": {
"destination": "docs",
"template": "node_modules/docdash"
},
"plugins": [],
"templates": {
"cleverLinks": true,
"monospaceLinks": true
}
}
+324
View File
@@ -0,0 +1,324 @@
{
"name": "ae-library-template",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ae-library-template",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"docdash": "^2.0.2",
"jsdoc": "^4.0.4"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz",
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.27.1"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/types": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz",
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@jsdoc/salty": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz",
"integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==",
"dev": true,
"dependencies": {
"lodash": "^4.17.21"
},
"engines": {
"node": ">=v12.0.0"
}
},
"node_modules/@types/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"dev": true
},
"node_modules/@types/markdown-it": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
"dev": true,
"dependencies": {
"@types/linkify-it": "^5",
"@types/mdurl": "^2"
}
},
"node_modules/@types/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"node_modules/catharsis": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
"integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
"dev": true,
"dependencies": {
"lodash": "^4.17.15"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/docdash": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/docdash/-/docdash-2.0.2.tgz",
"integrity": "sha512-3SDDheh9ddrwjzf6dPFe1a16M6ftstqTNjik2+1fx46l24H9dD2osT2q9y+nBEC1wWz4GIqA48JmicOLQ0R8xA==",
"dev": true,
"dependencies": {
"@jsdoc/salty": "^0.2.1"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
},
"node_modules/js2xmlparser": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
"integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
"dev": true,
"dependencies": {
"xmlcreate": "^2.0.4"
}
},
"node_modules/jsdoc": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz",
"integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.20.15",
"@jsdoc/salty": "^0.2.1",
"@types/markdown-it": "^14.1.1",
"bluebird": "^3.7.2",
"catharsis": "^0.9.0",
"escape-string-regexp": "^2.0.0",
"js2xmlparser": "^4.0.2",
"klaw": "^3.0.0",
"markdown-it": "^14.1.0",
"markdown-it-anchor": "^8.6.7",
"marked": "^4.0.10",
"mkdirp": "^1.0.4",
"requizzle": "^0.2.3",
"strip-json-comments": "^3.1.0",
"underscore": "~1.13.2"
},
"bin": {
"jsdoc": "jsdoc.js"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/klaw": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
"integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.1.9"
}
},
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"dev": true,
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdown-it-anchor": {
"version": "8.6.7",
"resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
"integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
"dev": true,
"peerDependencies": {
"@types/markdown-it": "*",
"markdown-it": "*"
}
},
"node_modules/marked": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"dev": true
},
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/requizzle": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz",
"integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==",
"dev": true,
"dependencies": {
"lodash": "^4.17.21"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"dev": true
},
"node_modules/underscore": {
"version": "1.13.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
"integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
"dev": true
},
"node_modules/xmlcreate": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
"integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
"dev": true
}
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "ae-library-template",
"version": "1.0.0",
"description": "A utility library for ExtendScript / After Effects scripting",
"scripts": {
"docs": "jsdoc -c jsdoc.json"
},
"keywords": [],
"author": "kyle harter",
"license": "MIT",
"devDependencies": {
"docdash": "^2.0.2",
"jsdoc": "^4.0.4"
}
}
BIN
View File
Binary file not shown.
+57
View File
@@ -0,0 +1,57 @@
var OS = (function(){
function isWindows() {
return $.os.indexOf("Windows") != -1;
};
function isMacOS(){
return !isWindows();
};
function openUrl(url){
if(isWindows()){
openUrlWin(url);
}
else {
openUrlMac(url);
}
}
function openUrlMac(url){
var command = 'open "'+url+'"';
system.callSystem(command);
}
function openUrlWin(url){
var command = 'start ' + url;
executeWinCommandlineCommand(command);
}
function executeWinCommandlineCommand(command){
var quotedCommand = quoteForWindowsCmd(command);
var outerCommand = "cmd /c \""+quotedCommand+"\"";
system.callSystem(outerCommand);
}
function quoteForWindowsCmd (string) {
// put a ^ before every META character that has a special meaning in CMD
var metaChars = ['^','(',')','%','!','"','<','>','&','|','\n'];
var prefix ="^"
for(var i=0; i< metaChars.length; i++){
string = replaceAll(string, metaChars[i],prefix+metaChars[i]);
}
return string;
};
function replaceAll(string, search, replace){
return string.split(search).join(replace);
};
return {
isWindows: isWindows,
isMacOS: isMacOS,
openUrl: openUrl
}
}())
File diff suppressed because one or more lines are too long
+14
View File
@@ -0,0 +1,14 @@
//@include "OS.jsx"
function joinPath(components){
var pathSeparator = getPathSeparatorSymbol();
return components.join(pathSeparator);
};
function getPathSeparatorSymbol(){
return (OS.isWindows() ? "\\":"/");
};
function getUserDataFolderPath(){
return Folder.userData.fsName;
};
+383
View File
@@ -0,0 +1,383 @@
/**
* Kyle Harter function library
* @module km-helper-functions
* @author kylenmotion@gmail.com
* @returns {object} returns exported modules to be used in other jsx files
*/
var kmFunction = (function () {
/**
* gets current project
* @function getProj
* @returns {object} current project
*/
function getProj() {
var proj = app.project;
if (!proj) {
alert(
"Whoops!\rYou don't have any projects open. Open a current project or create a new project and try again.",
);
return;
}
return proj;
}
/**
* gets the active comp
* @function getActiveComp
* @param {Project} proj - the current AE project
* @returns {CompItem} active composition object in ae project
*/
function getActiveComp(proj) {
var activeComp = proj.activeItem;
if (!(activeComp && activeComp instanceof CompItem)) {
alert(
"Whoops!\rYou don't have an comp item active. Open a comp item or select a comp item from the project panel and try again.",
);
return;
}
return activeComp;
}
/** gets selected comps as well as their names and unique ids in the project panel
* @function getSelectedComps
* @param {Project} proj - the current AE project
* @returns {object} an object that stores arrays of selected comp objects, names, and ids
*/
function getSelectedComps(proj) {
var comps = [];
var compNames = [];
var compIds = [];
var selectedItems = proj.selection;
if (selectedItems.length < 1) {
alert(
"Whoops!\rYou don't have any project items selected. Select at least 1 project item and try again.",
);
return;
}
var found = false;
for (var i = 0; i < selectedItems.length; i++) {
var item = selectedItems[i];
if (item instanceof CompItem) {
found = true;
comps.push(item);
compNames.push(item.name);
compIds.push(item.id);
}
}
if (!found) {
alert(
"Whoops!\rYou don't have any comp items selected. Select atleast 1 comp item and try again.",
);
return;
}
return {
comps: comps,
compNames: compNames,
compIds: compIds,
};
}
/**
* converts a hex code into a usable RGB array
* @function hexToRGB
* @param {string} hexValue - a 6-character string that makes up a hex code. Can be used with or without a '#'.
* @returns {Array} a 3 element array that makes up a full RGB value
*/
function hexToRGB(hexValue) {
var hexTrim = hexValue.trim();
var hexString = hexTrim;
var finalHex = hexString.replace(/[#]/g, "");
var hexColor = "0x" + finalHex;
var r = hexColor >> 16;
var g = (hexColor & 0x00ff00) >> 8;
var b = hexColor & 0xff;
return [r / 255, g / 255, b / 255];
}
/**
* gets selected layers in comp
* @function getSelectedLayers
* @param {CompItem} comp - current active or selected comp
* @return {Array} returns an array of selected layers in comp
*/
function getSelectedLayers(comp) {
if (!comp) return;
var selLayers = comp.selectedLayers;
if (selLayers.length < 1) {
alert(
"Whoops!\rYou don't have any layers selected in your comp. Select atleast 1 layer and try again.",
);
return;
}
return selLayers;
}
/**
* gets selected properties on a layer
* @function getSelectedProperties
* @param {LayerCollection} layers - current selected layers in active comp
* @return {array} selected keyframeable properties on a layer
*/
function getSelectedProperties(layers) {
if (!layers) return;
var selLayerProps = [];
var found = false;
for (var b = 0; b < layers.length; b++) {
var layer = layers[b];
var selProps = layer.selectedProperties;
for (var i = 0; i < selProps.length; i++) {
var prop = selProps[i];
if (prop.propertyType === PropertyType.PROPERTY && prop.canVaryOverTime) {
found = true;
selLayerProps.push(prop);
}
}
}
if (!found) {
alert(
"Whoops!\rYou don't have any keyframeable layer properties selected. Select atleast 1 keyframeable layer property and try again",
);
return;
}
return selLayerProps;
}
/**
* gets selected keyframes on layers in the comp
*
* @param {Object} props - selected properties on selected layers
* @return {Object} an object that stores arrays of selected keyframe objects, times, and values
*/
function getSelectedKeyframes(props) {
if (!props) return;
var selKeys = [];
var keyInSpatialTan = [];
var keyInTemporalEase = [];
var keyOutSpatialTan = [];
var keyOutTemporalEase = [];
var keyLabel = [];
var selKeyVal = [];
var found = false;
for (var i = 0; i < props.length; i++) {
var prop = props[i];
if (prop.selectedKeys.length > 0) {
found = true;
for (var k = 0; k < prop.selectedKeys.length; k++) {
var keyIndex = prop.selectedKeys[k];
selKeys.push(keyIndex);
selKeyVal.push(prop.keyValue(keyIndex));
keyInSpatialTan.push(prop.keyInSpatialTangent(keyIndex));
keyInTemporalEase.push(prop.keyInTemporalEase(keyIndex));
keyOutSpatialTan.push(prop.keyOutSpatialTangent(keyIndex));
keyOutTemporalEase.push(prop.keyOutTemporalEase(keyIndex));
keyLabel.push(prop.keyLabel(keyIndex));
}
}
}
if (!found) {
alert(
"Whoops!\rYou don't have any keyframes selected. Select atleast 1 keyframe and try again.",
);
return;
}
return {
selKeys: selKeys,
selKeyVal: selKeyVal,
keyInSpatialTan: keyInSpatialTan,
keyInTemporalEase: keyInTemporalEase,
keyOutSpatialTan: keyOutSpatialTan,
keyOutTemporalEase: keyOutTemporalEase,
keyLabel: keyLabel,
};
}
/**
* gets or creates a folder object based on the search term of the match string paramater
* @function getOrCreateFolder
* @param {object} proj - current AE project object
* @param {string} folderName - a valid string used to search for a folder name
* @return {object} - the folder object that was either created or found using the search parameter
*/
function getOrCreateFolder(proj, folderName) {
if (!proj) return;
if (typeof folderName !== "string") {
folderName = folderName.toString();
}
var folder = null;
for (var i = 1; i <= proj.numItems; i++) {
var item = proj.item(i);
if (item instanceof FolderItem && item.name === folderName) {
folder = item;
return folder;
}
}
if (folder === null) {
folder = proj.items.addFolder(folderName);
}
return folder;
}
/**
*
* @function traverseFolder
* @param {object} container - object with a number of items greater than 0
* @param {Function} callback
* @return {null}
*/
function traverseFolder(container, callback) {
for (var i = 1; i <= container.numItems; i++) {
var item = container.item(i);
var result = callback(item);
if (result) return result;
if (item instanceof FolderItem) {
var nested = traverseFolder(item, callback);
if (nested) return nested;
}
}
return null;
}
/**
*
* @function traverseProperties
* @param {CompItem} comp - object with a number of items greater than 0
* @param {Function} callback -
* @return {null}
*/
function traverseProperties(layer, callback) {
for (var b = 1; b <= layer.numProperties; b++) {
var prop = layer.property(b);
callback(prop);
if (prop.numProperties > 0) {
traverseProperties(prop, callback);
}
}
return null;
}
/**
*
* @function traverseComps
* @param {CompItem} comp - object with a number of items greater than 0
* @param {Function} callback
* @return {null}
*/
function traverseComps(comp, callback, visited) {
if (!visited) visited = {};
if (visited[comp.id]) return;
visited[comp.id] = true;
for (var i = 1; i <= comp.numLayers; i++) {
var layer = comp.layer(i);
callback(layer);
if (layer.source instanceof CompItem) {
traverseComps(layer.source, callback, visited);
}
}
return null;
}
/**
* finds comp by name via recursion
* @function findCompByName
* @param {string} name - a valid string used to search for a comp name
* @return {CompItem}
*/
function findCompByName(name) {
return traverseFolder(app.project, function (item) {
if (item instanceof CompItem && item.name === name) {
return item;
}
});
}
/**
* adds selected comps to the render queue and applies output module and token templates
* @function addCompsToRQ
* @param {CompItem} comps - an array of selected compositions in the project panel or the current active comp
* @param {String} module - a string representing the Output Module Template
* @param {String} tokenPath - a string representing the Output Destination Render Token
* @param {Boolean} imageFlag - a boolean that determines if the output is a still frame output or full sequence
* @returns nothing
*
*/
function addCompsToRQ(comps, module, tokenPath, imageFlag) {
var proj = app.project;
var renderQueue = proj.renderQueue;
while (renderQueue.numItems > 0) {
renderQueue.item(1).remove();
}
for (var i = 0; i < comps.length; i++) {
var comp = comps[i];
if (imageFlag) {
comp.workAreaStart = 0;
comp.workAreaDuration = comp.frameDuration * 1;
} else {
comp.workAreaStart = 0;
comp.workAreaDuration = comp.duration;
}
for (var b = 1; b <= proj.numItems; b++) {
var item = proj.item(b);
if (item.id === comp.id) {
var rqItem = renderQueue.items.add(comp);
var rqOM = rqItem.outputModule(1);
rqOM.applyTemplate(module);
var fileInfo = {
"Output File Info": {
"Full Flat Path": tokenPath,
},
};
rqOM.setSettings(fileInfo);
// rqOM.file = new File(tokenPath);
}
}
}
return;
}
return {
getProj: getProj,
getActiveComp: getActiveComp,
getSelectedComps: getSelectedComps,
hexToRGB: hexToRGB,
getSelectedLayers: getSelectedLayers,
getSelectedProperties: getSelectedProperties,
getOrCreateFolder: getOrCreateFolder,
addCompsToRQ: addCompsToRQ,
getSelectedKeyframes: getSelectedKeyframes,
traverseFolder: traverseFolder,
traverseProperties: traverseProperties,
traverseComps: traverseComps,
findCompByName: findCompByName,
};
})();
+75
View File
@@ -0,0 +1,75 @@
/**
* Kyle Harter's Script UI library
* @module km-scriptUI-functions
* @author Kyle Harter
* @returns {object} returns exported modules to be used in other jsx files
*/
var kmScriptUI = (function(){
var scriptName = "insert-script name";
/**
* shows help window for script
* @function showHelp
* @return {Object} a script UI window
*/
function showHelp(){
var settingsWindow = new Window("palette", "About " + scriptName, undefined, {closeButton: true, resizeable: true});
settingsWindow.orientation = 'column';
settingsWindow.alignChildren = ["fill", "fill"];
var editTextGroup = settingsWindow.add("group", undefined, "Middle Info Group");
editTextGroup.orientation = 'column';
editTextGroup.alignChildren = ["left", "top"];
var helpMessage =
'ABOUT '+scriptName.toUpperCase()+'\r\r\
INSERT INFO ABOUT SCRIPT HERE\r\r\
------------------------\
HOW TO USE '+scriptName.toUpperCase()+':\r\r\
STEP ##: STEP DETAIL\r\
INSERT STEP DETAIL HERE\r\r\
-----------\r\
'
var textBox = editTextGroup.add("edittext", undefined, helpMessage, {multiline: true, readonly: true ,scrollable: true});
textBox.justify = "left";
textBox.alignment = ["fill","fill"];
textBox.preferredSize = [600,200];
var creatorInfo =
''+scriptName+' v1.0\r\
Script created by Kyle Harter\r\
www.kylemotion.com'
var bottomGroup = settingsWindow.add("group", undefined, "bottomGroup");
bottomGroup.orientation = "row";
bottomGroup.alignChildren = ["fill", "center"];
var creatorGroup = bottomGroup.add("group", undefined, "Creator Info Group")
var creatorStatic = creatorGroup.add("statictext", undefined, creatorInfo, {multiline: true});
var closeGroup = bottomGroup.add("group", undefined, "Close Group");
closeGroup.alignChildren = ["right", "center"];
var closeButton = closeGroup.add("button", undefined, "Close");
closeButton.preferredSize = [-1, 30];
creatorStatic.addEventListener("mousedown", function () {
var userOS = OS
var launchCode = userOS.openUrl("https://www.kylemotion.com/")
});
closeButton.addEventListener("mousedown", function(){settingsWindow.close()})
settingsWindow.hide();
settingsWindow.show();
}
return {
showHelp: showHelp
}
})()
+70
View File
@@ -0,0 +1,70 @@
/**
* Kyle Harter systems function library
* @module km-system-functions
* @author kylenmotion@gmail.com
* @returns {object} returns exported modules to be used in other jsx files
*/
var kmSystemsLib = (function () {
/**
*
*
* @param {String} folderPath - valid file system string
* @return {Folder} returns folder object
*/
function getSystemFolder(folderPath) {
if (!folderPath) {
alert(
"Whoops!\rYou didn't enter a valid folder path string. Enter a valid folder path string and try again.",
);
return;
}
var folder = new Folder(folderPath);
if (!folder.exists) {
folder.create();
}
return folder;
}
/**
*
*
* @param {File} file - file system object
* @param {Array} contents - an array that holds an object of data to be logged
* @param {String} logTitle - valid string to be placed in the title of the log file
* @return {String} Contents of the log file
*/
function writeLogFile(file, contents, logTitle) {
var logTitle = "<----- " + logTitle + "----->";
var newDate = new Date();
var systemLogTime = newDate.toString();
var logFile = logTitle + "\r" + "Logged At: " + systemLogTime + "\r\r";
for (var i = 0; i < contents.length; i++) {
var currentObj = contents[i];
for (var key in currentObj) {
if (currentObj.hasOwnProperty(key)) {
logFile += key + ": " + currentObj[key] + "\r";
}
}
}
if (!file) {
file.open("w");
} else {
file.open("a");
}
file.write(logFile);
file.close();
return logFile;
}
return {
getSystemFolder: getSystemFolder,
writeLogFile: writeLogFile,
};
})();
+73
View File
@@ -0,0 +1,73 @@
/**
* A function library for adding text animators on top of text layers
*
* @author Kyle Harter
*
*/
var KMTextAnimatorsLib = (function(){
var matchNames = {
animator: "ADBE Text Animator",
props: {
anchorPoint: "ADBE Text Anchor Point 3D" ,
position: "ADBE Text Position 3D" ,
scale: "ADBE Text Scale 3D" ,
skew: "ADBE Text Skew" ,
skewAxis: "ADBE Text Skew Axis" ,
rotation: "ADBE Text Rotation",
opacity: "ADBE Text Opacity"
},
};
/**
* adds a text animator group to a text layer along with a range selector
*
* @param {TextLayer} textLayer
* @param {string} animator - matchNames.animatorName
* @return {Property} the added text animation property
*/
function addBasicAnimator(textLayer, animator){
var anim = textLayer.property("ADBE Text Properties")
.property("ADBE Text Animators")
.addProperty(animator);
var selector = anim.property("ADBE Text Selectors").addProperty("ADBE Text Selector");
return anim
}
/**
* adds a text animator property to a text animator group
*
* @param {object} anim - the text animator group established in "addBasicAnimator(textLayer,animator)"
* @param {string} prop - matchNames.propName
* @return {Property} added text animator property
*/
function addAnimProp(anim,prop){
var animPosGroup = anim.property("ADBE Text Animator Properties");
var textAnimProp = animPosGroup.addProperty(prop);
return textAnimProp
}
return {
matchNames: matchNames,
addBasicAnimator: addBasicAnimator,
addAnimProp: addAnimProp
};
}());
+316
View File
@@ -0,0 +1,316 @@
//@include "./OS.jsx"
var kmUtilityFunctions = (function (){
/**
* A function that will convert a file into a binary string. Useful fo displaying images in script UI
* @function getBinaryFile
* @return {File}
*/
function fileToBinaryString() {
var input = File.openDialog("choose a file to convert to source code");//new File("path/to/my/file")
if (input === null) return;
var rawData = readBinaryFile(input);
var variableName = stringToValidVariableName(input.name);
var sourceCode = convertRawDataToSourceCode(rawData, variableName);
writeTextFile(input.fsName + ".jsx", sourceCode);
function convertRawDataToSourceCode(rawData, variableName) {
var contentAsString = rawData.toSource();
var sourceCode = "var " + variableName + " = " + contentAsString + ";\n";
return sourceCode;
};
function readBinaryFile(file) {
file.encoding = "BINARY";
file.open("r");
var content = file.read();
file.close();
return content;
};
function writeTextFile(filePath, content) {
var output = new File(filePath);
output.open("w");
output.encoding = "UTF-8";
output.write(sourceCode);
output.close();
alert("Success!\rYou're jsx file is located here:\r\r" + output.fsName);
var binaryLocation = output.parent;
binaryLocation.execute();
};
function stringToValidVariableName(string) {
return string.replace(/\W/g, "") // remove anything that is not letter, digit or _
.replace(/^\d+/, ""); // remove any digits at the beginning
};
}
/**
* A function to load CSV data and bring in data from an array
*
* @param {object} options - Encoding object to determing encoding type. Acceptable keys are 'encoding' or 'separatorSymbol'. Ex:{encoding: "ascii", separatorSymbol: ;};
* @return {Array} - CSV Data from a chosen CSV file
*/
function loadCSVFromFile(options){
var file = File.openDialog("Select a .CSV file to parse data from")
function parseCSVString(csvString, options){
options = options || {};
var separatorSymbol = options.separatorSymbol || ",";
var currentRow = 0;
var currentColumn = -1; // will be increased to 0 during first loop iteration
var thisCell = "";
var i;
var token;
var cellStart = true;
var insideQuote;
function nextTokenLookAhead(){
var nextTokenId = i + 1;
return (nextTokenId <csvString.length ? csvString[nextTokenId]:"")
}
function processLineBreaks(){
addCsvCellToData(thisCell, currentRow, currentColumn);
cellStart = true;
currentRow++;
currentColumn = -1;
}
function processCellStart(){
thisCell = "";
currentColumn++;
insideQuote = (token == '"');
if(insideQuote){
i++;
token = csvString[i]
}
if(!insideQuote){
thisCell += token;
}
cellStart = false;
}
for (i=0; i< csvString.length; i++){
token = csvString[i];
if(cellStart){
processCellStart();
}
else if(!insideQuote && token == separatorSymbol){
addCsvCellToData(thisCell, currentRow, currentColumn);
cellStart = true;
}
else if(!insideQuote && token == "\n"){
processLineBreaks()
}
else if(!insideQuote && token == "\r" && nextTokenLookAhead() == "\n"){
i++;
processLineBreaks();
}
else if(insideQuote && token == '"'){
if(nextTokenLookAhead() == '"'){
i++;
thisCell += '"';
}
else {
insideQuote = false;
}
}
else {
thisCell += token;
}
}
return data
};
function addCsvCellToData(cellData, row, column){
if(data == undefined){
data = [];
}
if(data[row] == undefined){
data[row] = [];
}
data[row][column] = cellData
}
var data;
options = options || {}
file.encoding = options.encoding || "utf-8";
if(!(file.open("r"))){
throw new Error("Could not open file: " + file.error) ;
}
var rawData = file.read();
file.close();
if(file.error != "") throw new Error("Could not read file:" + file.error);
return parseCSVString(rawData, options);
};
/**
* reads and parses JSON file from supplied file path on disk
* @function readJSONFile()
* @param {string} filePath - file path to local JSON path
* @return {Array} Array of values from external JSON file
*/
function readJSONFile(filePath){
var file = new File(filePath);
if(!file.exists) return null;
file.open('r');
var content = file.read();
file.close();
try {
return JSON.parse(content);
} catch (err){
alert("JSON parse error: " + err);
return null;
}
}
/**
*
*
* @param {String} filePath - OS specific file path
* @param {Object} obj -
* @return {Boolean} true or false
*/
function writeJSON(filePath, obj){
var file = new File(filePath);
if(!file.parent.exists){
file.parent.create();
}
if(!file.open("w")){
alert("Could not open JSON file for writing");
return false
}
file.write(JSON.stringify(obj, null, 2));
file.close();
return true
}
/**
*
*
* @param {String} filePath - OS specific file path
* @param {String} key - unique name given to name of array in the main object
* @param {Array} value - collection of items to be added to JSON file
* @return {Object} JSON data from file
*/
function updateJSON(filePath, key, value){
var data = readJSON(filePath);
data[key] = value;
writeJSON(filePath, data);
return data;
}
/**
*
*
* @param {String} filePath - OS specific file path
* @param {Object} updates - key value pairs
* @return {Object} JSON data from file
*/
function updateJSONBatch(filePath, updates){
var data = readJSON(filePath);
for(var key in updates){
data[key] = updates[key];
}
writeJSON(filePath, data);
return data;
}
/**
* removes trailing characters from file names
*
* @function removeTrailingCharacters
* @param {String} fileName - file system name of a file
* @param {Extension} extension - a file extension you're wanting to find and replace trailing characters. DO NOT INCLUDE the period "." in the parameter
* @return {String} an amended file name without
*/
function removeTrailingCharacters(fileName, extension) {
return fileName.replace(/\.extenstion\d+$/i, "." + extension.toSring());
}
/**
* gets all AE script files with either a jsx or jsxbin file extension
* @function getScriptFiles
* @param {String} path - valid folder path location
* @return {Object} - a JSON object composed of script fs names
*/
function getScriptFiles(path){
var folder = Folder(path);
if(folder.exists){
var files = folder.getFiles();
}
var scriptFiles = [];
for(var i=0; i<files.length; i++){
var file = files[i];
if(file.name.indexOf("jsx") !== -1 || file.name.indexOf("jsxbin") !== -1){
scriptFiles.push(file.fsName)
}
}
return JSON.stringify(scriptFiles);
}
/**
* A function that will eval a script file given a valid FS string
*
* @function runScript
* @param {String} scriptPath - a valid file path derived from fsName
*/
function runScript(scriptPath){
var scriptFile = File(scriptPath);
$.evalFile(scriptFile);
}
return {
fileToBinaryString: fileToBinaryString,
loadCSVFromFile: loadCSVFromFile,
readJSONFile: readJSONFile,
writeJSON: writeJSON,
updateJSON: updateJSON,
removeTrailingCharacters: removeTrailingCharacters,
getScriptFiles: getScriptFiles,
runScript: runScript
};
}());
+14
View File
@@ -0,0 +1,14 @@
//@include "binaryFile.jsx"
//@include "filePath.jsx"
function getUiImage(fileName, toolName,rawData){
var filePath = getImagePath(fileName, toolName);
var file = getBinaryFile(filePath, rawData);
return file;
function getImagePath(fileName, toolName){
var filePath = joinPath([getUserDataFolderPath(), toolName, fileName]);
return filePath;
};
};
@@ -0,0 +1,71 @@
/**
* @description a headless script that will set the comp to the selected layer's current duration
* @name km-comp-duration-from-layer
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function () {
//@include "../library/km_helperFunctions.jsx";
//@include "../library/km_scriptUI_functions.jsx";
//@include "../library/km_utilityFunctions.jsx";
//@include "../library/km_textAnimators.jsx";
//@include "../library/km_systemFunctions.jsx";
try {
app.beginUndoGroup("Layer to comp dur");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var kmSystems = kmSystemsLib;
var activeComp = km.getActiveComp(app.project);
if(!activeComp) return;
var selLayers = km.getSelectedLayers(activeComp);
if(!selLayers) return;
setCompDurationFromLayer(activeComp,selLayers[0])
} catch (error) {
alert(
"An error occured on line: " +
error.line +
"\nError message: " +
error.message,
);
} finally {
// this always runs no matter what
app.endUndoGroup();
}
function setCompDurationFromLayer(comp,layer){
var layerStart = layer.startTime;
var layerIn = layer.inPoint;
var layerOut = layer.outPoint;
var layerShiftTime;
comp.duration = layerOut-layerIn;
for(var i = 1; i<=comp.numLayers; i++){
var compLayer = comp.layer(i);
$.writeln("Layer Start Time: " + layerIn)
if(layerIn > 0){
layerShiftTime = -layerIn;
$.writeln("Layer Shift Time: " + layerShiftTime)
} else {
layerShiftTime = layerIn;
}
compLayer.startTime += layerShiftTime
}
return comp
}
})();
+134
View File
@@ -0,0 +1,134 @@
/**
* @description a script wiyh a UI that will do something really cool in AE
* @name km-layer-labeler
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function(thisObj){
//@include "../library/km_helperFunctions.jsx";
//@include "../library/km_scriptUI_functions.jsx";
//@include "../library/km_utilityFunctions.jsx";
var scriptName = "km-layer-labeler";
createUI(thisObj)
function createUI(thisObj){
var kmUtils = kmUtilityFunctions;
var file = new File('/Users/Shared/km/km-layer-labels.json');
var config = kmUtils.readJSONFile(file);
var btnSize = [100,25]
var win = thisObj instanceof Panel
? thisObj
: new Window("window", scriptName, undefined, {
resizeable: true
});
win.orientation = 'column';
win.alignChildren = ["left", "top"];
var mainGroup = win.add("group", undefined, "Main Group");
mainGroup.orientation = 'column';
if(config && config.labels && config.labels.length > 0){
var buttonsPerRow = 4;
var labelGroup = mainGroup.add("group", undefined, "Labels Group");
labelGroup.orientation = "column";
labelGroup.alignChildren = ["left", "top"];
for(var i = 0; i<config.labels.length; i++){
if(i % buttonsPerRow === 0){
var rowGroup = labelGroup.add("group", undefined);
rowGroup.orientation = "row";
rowGroup.spacing = 5;
}
(function(labelObj){
var btn = rowGroup.add("button", undefined, labelObj.label);
btn.preferredSize = btnSize;
btn.onClick = function (){
app.beginUndoGroup("Label Comps");
var kmFunc = kmFunction;
var proj = kmFunc.getProj();
var activeComp = kmFunc.getActiveComp(proj);
var selectedLayers = kmFunc.getSelectedLayers(activeComp);
if(selectedLayers){
var allPrefixes = [];
for(var t = 0; t<config.labels.length; t++){
allPrefixes.push(config.labels[t].prefix + "-");
}
}
var shift = ScriptUI.environment.keyboardState.shiftKey;
var currentPrefix = '';
if(shift){
currentPrefix = labelObj.prefix + "-";
} else {
currentPrefix = labelObj.prefix;
}
for(var j=0; j<selectedLayers.length; j++){
var layer = selectedLayers[j];
var originalName = layer.name;
if(originalName.indexOf(currentPrefix) === 0){
continue
}
for(var n = 0; n<allPrefixes.length; n++){
if(originalName.indexOf(allPrefixes[n]) === 0){
originalName = originalName.substring(allPrefixes[n].length);
break;
}
}
layer.name = currentPrefix;
}
app.endUndoGroup();
}
})(config.labels[i])
}
}
var helpButton = mainGroup.add("button", undefined, "Help");
helpButton.alignment = ["fill", "top"];
helpButton.preferredSize = [-1,btnSize[1]];
helpButton.addEventListener('mousedown',function(){
kmScriptUI.showHelp()
})
win.onResizing = win.onResize = function (){
this.layout.resize();
};
if(win instanceof Window){
win.center();
win.show();
} else {
win.layout.layout(true);
win.layout.resize();
}
}
}(this))
@@ -0,0 +1,66 @@
/**
* @description a headless script to do something cool in AE
* @name km-scriptname
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function () {
//@include "../library/km_helperFunctions.jsx";
//@include "../library/km_scriptUI_functions.jsx";
//@include "../library/km_utilityFunctions.jsx";
//@include "../library/km_textAnimators.jsx";
//@include "../library/km_systemFunctions.jsx";
try {
app.beginUndoGroup("what does this script do?");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var kmSystems = kmSystemsLib;
var activeComp = km.getActiveComp(km.getProj());
var selLayers = km.getSelectedLayers(activeComp);
nullNamefromFirstChild(selLayers)
} catch (error) {
alert(
"An error occured on line: " +
error.line +
"\nError message: " +
error.message,
);
} finally {
// this always runs no matter what
app.endUndoGroup();
}
function nullNamefromFirstChild(layers) {
var found = false
for(var i = 0; i<layers.length; i++){
var layer = layers[i];
if(layer.parent !== null){
found = true;
var parentLayer = layer.parent;
parentLayer.name = layer.name + '-NULL'
}
}
if(!found){
alert("Whoops!\r\r You don't have any layers with parents selected. Select a layer with a parent and try again.")
return
}
return;
}
})();
+159
View File
@@ -0,0 +1,159 @@
/**
* @description a script wiyh a UI that will do something really cool in AE
* @name km-layer-props-copy-paste
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function(thisObj){
//@include "../library/km_helperFunctions.jsx";
//@include "../library/km_scriptUI_functions.jsx";
//@include "../library/km_utilityFunctions.jsx";
//@include "../library/km_textAnimators.jsx";
//@include "../library/km_systemFunctions.jsx";
var scriptName = "km-layer-props-copy-paste";
createUI(thisObj)
function createUI(thisObj){
var win = thisObj instanceof Panel
? thisObj
: new Window("window", scriptName, undefined, {
resizeable: true
})
win.orientation = 'column';
win.alignChildren = ["left", "top"];
var mainGroup = win.add("group", undefined, "Main Group");
mainGroup.orientation = 'column';
var copyPasteGroup = mainGroup.add("group", undefined, "Copy Paste Group");
copyPasteGroup.orientation = 'row';
var copyButton = copyPasteGroup.add("button", undefined, "Copy");
copyButton.preferredSize = [-1,30];
var pasteButton = copyPasteGroup.add("button", undefined, "Paste");
pasteButton.preferredSize = [-1,30];
var layerInfoGroup = mainGroup.add('group', undefined, 'Copy Info');
layerInfoGroup.alignChildren = ['left','top'];
var layerInfoText = layerInfoGroup.add('staticText', undefined, 'text');
layerInfoText.characters = 50;
var layerPropData = [{
label: null,
name: '',
comment: ''
}];
copyButton.onClick = function(){
try {
app.beginUndoGroup("What script does");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var activeComp = km.getActiveComp(km.getProj());
var selLayers = km.getSelectedLayers(activeComp);
copyProps(selLayers)
layerInfoText.text = layerPropData.length + ' layers copied from ' + activeComp.name;
} catch(error) {
alert("An error occured on line: " + error.line + "\nError message: " + error.message);
} finally {
// this always runs no matter what
app.endUndoGroup()
}
}
pasteButton.onClick = function(){
try {
app.beginUndoGroup("What script does");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var activeComp = km.getActiveComp(km.getProj());
var selLayers = km.getSelectedLayers(activeComp);
pasteProps(selLayers)
layerInfoText.text = layerPropData.length + ' layers pasted to ' + activeComp.name;
} catch(error) {
alert("An error occured on line: " + error.line + "\nError message: " + error.message);
} finally {
// this always runs no matter what
app.endUndoGroup()
}
}
function copyProps(selLayers){
layerPropData = [];
for(var i = 0; i<selLayers.length; i++){
var selLayer = selLayers[i];
layerPropData.push({
label: selLayer.label,
name: selLayer.name,
comment: selLayer.comment
})
}
return
}
function pasteProps(selLayers){
for(var i = 0; i<selLayers.length; i++){
var selLayer = selLayers[i];
selLayer.label = layerPropData[i].label
selLayer.name = layerPropData[i].name
selLayer.comment = layerPropData[i].comment
}
return
}
win.onResizing = win.onResize = function (){
this.layout.resize();
};
if(win instanceof Window){
win.center();
win.show();
} else {
win.layout.layout(true);
win.layout.resize();
}
}
}(this))
@@ -0,0 +1,66 @@
/**
* @description a headless script to do something cool in AE
* @name km-recurse-cti-comp-center
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function () {
//@include "../library/km_helperFunctions.jsx";
//@include "../library/km_scriptUI_functions.jsx";
//@include "../library/km_utilityFunctions.jsx";
//@include "../library/km_textAnimators.jsx";
//@include "../library/km_systemFunctions.jsx";
try {
app.beginUndoGroup("Moves each comp CTI to middle of comp timeline for easy viewing when viewing comp");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var kmSystems = kmSystemsLib;
var proj = km.getProj();
batchCTICompCenter(proj)
} catch (error) {
alert(
"An error occured on line: " +
error.line +
"\nError message: " +
error.message,
);
} finally {
// this always runs no matter what
app.endUndoGroup();
}
function batchCTICompCenter(proj) {
var compsArray = []
km.traverseFolder(proj, function (item){
if(item instanceof CompItem){
item.time = item.duration/2;
compsArray.push({
compItem: item,
compName: item.name
})
}
})
var msg = 'Analysis is complete!\r\r' + compsArray.length + ' comps\' CTIs were placed in the middle of their timelines.';
alert(msg)
return;
}
})();
@@ -0,0 +1,60 @@
/**
* @description a headless script to do something cool in AE
* @name km-trim-selected-comps-work_area
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function () {
//@include "../library/km_helperFunctions.jsx";
//@include "../library/km_scriptUI_functions.jsx";
//@include "../library/km_utilityFunctions.jsx";
//@include "../library/km_textAnimators.jsx";
//@include "../library/km_systemFunctions.jsx";
try {
app.beginUndoGroup("what does this script do?");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var kmSystems = kmSystemsLib;
var comps = km.getSelectedComps(km.getProj()).comps;
var trimmedComps = trimCompsWorkArea(comps);
alert('Comps Trimmed: ' + trimmedComps)
} catch (error) {
alert(
"An error occured on line: " +
error.line +
"\nError message: " +
error.message,
);
} finally {
// this always runs no matter what
app.endUndoGroup();
}
function trimCompsWorkArea(comps) {
var compsTrimmed = 0
for(var i = 0; i < comps.length; i++){
var comp = comps[i];
comp.openInViewer();
app.executeCommand(2360);
comp.time = comp.duration/2;
compsTrimmed++
}
return compsTrimmed
}
})();
+45
View File
@@ -0,0 +1,45 @@
/**
* @description a headless script to do something cool in AE
* @name km-scriptname
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function () {
//@include "./library/km_helperFunctions.jsx";
//@include "./library/km_scriptUI_functions.jsx";
//@include "./library/km_utilityFunctions.jsx";
//@include "./library/km_textAnimators.jsx";
//@include "./library/km_systemFunctions.jsx";
try {
app.beginUndoGroup("what does this script do?");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
var kmSystems = kmSystemsLib;
} catch (error) {
alert(
"An error occured on line: " +
error.line +
"\nError message: " +
error.message,
);
} finally {
// this always runs no matter what
app.endUndoGroup();
}
function runScript() {
alert("Script is run");
return;
}
})();
@@ -0,0 +1,94 @@
/**
* @description a script wiyh a UI that will do something really cool in AE
* @name km-scriptname
* @author Kyle Harter <kylenmotion@gmail.com>
* @version 1.0.0
*
* @license This script is provided "as is," without warranty of any kind, expressed or implied. In
* no event shall the author be held liable for any damages arising in any way from the use of this
* script.
*
*
*
*
*/
(function(thisObj){
//@include ".../library/km_helperFunctions.jsx;
//@include ".../library/km_scriptUI_functions.jsx";
//@include ".../library/km_utilityFunctions.jsx";
//@include ".../library/km_textAnimators.jsx";
//@include ".../library/km_systemFunctions.jsx";
var scriptName = "Script Name";
createUI(thisObj)
function createUI(thisObj){
var win = thisObj instanceof Panel
? thisObj
: new Window("window", scriptName, undefined, {
resizeable: true
})
win.orientation = 'column';
win.alignChildren = ["left", "top"];
var mainGroup = win.add("group", undefined, "Main Group");
mainGroup.orientation = 'column';
var applyGroup = mainGroup.add("group", undefined, "Apply Group");
applyGroup.orientation = 'row';
var applyButton = applyGroup.add("button", undefined, "Apply");
applyButton.preferredSize = [-1,30];
applyButton.helpTip = "Click: Apply markers to selected layers.\rShift+Click: Apply markers to beginning of a comp."
applyButton.onClick = function(){
try {
app.beginUndoGroup("What script does");
var km = kmFunction;
var kmScript = kmScriptUI;
var kmUtils = kmUtilityFunctions;
var kmTextAnims = KMTextAnimatorsLib;
runScript()
} catch(error) {
alert("An error occured on line: " + error.line + "\nError message: " + error.message);
} finally {
// this always runs no matter what
app.endUndoGroup()
}
}
function runScript(){
alert("Script is run")
return
}
win.onResizing = win.onResize = function (){
this.layout.resize();
};
if(win instanceof Window){
win.center();
win.show();
} else {
win.layout.layout(true);
win.layout.resize();
}
}
}(this))
+2731
View File
File diff suppressed because it is too large Load Diff
+91
View File
@@ -0,0 +1,91 @@
/// <reference path="JavaScript.d.ts" />
interface ExternalObjectConstructor {
readonly prototype: ExternalObject
/**
* Creates a new ExternalObject object.
*/
new (lib: string): ExternalObject
(lib: string): ExternalObject
}
declare const ExternalObject: ExternalObjectConstructor
interface ExternalObject {
/**
* Set to true to write status information to standard output (the
* JavaScript Console in the ExtendScript Toolkit). Set to false to turn
* logging off. Default is false.
*/
log: boolean
/**
* A set of alternate paths in which to search for the shared library files, a
* single string with multiple path specifications delimited by semicolons
* (;). Paths can be absolute or relative to the Folder.startup location.
*/
searchFolders: string
/**
* The version of the library, as returned by ESGetVersion()
*/
version: number
/**
* Reports whether a compiled C/C++ library can be found, but does not load it. If logging is on, the
* paths searched are reported to the JavaScript Console in the ExtendScript Toolkit.
* Returns true if the library is found, false otherwise.
* @param spec The file specification for the compiled library, with or without path information.
*/
search(spec: string): boolean
/**
* Explicitly shuts down the ExternalObject dynamic library wrapped by this instance.
* It can be helpful to force a shutdown of the external library if termination of external libraries during
* the shutdown of the hosting application does not occur in the correct order.
*/
terminate(): undefined
}
interface CSXSEventConstructor {
readonly prototype: CSXSEvent
/**
* Creates a new CSXSEvent object.
*/
new (type?: string, scope?: string, data?: string): CSXSEvent
(type?: string, scope?: string, data?: string): CSXSEvent
}
declare const CSXSEvent: CSXSEventConstructor
interface CSXSEvent {
/**
* Retrieves the unique identifier of the application from which this event was dispatched.
*/
readonly appId: string
/**
* Retrieves or sets the payload of this event.
*/
data: string
/**
* Retrieves the unique identifier of the extension from which this event was dispatched.
*/
readonly extensionId: string
/**
* Retrieves the scope of this event.
*/
scope: string
/**
* Retrieves the type of this event.
*/
type: string
/**
* Dispatch the event
*/
dispatch(): void
}
+3007
View File
File diff suppressed because it is too large Load Diff
+72
View File
@@ -0,0 +1,72 @@
/// <reference path="./PlugPlugExternalObject.d.ts" />
// A commonly used construct for loading XMPScript into
// ExtendScript contexts.
interface ExternalObjectConstructor {
AdobeXMPScript: ExternalObject | undefined
}
interface XMPMetaConstructor {
/** Creates an empty object. */
new (): XMPMetaInstance
/**
* @param packet A String containing an XML file or an XMP packet.
*/
new (packet: string): XMPMetaInstance
/**
* @param buffer The UTF-8 or UTF-16 encoded bytes of an XML file
* or an XMP packet. This array is the result of a call to `serializeToArray`
* on an `XMPMeta` instance.
*/
new (buffer: number[]): XMPMetaInstance
/**
* @param prefix The prefix of the namespace.
* @example XMPMeta.getNamespacePrefix('xmp'); // 'http://ns.adobe.com/xap/1.0/'
*/
getNamespaceURI(prefix: string): string
/**
* @param uri The URI of the namespace.
* @example XMPMeta.getNamespacePrefix('http://ns.adobe.com/xap/1.0/'); // 'xmp:'
*/
getNamespacePrefix(uri: string): string
}
type XMPProperty = {
locale: string
namespace: string
options: string
path: string
value: string
}
interface XMPMetaInstance {
doesPropertyExist(namespace: string, value: string): boolean
getProperty(namespace: string, property: string): XMPProperty
setProperty(namespace: string, property: string, value: string): boolean
countArrayItems(namespace: string, property: string): number
getArrayItem(namespace: string, property: string, itemIndex: number): XMPProperty
deleteProperty(namespace: string, property: string): boolean
appendArrayItem(
namespace: string,
property: string,
arrayOptions: string,
valueToAppend: string,
valueOptions: string,
): boolean
dumpObject(): string
serialize(): string
getNamespaceURI(ns: string): string
}
declare const XMPMeta: XMPMetaConstructor | undefined
interface XMPConstConstructor {
new (): XMPConstInstance
NS_DM: string
NS_DC: string
ARRAY_IS_ORDERED: string
}
interface XMPConstInstance {
// Instance stuff.
}
declare const XMPConst: XMPConstConstructor | undefined
+152
View File
@@ -0,0 +1,152 @@
/// <reference path="JavaScript.d.ts" />
/// <reference path="XMPScript.d.ts" />
/**
* The global BridgeTalk object.
*/
declare var BridgeTalk: any
/**
* The Infinity global property is a predefined variable with the value for infinity.
*/
declare var Infinity: number
/**
* The NaN global property is a predefined variable with the value NaN (Not-a-Number), as specified by the IEEE-754 standard.
*/
declare var NaN: number
/**
* The application object
*/
declare var app: Application
declare interface Application {}
/**
* Displays an alert box
* @param message The text to display
* @param title The title of the alert; ignored on the Macintosh
* @param errorIcon Display an Error icon; ignored on the Macintosh
*/
declare function alert(message: string, title?: string, errorIcon?: boolean): void
/**
* Displays an alert box with Yes and No buttons; returns true for Yes
* @param message The text to display
* @param noAsDefault Set to true to set the No button as the default button
* @param title The title of the alert; ignored on the Macintosh
*/
declare function confirm(message: string, noAsDefault?: boolean, title?: string): boolean
/**
* Decodes a string created with encodeURI().
* @param uri The text to decode.
*/
declare function decodeURI(uri: string): string
/**
* Decodes a string created with encodeURIComponent().
* @param uri The text to decode.
*/
declare function decodeURIComponent(uri: string): string
/**
* Encodes a string after RFC2396.
* Create an UTF-8 ASCII encoded version of this string. The string is converted into UTF-8. Every non-alphanumeric character is encoded as a percent escape
* character of the form %xx, where xx is the hex value of the character. After the conversion to UTF-8 encoding and escaping, it is guaranteed that the string does not contain characters codes greater than 127. The list of characters not to be encoded is -_.!~*'();/?:@&=+$,#. The method returns false on errors.
* @param text The text to encode.
*/
declare function encodeURI(text: string): string
/**
* Encodes a string after RFC2396.
* Create an UTF-8 ASCII encoded version of this string. The string is converted into UTF-8. Every non-alphanumeric character is encoded as a percent escape
* character of the form %xx, where xx is the hex value of the character. After the conversion to UTF-8 encoding and escaping, it is guaranteed that the string does not contain characters codes greater than 127. The list of characters not to be encoded is -_.!~*'(). The method returns false on errors.
* @param text The text to encode.
*/
declare function encodeURIComponent(text: string): string
/**
* Creates a URL-encoded string from aString.
* In the new string, characters of aString that require URL encoding are replaced with the format %xx, where xx is the hexadecimal value of the character code in the Unicode character set.This format is used to transmit information appended to a URL during, for example, execution of the GET method.Use the unescape() global function to translate the string back into its original format. Returns a string which is aString URL-encoded.
* @param aString The string to be encoded.
*/
declare function escape(aString: string): string
/**
* Evaluates its argument as a JavaScript script, and returns the result of evaluation.
* You can pass the result of an object's toSource() method to reconstruct that object.
* @param stringExpression The string to evaluate.
*/
declare function eval(stringExpression: string): any
/**
* Evaluates an expression and reports whether the result is a finite number.
* Returns true if the expression is a finite number, false otherwise. False if the value is infinity or negative infinity.
* @param expression Any valid JavaScript expression.
*/
declare function isFinite(expression: number): boolean
/**
* Evaluates an expression and reports whether the result is "Not-a-Number" (NaN).
* Returns true if the result of evaluation is not a number (NaN), false if the value is a number.
* @param expression Any valid JavaScript expression.
*/
declare function isNaN(expression: number): boolean
/**
* Returns true if the supplied string is a valid XML name.
* @param name The XML name to test.
*/
declare function isXMLName(name: string): boolean
/**
* Localizes a ZString-encoded string and merges additional arguments into the string.
* @param what The string to localize. A ZString-encoded string that can contain placeholder for additional arguments in the form %1 to %n.
* @param arguments Optional argument(s) to be merged into the string. There may be more than one argument.
*/
declare function localize(what: string, ...arguments: any[]): string
/**
* Extracts a floating-point number from a string.
* Parses a string to find the first set of characters that can be converted to a floating point number, and returns that number, or NaN if it does not encounter characters that it can converted to a number.The function supports exponential notation.
* @param text The string from which to extract a floating point number.
*/
declare function parseFloat(text: string): number
/**
* Extracts an integer from a string.
* Parses a string to find the first set of characters, in a specified base, that can be converted to an integer, and returns that integer, or NaN if it does not encounter characters that it can convert to a number.
* @param text The string from which to extract an integer.
* @param base The base of the string to parse (from base 2 to base 36). If not supplied, base is determined by the format of string.
*/
declare function parseInt(text: string, base?: number): number
/**
* Displays a dialog allowing the user to enter text
* Returns null if the user cancelled the dialog, the text otherwise
* @param prompt The text to display
* @param default_ The default text to preset the edit field with
* @param title The title of the dialog;
*/
declare function prompt(prompt: string, default_?: string, title?: string): string | null
/**
* Defines the default XML namespace.
* This is a replacement function for the standard JavaScript statement set default xml namespace.
* @param namespace The namespace to use. Omit this parameter to return to the empty namespace. This is either a Namespace object or a string.
*/
declare function setDefaultXMLNamespace(namespace: Namespace): void
/**
* Translates URL-encoded string into a regular string, and returns that string.
* Use the escape() global function to URL-encode strings.
* @param stringExpression The URL-encoded string to convert.
*/
declare function unescape(stringExpression: string): string
/**
* Creates a source code representation of the supplied argument, and returns it as a string.
* @param what The object to uneval.
*/
declare function uneval(what: any): string
+2933
View File
File diff suppressed because it is too large Load Diff