Skip to main content
Inspiring
October 26, 2015
Answered

Undo Group Mismatch

  • October 26, 2015
  • 1 reply
  • 2199 views

I am just learning AE Scripting, and this is my first script. It took a while, and I eventually got it to do what I wanted it to, but I am now having an issue with the Undo Group. When I run the script it gives me an 'Undo Group Mismatch' and fails to completely undo the actions in the script. I'm afraid I'm not knowledgeable enough to determine the source of the problem. I'd appreciate any help.

The script creates a solid, applies the Gradient Ramp, then Copies it with Property Links, Pastes it, then pre-comps the copy. Then on the master solid it adds a camera blur, sets the pre-comp to the blur layer, and hides the main gradient ramp effect. The idea being I can still control the ramp from the main timeline and it is mirrored in the pre comp. Here's the script:

  1. /* DOF script
  2. Make a solid called 'DOF_Master'
  3. Apply Gradient Ramp
  4. Copy With Properties
  5. Paste as 'DOF_Slave'
  6. Pre-Comp as 'DOF_Slave Comp'
  7. Move Slave to bottom of layer stack
  8. To Master: Apply Camera Blur
  9. Turn Gradient Ramp off
  10. Select slave Comp as Blur Layer
  11. Set as  Adjustment layer
  12. */
  13. app.beginUndoGroup("DOF with Precomped Gradient");
  14. function createDOF(){
  15. // variables
  16. var myComp = app.project.activeItem; 
  17. if(myComp == null){alert("Please, select your composition"); return false;}
  18. var slaveIndex
  19. var w = myComp.width ;
  20. var h = myComp.height ;
  21. // create solid at comp dimensions
  22. myComp.layers.addSolid([1.0,1.0,0], "DOF_Master", w, h, 1);
  23. // Apply Ramp and Camera Blur filters
  24. myComp.layer("DOF_Master").Effects.addProperty("ADBE Ramp");
  25. // Copy layer with Property Links
  26. app.executeCommand(10310);
  27. // Paste layer
  28. app.executeCommand(20);
  29. // Rename
  30. myComp.layer("DOF_Master 2").name = "DOF_Slave";
  31. //Pre Compose Slave, hide and move to bottom of layers
  32. slaveIndexA = myComp.layer("DOF_Slave").index
  33. myComp.layers.precompose([slaveIndexA],"DOF_Slave Comp","True");
  34. myComp.selectedLayers[0].enabled = false;
  35. myComp.selectedLayers[0].moveToEnd();
  36. slaveIndex = myComp.layer("DOF_Slave Comp").index
  37. //add Camera Blur, set effect properties to Master Layer and make adjustment layer
  38. myComp.layer("DOF_Master").effect("Gradient Ramp").enabled = false
  39. myComp.layer("DOF_Master").Effects.addProperty("ADBE Camera Lens Blur");
  40. myComp.layer("DOF_Master").effect("Camera Lens Blur").property("Layer").setValue(slaveIndex);
  41. myComp.layer("DOF_Master").effect("Camera Lens Blur").property("Invert Blur Map").setValue(true);
  42. myComp.layer("DOF_Master").adjustmentLayer = true
  43. myComp.layer("DOF_Master").selected = true
  44. myComp.layer("DOF_Slave Comp").selected = false
  45. }
  46. createDOF();
  47. app.endUndoGroup();
This topic has been closed for replies.
Correct answer David Torno

Glad to hear you are interested and trying to learn AE scripting. Welcome to the chaos of programming. Breaking down your script as you've done in steps is a great start. You've set your script up as if you were normally navigating the UI, and that's a good mindset to have in helping organize your script as you build it. Knowing the build steps is half the battle. Now the trickier part is stream lining the code. I see that you used the app.executeCommand method, while this can be handy at times, it can also be very dangerous as it may not always work as expected. Some menu commands have very specific demands when executing, like selections must be present first, or certain viewer panels should be active to run a command, etc... that's where things can be bad in a script. This is also what might be causing the mis-match issues with the undo group. So for your copy and paste lines (34 & 37), it would be better to create the slave layer just like you did the master layer. Since you want to control the slave gradient using the master gradient, you'll need expressions on the slave gradient for that to work, so creating your slave layer from scratch is better. Below is a modified version of your code. Feel free to ask any questions about what doesn't make sense or how something works if need be. I've placed a lot of comments hopefully to clarify all of it.

