Create sort of Metadata in AE project

All things .jsx

Moderator: Paul Tuersley

Post Reply
HTN3D
Posts: 11
Joined: February 28th, 2017, 4:02 pm
Location: Atlanta, GA
Contact:

March 6th, 2017, 10:25 am

I am woking on a script that creates different types of comps. And I am searching for a way to store some data for each comp somewhere in the project or in the comp itself. this data act sort of Metadata, So I can use it to recall the comps and read some comp's properties like color, size, number of layers...etc. and update them if I need to.
I was thinking of using a hidden null layer with keyframes in each comp and store these info/Metadata as keyframes by reading its values and convert it to data or maybe adding markers. But since I am fairly new in AE Scripting I would like to ask for any advice or suggestion of what the most efficient solution to store this kind of metadata.

Thanks in  advance
Haider Najeeb
Art Director and Motion Designer
www.htn3d.com
runegan
Posts: 22
Joined: November 4th, 2016, 3:18 pm
Contact:

March 6th, 2017, 12:02 pm

You are already able to read most of the comps metadata:

Code: Select all

comp.bgColor;
comp.width; comp.height;
comp.numLayers;
All of those, except numLayers, are read/write. So you can set to something else to change the comp.

Take a look at http://docs.aenhancers.com/compitem/, http://docs.aenhancers.com/avitem/, and http://docs.aenhancers.com/item/, for more info on available attributes to the comp object.

If you need to store additional additional, depending on the data and your script, you could maybe store it in the comp and use a textlayer, then populate the text property with the data.

Something like this could be used.

Code: Select all

function storeCompData( comp, data ) {
	var textlayer = comp.layers.byName( 'CompData' );

	if ( textlayer === null ) {
		textlayer = comp.layers.addText();
		textlayer.name = 'CompData';
	}

	textlayer
		.property( 'ADBE Text Properties' )
		.property( 'ADBE Text Document' )
		.setValue( data );
}

function getData( comp ) {
	var textlayer = comp.layers.byName( 'CompData' );

	textlayer
		.property( 'ADBE Text Properties' )
		.property( 'ADBE Text Document' )
		.value;
}


You can also use JSON2 to convert the data from and to object and string:

Code: Select all

//@include "JSON2.js"

var data = {
    example: 'somedata'
};

var dataAsString = JSON.stringify( data );

var parsedDataString = JSON.parse( dataAsString );

If you don't need to store the data in-between running the script, you could store the data in an object and use the items id as the key:

Code: Select all

var compData = {};
compData[ comp.id ] = {
   example: 'somedata'
};

compData[ comp.id ].example;
and if you need to have the data between multiple times of runnings of the script, but not between after effects sessions you can remove the 'var' keyword to make the variable into a global variable.

Code: Select all

// You need to check if the variable exists before setting its value
if ( typeof myGlobalCompData === 'undefined' ) {

    // Do not use the 'var' keyword to make the variable global
    myGlobalCompData = {}; 
}

Hope that gives you some ideas!
HTN3D
Posts: 11
Joined: February 28th, 2017, 4:02 pm
Location: Atlanta, GA
Contact:

March 6th, 2017, 2:20 pm

Thank you so much Runegan for your very rich and useful respond! I went through all the options and I learned something from each one. 

I would like to use the fifth method which is store the data in objects and use the item ID as the key but without using "Var" which is something I didn't know if you don't use it will create a global variable and keeps the data during AE session and it will not loose it in-between script-run. The only think I wish if there is an option to refresh the object-list automatically every time the user open a project. it's like if you close the project and open new one without quitting the app something will trigger the function that generates a new list. But thats not a big deal I can add a "refresh" button to refresh the list manually by the user and update the ScriptUI listbox.

Thank you so much again for your help.
Haider Najeeb
Art Director and Motion Designer
www.htn3d.com
runegan
Posts: 22
Joined: November 4th, 2016, 3:18 pm
Contact:

March 6th, 2017, 3:41 pm

Just to be clear: any variable you declare in your script that is not inside a function will become a global variable. You should look up javascript scope.

Most people would recomend wrapping your script in a function. So you do not declare or modify any global variables, which can have unforseen consequences.

Function myScript(thisObj) { // thisObj refers to the panel if run from the Window menu
// code
}; myScript(this);

I usually do this:

(Function(thisObj){})(this);

Which is a self executing function, but I have heard that does not always creates the scope correctly, so you may not want to use that in any script you are shipping.

You should be aware that global variables sre available to any script that a user runs, so you should name the variable something unique that nobody would accidenty overwrite.

E.g: "data" is a common variable name, and could be overwritten by someone else, while "HTNCompData" would probably not be overwritten by anyone.

I usally use my initials or the product name as a prefix to my global variables.
HTN3D
Posts: 11
Joined: February 28th, 2017, 4:02 pm
Location: Atlanta, GA
Contact:

March 7th, 2017, 9:16 am

it makes sense! using a global variable is not the safest way, specially if the user using other scripts (I wasn't aware of that!). But anyway I've been trying to encapsulate my variables in objects as much as possible to keep the argument list short when I call the main functions. But sometimes I end up pulling some variables out and make them global so they'll be easily seen by all functions... is that something I should stop doing, even with having relatively long argument list?
Haider Najeeb
Art Director and Motion Designer
www.htn3d.com
runegan
Posts: 22
Joined: November 4th, 2016, 3:18 pm
Contact:

March 7th, 2017, 9:45 am

Pulling the variables out to the outer scope is not a bad idea, as long as they are still inside your main function (i.e not polluting the global scope).

Putting the variables so they are accessible from all functions can be tricky if they are going to change between executions (e.g a layer variable that changes when the user clicks a button). You have to be sure the variable is set correctly and that it is the correct type, but it shouldn't be a problem for most cases.

Having one or multiple variables that are static available to all functions is a good idea, and works well.
HTN3D
Posts: 11
Joined: February 28th, 2017, 4:02 pm
Location: Atlanta, GA
Contact:

March 7th, 2017, 1:09 pm

Thank you so much Runegan for your help and advice. it's always useful for someone like me who hasn't done any serious coding since the college days (which is a decade ago) to learn coding strategies to build a complex script. And this is what I am trying to learn as i am building my fairly-complex AE script.

So I am grateful for your useful responses and I'm sure I'll have more questions as I am working on my script.
Haider Najeeb
Art Director and Motion Designer
www.htn3d.com
wysee
Posts: 7
Joined: November 21st, 2016, 9:24 am

March 8th, 2017, 5:12 pm

Hi,
Sometimes, I use the comment to store values that I need to retrieve, or to tag layers. It exists inside the project panel for any item. Or on layers in a comp.

app.project.item(index).comment  , it's a string so you could store stringified JSON I guess (never tried it);


Ben
HTN3D
Posts: 11
Joined: February 28th, 2017, 4:02 pm
Location: Atlanta, GA
Contact:

March 9th, 2017, 9:54 am

Thanks Ben! I am testing it and it's woking the way how I exactly need.
 this is how i am testing it:

Code: Select all

var x=app.project.activeItem;
x.comment="Writing Info";
alert ("reading the Info: " + x.comment);
Thank you so much Ben
Haider Najeeb
Art Director and Motion Designer
www.htn3d.com
Post Reply