Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
converts after effects layers' keyframes to JSON and saves file on hard drive.
//JSON object
"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?i+"":"null";case"boolean":case"null":return i+"";case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;u>r;r+=1)f[r]=str(r,i)||"null";return o=0===f.length?"[]":gap?"[\n"+gap+f.join(",\n"+gap)+"\n"+a+"]":"["+f.join(",")+"]",gap=a,o}if(rep&&"object"==typeof rep)for(u=rep.length,r=0;u>r;r+=1)"string"==typeof rep[r]&&(n=rep[r],o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));else for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));return o=0===f.length?"{}":gap?"{\n"+gap+f.join(",\n"+gap)+"\n"+a+"}":"{"+f.join(",")+"}",gap=a,o}}var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,r){var n;if(gap="",indent="","number"==typeof r)for(n=0;r>n;n+=1)indent+=" ";else"string"==typeof r&&(indent=r);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(t,e){var r,n,o=t[e];if(o&&"object"==typeof o)for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(n=walk(o,r),void 0!==n?o[r]=n:delete o[r]);return reviver.call(t,e,o)}var j;if(text+="",rx_dangerous.lastIndex=0,rx_dangerous.test(text)&&(text=text.replace(rx_dangerous,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),rx_one.test(text.replace(rx_two,"@").replace(rx_three,"]").replace(rx_four,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}();
//log wrapper
function log( arg ){$.writeln( arg );}
//gets a URL based on the file path and the name
function getUrl( name ){
var projectName = app.project.file.name.replace(".aep", '');
var compName = app.project.activeItem.name;
var fileName = name || projectName + "_"+ compName + ".json";
fileName = fileName.replace(/\s/g, '');
var path = app.project.file.parent.absoluteURI + "/";
return path + fileName;
}
// you need to allow AE to write files to your hard drive:
// go to: Edit > Preferences > General > and check on "Allow Scripts to Write Files and Access Network"
//
//write the output to disk:
function saveFile( obj, fileName ){
var output = new File( getUrl( fileName + ".json" ) );
if( output.open( "w" ) ){
output.encoding = "UTF-8";
var content =JSON.stringify( out, undefined, 2 );
output.write( content );
output.close();
}
}
//recursive method to get all values from all layers
function scanLayers( obj, id, props ){
if( id > comp.layers.length )return;
//for each layer
var layer = comp.layer(id);
if( layer == null ) return;
//stores all layer's values in an object
var tmp = {};
tmp.times = [];
//for each property passed as an argument
for( var p =0; p< props.length; p++ ){
var property = layer[ props[ p ] ];
//gets the keyframe count
var numKeys = property.numKeys;
//default value if property is not animated
if( numKeys <= 0 ){
tmp[ props[ p ] ] = null;
continue;
}
//if the property is animated
var values = [];
if (numKeys > 0){
var time, value;
for( var i = 1; i <= numKeys; i++ ){
//gets the time and property values at this keyFrame
time = property.keyTime( i );
value = property.keyValue( i );
//stores them into an array which first value is the time stamp
var keyframe = [time];
if( !isNaN( value ) ){
// stores rotations in RADIANS
if( props[ p ] == "rotation" )
{
keyframe.push( value * Math.PI / 180 );
}
else
{
keyframe.push( value );
}
}
else
{
for( var j = 0; j < value.length; j++ ){
keyframe.push( value[ j ] );
}
}
//store this keyframe in the layer object
values.push( keyframe );
//if this timestamp was not yet present in the layer's list of timestamps
var addTime = true;
for( var j = 0; j < tmp.times.length; j++ ){
if( tmp.times[ j ] == time ) addTime = false;
}
//add it
if( addTime ) tmp.times.push( time );
}
}
//stores the property's values for this layer and got ot next property
tmp[ props[ p ] ] = values;
}
// add this layer to the final object
obj[ layer.name.replace(/\s/g, '_' ).toLowerCase() ] = tmp;
return scanLayers (obj, ++id, props);
}
////////////////////////////////////////////////
// SETUP WINDOW
////////////////////////////////////////////////
var win = new Window('dialog', 'Alert Box Builder');
win.options = win.add('panel', undefined, 'Build it');
var prs = [
"position",
"rotation",
"scale"
];
for( var i = 0; i < prs.length; i++ )
{
win[ prs[ i ] ] = win.options.add('checkbox', undefined, prs[ i ] );
win[ prs[ i ] ].value = true;
}
win.options.fileNameLabel = win.options.add('statictext', undefined, 'json file name:');
win.options.fileName = win.options.add('edittext', undefined, 'fileName' );
win.options.buildBtn = win.options.add('button', undefined, 'Build', {name:'ok'});
win.show();
//specify properties to export
var properties = [];
for( var i = 0; i < prs.length; i++ ){
log( prs[i] + " -> " + win[ prs[ i ] ].value );
if( win[ prs[ i ] ].value ) properties.push( prs[ i ] );
}
//specify file name or fall back to file name + .json
var fileName = win.options.fileName.text;
if( fileName == "fileName" ) fileName = app.project.file.name.replace(".aep", '');
////////////////////////////////////////////////
// GO !
////////////////////////////////////////////////
var proj = app.project;
var comp = proj.activeItem;
var out = {};
saveFile( scanLayers( out, 1, properties ), fileName );
{
"bla": {
"times": [
0,
38.0046713380047,
50.6172839506173,
37.7711044377711
],
"position": [
[
0,
430,
450,
0
],
[
38.0046713380047,
474,
96,
0
],
[
50.6172839506173,
394,
156,
0
]
],
"rotation": null,
"scale": [
[
0,
100,
100,
100
],
[
37.7711044377711,
100,
-14122.2222222222,
100
],
[
38.0046713380047,
100,
99.9999999999982,
100
]
]
},
"red_solid_1": {
"times": [
38.0046713380047,
43.1431431431431,
46.6466466466466
],
"position": null,
"rotation": null,
"scale": [
[
38.0046713380047,
100,
100,
100
],
[
43.1431431431431,
244,
244,
100
],
[
46.6466466466466,
100,
100,
100
]
]
},
"rect": {
"times": [
40.5739072405739,
54.5879212545879,
38.0046713380047,
50.6172839506173,
59.693026359693
],
"position": null,
"rotation": [
[
40.5739072405739,
1.81828270071446
],
[
54.5879212545879,
0
]
],
"scale": [
[
38.0046713380047,
8.203125,
7.8125,
100
],
[
40.5739072405739,
26.0121527777778,
27.3032407407407,
100
],
[
50.6172839506173,
76.453125,
72.8125,
100
],
[
59.693026359693,
8.203125,
7.8125,
100
]
]
}
}
Owner

nicoptere commented Mar 30, 2016

the times are set in an array per layer to store all the times when a property changes.
each property's array stores arrays of all changes, they starts with the timestamp followed by the property's values at this timestamp.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment