Skip to main content
Participant
December 3, 2012
Answered

Need help with a Fade Transitions script

  • December 3, 2012
  • 1 reply
  • 1308 views

I am new to scripting so my apologies if I have made some obvious mistakes.

Also, not sure if there is already a feature in AE I don't know about that will accomplish

what I'm trying to do, but I would like to learn AdobeExtendScript and thought this was a great application for a script.

I am trying to write a script that will adjust video footage layers and keyframe opacity fades from 100% to 0% over a

length of frames determined by the user. Nothing too crazy. I tested this script with imported snippets from Premiere and

it works, kind of, but only when the first layer in the comp is part of the selected layers.

Here's the script:

//

// fadeTransitions.jsx (12/03/12)

// Copyright © 2012 Paul Kelly for Perioperative Interactive Education. All rights reserved.

// http:pkvisualization.com

// http://pie.med.utoronto.ca

//

// This script will adjust a series of layers so that the layer opacity fades

// from 100% to 0% over a length of frames determined by the user.

//

var theComp = app.project.activeItem; //set a variable equal to the active composition

if (theComp == null || (theComp instanceof CompItem) == false) // Check if item is selected and make sure it is a CompItem

{

    alert("You must have at least two layers selected");

} else {

        var numberOfLayers = theComp.selectedLayers.length; // set a variable equal to the total number of selected layers

        if (numberOfLayers == null || numberOfLayers < 2) // make sure there are at least two layers selected

        {

        alert("You must have at least two layers selected");

        } else {

        var startLayer = prompt("First layer to be affected: ", "Layer#");

        // want to eliminate this prompt and set a variable for the top-most selected layer.

        // var startLayer = theComp.selectedLayers[0]; isn't working. I want the lowest indexed layer of several selected layers

        fadeTransitions();

        } //end second else: numberOfLayers test

} //end first else: theComp test

function fadeTransitions()

{

app.beginUndoGroup("FadeTransitions");   

var overLap = parseInt(prompt("Specify length of fade-off (frames)", "0"));

overLap = overLap * theComp.frameDuration;

for (var i=1; i<=numberOfLayers; i++)

        {

        var layerIndex = (startLayer - 1) + i; //create layer index, subtract 1 to correct layer offset

            if (layerIndex > numberOfLayers) { //end before layerIndex becomes more than numberOfLayers

                alert("Fade Transitions script done");

                break;

                } else {

                    var topLayerEnd = theComp.layer(layerIndex).outPoint;

                    if ((layerIndex+1) > numberOfLayers) { //end before (layerIndex+1) becomes more than numberOfLayers

                        alert("Fade Transitions script done");

                        break;

                        } else {

                            var btmLayerStart = theComp.layer(layerIndex+1).inPoint;

                            var btmLayerEnd = theComp.layer(layerIndex+1).outPoint;

                            var duration = btmLayerEnd - btmLayerStart;

                            theComp.layer(layerIndex+1).inPoint = (topLayerEnd  - overLap);

                            theComp.layer(layerIndex+1).outPoint = (topLayerEnd + duration);

                             theComp.layer(layerIndex).opacity.setValueAtTime((theComp.layer(layerIndex).outPoint - overLap), 100);

                            theComp.layer(layerIndex).opacity.setValueAtTime(theComp.layer(layerIndex).outPoint, 0);

                } //end 2nd else

          } //end 1st else

    } //end for loop   

app.endUndoGroup();

} //end fadeTransitions function

Problem #1: I want to eliminate the prompt asking for the startLayer, instead I want the first layer to be the top-most of

a selection of layers, so that at any point you can select a series of layers and run the script to only affect those layers.

I tried to do that by setting a variable to app.project.activeItem.selectedLayers[0]; but it didn't work. This feature would really be

necessary during later stages of compositing, when there are many layers of captions, audio, 3D rendered images, etc. above

the footage layers in the comp.

Problem #2: Unless the selected layers are pre-arranged in a cascading fashion, I get some really weird adjustments to the in-