function createDOF(){

  var myComp = app.project.activeItem;

  if(myComp instanceof CompItem){//Check if myComp is a CompItem object

  var slaveIndex

  var w = myComp.width ;

  var h = myComp.height ;

     //Create DOF Master layer and change some attributes

  var dofMaster = myComp.layers.addSolid([1.0,1.0,0], "DOF_Master", w, h, 1);

  dofMaster.adjustmentLayer = true

     //Add Gradient Ramp effect and disable it

  dofMaster.Effects.addProperty("ADBE Ramp");

  dofMaster.effect("Gradient Ramp").enabled = false

     //Add Camera Lens Blur effect

  dofMaster.Effects.addProperty("ADBE Camera Lens Blur");

  dofMaster.effect("Camera Lens Blur").property("Invert Blur Map").setValue(true);

     //Setup the individual expressions needed to tie the slave to the master

  var startOfRampExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Start of Ramp\")";

  var startColorExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Start Color\")";

  var endOfRampExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"End of Ramp\")";

  var endColorExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"End Color\")";

  var rampShapeExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Ramp Shape\")";

  var rampScatterExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Ramp Scatter\")";

  var blendWithOriginalExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Blend With Original\")";

     //Create DOF Slave

  var dofSlave = myComp.layers.addSolid([1.0,1.0,0], "DOF_Slave", w, h, 1);

     //Add Gradient Ramp effect

  var gradientRampSlave = dofSlave.Effects.addProperty("ADBE Ramp");

     //Assign the Gradient Ramp expressions

  gradientRampSlave.property("Start of Ramp").expression = startOfRampExpression;

  gradientRampSlave.property("Start Color").expression = startColorExpression;

  gradientRampSlave.property("End of Ramp").expression = endOfRampExpression;

  gradientRampSlave.property("End Color").expression = endColorExpression;

  gradientRampSlave.property("Ramp Shape").expression = rampShapeExpression;

  gradientRampSlave.property("Ramp Scatter").expression = rampScatterExpression;

     //Get slave layer index

  slaveIndex = dofSlave.index

     //Precomp slave layer and move it to the bottom of the stack

  myComp.layers.precompose([slaveIndex],"DOF_Slave Comp","True");

  myComp.layer("DOF_Slave Comp").moveToEnd();

     //Now that the slave layer is created we can now assign it as the layer in the master Camera Lens Blur effect

  myComp.layer("DOF_Master").effect("Camera Lens Blur").property("Layer").setValue(slaveIndex);

     //Select the master

  myComp.layer("DOF_Master").selected = true

     //And deselect the slave layer

  myComp.layer("DOF_Slave Comp").selected = false

  }else{

       alert("Please, select your composition");

  return false;

  }

}

//Start undo group

app.beginUndoGroup("DOF with Precomped Gradient");

     //Run function

     createDOF();

//End undo group

app.endUndoGroup();

1 reply

David TornoCorrect answer
Legend
October 27, 2015

Glad to hear you are interested and trying to learn AE scripting. Welcome to the chaos of programming. Breaking down your script as you've done in steps is a great start. You've set your script up as if you were normally navigating the UI, and that's a good mindset to have in helping organize your script as you build it. Knowing the build steps is half the battle. Now the trickier part is stream lining the code. I see that you used the app.executeCommand method, while this can be handy at times, it can also be very dangerous as it may not always work as expected. Some menu commands have very specific demands when executing, like selections must be present first, or certain viewer panels should be active to run a command, etc... that's where things can be bad in a script. This is also what might be causing the mis-match issues with the undo group. So for your copy and paste lines (34 & 37), it would be better to create the slave layer just like you did the master layer. Since you want to control the slave gradient using the master gradient, you'll need expressions on the slave gradient for that to work, so creating your slave layer from scratch is better. Below is a modified version of your code. Feel free to ask any questions about what doesn't make sense or how something works if need be. I've placed a lot of comments hopefully to clarify all of it.

