//***********Replicate as Spine, version 2 // this script will take a selected solid and replicate it upward into an animatable spine; // each vertebra is parented to the one below it, and each vertebra above the lowermost (base) vertebra // has an expression that is linked to the base vertebra's x rotation. //***********// var cancelledOut = false; function askForNumber(thePrompt, theDefault) { gotANum = false; while (! gotANum) { p = prompt(thePrompt, theDefault); if (p == null) { cancelledOut = true; gotANum = true;//just to get us out of loop } else { if (! isNaN(p)) { gotANum = true; } } } //needs to NOT be a string, so we parseFloat: return parseFloat(p); } function mainSpine() { // make sure a comp is selected var activeItem = app.project.activeItem; if (activeItem == null || !(activeItem instanceof CompItem)){ alert("You need to select one layer first."); } else { // make sure just one layer is selected var selectedLayers = activeItem.selectedLayers; var selNum = activeItem.selectedLayers.length; if (!(selNum == 1)) { if (selNum == 0) {selNum = "No"} alert(selNum + " layers selected. You need to select just one layer first."); } else { // make sure it is not a light, camera; must be solid or footage item if (selectedLayers[0].adjustmentLayer == undefined) { alert("Selected layer not valid (must not be a camera or light)."); } else { vn = 0; while (vn < 2) { vn = askForNumber("Enter number of vertebrae:", "10"); } if (! cancelledOut) { vOlap = askForNumber("Enter overlap amount (in pixels. Zero means no overlap; negative number creates spacing):", "2"); if (! cancelledOut) { app.beginUndoGroup("spine creation"); vNa = "vertabra"; vShy = true; baseLayer = selectedLayers[0]; // (if not 3D layer, make it one) if (!baseLayer.threeDLayer) {baseLayer.threeDLayer = true} ; // rename to 'base vertebra' vZeroName = ("base " + vNa); baseLayer.name = vZeroName; lastLayer = baseLayer; lastLayerHtOffset = lastLayer.height; //change anchor point to bottom of layer ap = lastLayer.property("Anchor Point").value; lastLayer.property("Anchor Point").setValue( [ap[0], (lastLayerHtOffset), ap[2]] ); newLayer = baseLayer.duplicate(); newLayer.name = (vNa + "_" + "1"); for (i = 1; i < (vn); ++i) { /////LAYER ITEM ADJUSTMENTS///// if (i > 1) { newLayer = newLayer.duplicate(); newLayer.name = (vNa + "_" + i); //move new layer to above last layer newLayer.moveBefore(lastLayer); } /////PROPERTY ADJUSTMENTS///// //this is a little inefficient, but i want to use it for nonreplicating //version (which uses selected layer group, with layers possibly at different heights): p = lastLayer.property("Position").value; newLayer.property("Position").setValue([ p[0], (p[1] - lastLayerHtOffset + vOlap), p[2] ]); //add x rot expression to new layer newLayer.property("rotationX").expression = 'thisComp.layer("' + vZeroName + '").rotationX;'; lastLayer = newLayer; ///// now we have a reference to this layer to use at next iteration as last layer lastLayerHtOffset = lastLayer.height; } baseIndex = baseLayer.index; for (n = baseIndex; n > (baseIndex - (vn - 1)); --n) { childL = activeItem.layer(n - 1); parentL = activeItem.layer(n); childL.parent = parentL; if (vShy == true) {childL.shy = true} ; } app.endUndoGroup(); } } } } } } mainSpine();