and outPoints. Not sure what's causing this. This isn't a top priority because most of the time I will be using this script the layers

will already be arranged correctly (I am importing a sequence from Premiere Pro), but I would still like to know how I could fix this

and better understand the way ExtendScript works.

Problem #3: Right now, the way the layer inPoints are adjusted, is the same as if I hovered the mouse over the layer inPoint and

got the horizontal line with opposite-facing arrows, and click-dragged the inPoint backward, but, what I would prefer is the

equivalent of if I hover the selection tool over the middle of the layer and click-dragged the entire layer L or R, so that the inPoint

is still the same location in the footage. Like problem #2, this isn't a super big deal, I just want to better understand what's happening

in the script. I tried using startTime instead of inPoint in the script, but then it just stopped working entirely.

Any help/insights would be greatly appreciated, and everyone feel free to use what I have so far if you like.

This topic has been closed for replies.
Correct answer Paul Tuersley

Give this a try. I haven't tested it extensively but I think it's pretty close to what you're after. It also isn't restricted to a contiguous layer selection.

//

// fadeTransitions.jsx (12/03/12)

// Copyright © 2012 Paul Kelly for Perioperative Interactive Education. All rights reserved.

// http:pkvisualization.com

// http://pie.med.utoronto.ca

//

// This script will adjust a series of layers so that the layer opacity fades

// from 100% to 0% over a length of frames determined by the user.

//

var indexArray = new Array();

var theComp = app.project.activeItem; //set a variable equal to the active composition

if (theComp == null || (theComp instanceof CompItem) == false) // Check if item is selected and make sure it is a CompItem

{

    alert("You must have at least two layers selected");

} else {

    var numberOfLayers = theComp.selectedLayers.length; // set a variable equal to the total number of selected layers

    if (numberOfLayers == null || numberOfLayers < 2) // make sure there are at least two layers selected

    {

        alert("You must have at least two layers selected");

    } else {

        // as "selectedLayers" is based on selection order, need a different approach to ensure  we're working from top to bottom

        // make an array of the layer indexes

        for (var x = 0; x < numberOfLayers; x++) {

            indexArray.push(theComp.selectedLayers.index);

        }

        // sort the indexArray

        indexArray.sort();

        var startLayer = indexArray[0];

        fadeTransitions();

    } //end second else: numberOfLayers test

} //end first else: theComp test

function fadeTransitions()

{

    var overLap = parseInt(prompt("Specify length of fade-off (frames)", "0"));

   

    if (overLap == null) return; // if user cancelled prompt

   

    overLap = parseInt(overLap);

   

    if (isNaN(overLap)) return;          // if user didn't enter number

       

    app.beginUndoGroup("FadeTransitions");  

    overLap = overLap * theComp.frameDuration;

    

    var layerIndex, topLayerEnd, btmLayerStart, btmLayerEnd, duration, startTimeOffset;

    for (var i=0; i<numberOfLayers; i++)

   

    {

       

        layerIndex = indexArray;

        topLayerEnd = theComp.layer(layerIndex).outPoint;

        if (i+1 < numberOfLayers) { //end before (layerIndex+1) becomes more than numberOfLayers

            btmLayerStart = theComp.layer(indexArray[i+1]).inPoint;

            btmLayerEnd = theComp.layer(indexArray[i+1]).outPoint;

            duration = btmLayerEnd - btmLayerStart;

           

            // need to calculate offset in case inPoint isn't at start of the layer

            startTimeOffset = btmLayerStart - theComp.layer(indexArray[i+1]).startTime;

            // move the layer by changing startTime rather than inPoint

            theComp.layer(indexArray[i+1]).startTime = (topLayerEnd-overLap - startTimeOffset);

            theComp.layer(indexArray[i+1]).outPoint = (topLayerEnd + duration);

            theComp.layer(layerIndex).opacity.setValueAtTime((theComp.layer(layerIndex).outPoint - overLap), 100);

            theComp.layer(layerIndex).opacity.setValueAtTime(theComp.layer(layerIndex).outPoint, 0);

        }

    } //end for loop  

 

    alert("Fade Transitions script done");

    app.endUndoGroup();

} //end fadeTransitions function