function createDOF(){

  var myComp = app.project.activeItem;

  if(myComp instanceof CompItem){//Check if myComp is a CompItem object

  var slaveIndex

  var w = myComp.width ;

  var h = myComp.height ;

     //Create DOF Master layer and change some attributes

  var dofMaster = myComp.layers.addSolid([1.0,1.0,0], "DOF_Master", w, h, 1);

  dofMaster.adjustmentLayer = true

     //Add Gradient Ramp effect and disable it

  dofMaster.Effects.addProperty("ADBE Ramp");

  dofMaster.effect("Gradient Ramp").enabled = false

     //Add Camera Lens Blur effect

  dofMaster.Effects.addProperty("ADBE Camera Lens Blur");

  dofMaster.effect("Camera Lens Blur").property("Invert Blur Map").setValue(true);

     //Setup the individual expressions needed to tie the slave to the master

  var startOfRampExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Start of Ramp\")";

  var startColorExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Start Color\")";

  var endOfRampExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"End of Ramp\")";

  var endColorExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"End Color\")";

  var rampShapeExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Ramp Shape\")";

  var rampScatterExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Ramp Scatter\")";

  var blendWithOriginalExpression = "comp(\"" + myComp.name + "\").layer(\"" + dofMaster.name + "\").effect(\"Gradient Ramp\")(\"Blend With Original\")";

     //Create DOF Slave

  var dofSlave = myComp.layers.addSolid([1.0,1.0,0], "DOF_Slave", w, h, 1);

     //Add Gradient Ramp effect

  var gradientRampSlave = dofSlave.Effects.addProperty("ADBE Ramp");

     //Assign the Gradient Ramp expressions

  gradientRampSlave.property("Start of Ramp").expression = startOfRampExpression;

  gradientRampSlave.property("Start Color").expression = startColorExpression;

  gradientRampSlave.property("End of Ramp").expression = endOfRampExpression;

  gradientRampSlave.property("End Color").expression = endColorExpression;

  gradientRampSlave.property("Ramp Shape").expression = rampShapeExpression;

  gradientRampSlave.property("Ramp Scatter").expression = rampScatterExpression;

     //Get slave layer index

  slaveIndex = dofSlave.index

     //Precomp slave layer and move it to the bottom of the stack

  myComp.layers.precompose([slaveIndex],"DOF_Slave Comp","True");

  myComp.layer("DOF_Slave Comp").moveToEnd();

     //Now that the slave layer is created we can now assign it as the layer in the master Camera Lens Blur effect

  myComp.layer("DOF_Master").effect("Camera Lens Blur").property("Layer").setValue(slaveIndex);

     //Select the master

  myComp.layer("DOF_Master").selected = true

     //And deselect the slave layer

  myComp.layer("DOF_Slave Comp").selected = false

  }else{

       alert("Please, select your composition");

  return false;

  }

}

//Start undo group

app.beginUndoGroup("DOF with Precomped Gradient");

     //Run function

     createDOF();

//End undo group

app.endUndoGroup();

Inspiring
October 27, 2015

That was brilliant. It was extremely informative to see how my novice attempts were translated into cleaner, more proper syntax. For someone like myself who isn't well versed in Javascript or AE scripting this REALLY helps. I was able to understand everything you graciously took the time to write out and annotate, and even fix a couple things that didn't link quite right.

I have a question for you though. I started with this script because it's somewhat simple and a thing I do frequently. But if I were to do a similar thing (create a precomp of a layer with effects properties copied from a main timeline controller) with a lot more complexity (say several effects, some third party like Particular, perhaps even multiple layers), what would the best general approach be? In your example you have written out all of the parameters of the Ramp effect and dynamically created custom expressions. I had used executeCommand in hopes that it would be a good template and I could modify the script to handle different, and more complex, situations. Is there another way to approach it?