1 reply

Paul TuersleyCorrect answer
Inspiring
December 3, 2012

Give this a try. I haven't tested it extensively but I think it's pretty close to what you're after. It also isn't restricted to a contiguous layer selection.

//

// fadeTransitions.jsx (12/03/12)

// Copyright © 2012 Paul Kelly for Perioperative Interactive Education. All rights reserved.

// http:pkvisualization.com

// http://pie.med.utoronto.ca

//

// This script will adjust a series of layers so that the layer opacity fades

// from 100% to 0% over a length of frames determined by the user.

//

var indexArray = new Array();

var theComp = app.project.activeItem; //set a variable equal to the active composition

if (theComp == null || (theComp instanceof CompItem) == false) // Check if item is selected and make sure it is a CompItem

{

    alert("You must have at least two layers selected");

} else {

    var numberOfLayers = theComp.selectedLayers.length; // set a variable equal to the total number of selected layers

    if (numberOfLayers == null || numberOfLayers < 2) // make sure there are at least two layers selected

    {

        alert("You must have at least two layers selected");

    } else {

        // as "selectedLayers" is based on selection order, need a different approach to ensure  we're working from top to bottom

        // make an array of the layer indexes

        for (var x = 0; x < numberOfLayers; x++) {

            indexArray.push(theComp.selectedLayers.index);

        }

        // sort the indexArray

        indexArray.sort();

        var startLayer = indexArray[0];

        fadeTransitions();

    } //end second else: numberOfLayers test

} //end first else: theComp test

function fadeTransitions()

{

    var overLap = parseInt(prompt("Specify length of fade-off (frames)", "0"));

   

    if (overLap == null) return; // if user cancelled prompt

   

    overLap = parseInt(overLap);

   

    if (isNaN(overLap)) return;          // if user didn't enter number

       

    app.beginUndoGroup("FadeTransitions");  

    overLap = overLap * theComp.frameDuration;

    

    var layerIndex, topLayerEnd, btmLayerStart, btmLayerEnd, duration, startTimeOffset;

    for (var i=0; i<numberOfLayers; i++)

   

    {

       

        layerIndex = indexArray;

        topLayerEnd = theComp.layer(layerIndex).outPoint;

        if (i+1 < numberOfLayers) { //end before (layerIndex+1) becomes more than numberOfLayers

            btmLayerStart = theComp.layer(indexArray[i+1]).inPoint;

            btmLayerEnd = theComp.layer(indexArray[i+1]).outPoint;

            duration = btmLayerEnd - btmLayerStart;

           

            // need to calculate offset in case inPoint isn't at start of the layer

            startTimeOffset = btmLayerStart - theComp.layer(indexArray[i+1]).startTime;

            // move the layer by changing startTime rather than inPoint

            theComp.layer(indexArray[i+1]).startTime = (topLayerEnd-overLap - startTimeOffset);

            theComp.layer(indexArray[i+1]).outPoint = (topLayerEnd + duration);

            theComp.layer(layerIndex).opacity.setValueAtTime((theComp.layer(layerIndex).outPoint - overLap), 100);

            theComp.layer(layerIndex).opacity.setValueAtTime(theComp.layer(layerIndex).outPoint, 0);

        }

    } //end for loop  

 

    alert("Fade Transitions script done");

    app.endUndoGroup();

} //end fadeTransitions function

Inspiring
December 3, 2012

Oh and I forgot to mention, you should check out the built-in Animation > Keyframe Assistant > Sequence Layers function which does pretty much the same thing.

PizawLAuthor
Participant
December 4, 2012

D'oh! Haha, I figured there might be.

Thank you very much for your edits on the script, it works great. You definitely did some steps I would not have thought to do, so this is really helpful for my learning. The comments are a huge help too, thanks again.