[READ-ONLY] Mirror of https://github.com/probablykasper/2dcam. After Effects 2d camera
after-effects camera extendscript script
0

Configure Feed

Select the types of activity you want to include in your feed.

Further progress on everything

Kasper (Mar 8, 2020, 5:50 PM +0100) 45884d33 b0b96738

+134 -70
+134 -70
2dcam.jsx
··· 1 - var myPanel = (this instanceof Panel) ? this : new Window("palette", "2dCam", undefined, { resizeable: true }); 1 + var win = (this instanceof Panel) ? this : new Window("palette", "2dCam", undefined, { resizeable: true }); 2 2 3 - res = "group{orientation:'row',\ 4 - groupTwo: Panel{orientation:'row',\ 5 - deleteCompButton: Button{text:'+'},\ 6 - deleteText: StaticText{text:'Add 2dCam'},\ 7 - },\ 8 - }"; 3 + icons = { 4 + screen: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\b\x06\x00\x00\x00\u00C4\u00B4l;\x00\x00\x01\u0081iCCPsRGB IEC61966-2.1\x00\x00(\u0091u\u0091\u00CF+DQ\x14\u00C7?3C#\u0086Q,,,&\x06\x1B4FMl\u0094\u0091P\u0093\u00A61\u00CA`3\u00F3\u00E6\u0097\u009A\x1F\u00AF\u00F7F\u0092\u00AD\u00B2U\u0094\u00D8\u00F8\u00B5\u00E0/`\u00AB\u00AC\u0095\"R\u00B2\u00B2\u00B0&6\u00E89oF\u00CD$sn\u00E7\u009E\u00CF\u00FD\u00DE{N\u00F7\u009E\x0B\u00D6pF\u00C9\u00EA5\x1E\u00C8\u00E6\nZh\u00C2\u00EF\u009A\u008B\u00CC\u00BB\u00EC\u00CF\u00D8\u00A8\u00A3\u0089\x1E:\u00A3\u008A\u00AE\u008E\x06\u0083\x01\u00AA\u00DA\u00C7\x1D\x163\u00DE\u00F4\u0099\u00B5\u00AA\u009F\u00FB\u00D7\x1A\u00E2\t]\x01K\u009D\u00F0\u0088\u00A2j\x05\u00E1I\u00E1\u00C0JA5y[\u00B8UIG\u00E3\u00C2\u00A7\u00C2\u00BD\u009A\\P\u00F8\u00D6\u00D4c%~19U\u00E2/\u0093\u00B5ph\f\u00AC\u00CD\u00C2\u00AET\x05\u00C7*XIkYay9\u00EElfY\u00F9\u00BD\u008F\u00F9\x12G\"7;#\u00B1C\u00BC\x1D\u009D\x10\x13\u00F8q1\u00C58c\u00F8\x18`Xf\x1F}x\u00E9\u0097\x15U\u00F2=\u00C5\u00FCi\u00F2\u0092\u00AB\u00C8\u00AC\u00B2\u008A\u00C6\x12)\u00D2\x14\u00E8\x15uY\u00AA'$&EO\u00C8\u00C8\u00B0j\u00F6\u00FFo_\u00F5\u00E4\u00A0\u00B7T\u00DD\u00E1\u0087\u00DA'\u00C3x\u00EB\x02\u00FB\x16|o\x1A\u00C6\u00E7\u00A1a|\x1F\u0081\u00ED\x11.r\u00E5\u00FC\u00FC\x01\f\u00BD\u008B\u00BEY\u00D6\u00DC\u00FB\u00E0\\\u0087\u00B3\u00CB\u00B2\x16\u00DB\u0081\u00F3\rh{P\u00A3Z\u00B4(\u00D9\u00C4\u00AD\u00C9$\u00BC\u009E@c\x04Z\u00AE\u00A1~\u00A1\u00D4\u00B3\u00DF}\u008E\u00EF!\u00BC&_u\x05\u00BB{\u00D0-\u00E7\u009D\u008B?L\u00F1g\u00DA\u00922\u00E21\x00\x00\x00\tpHYs\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\u009A\u009C\x18\x00\x00\x00\u0087IDAT8\u008D\u00ED\u00D3\u00B1\r\u00830\x10F\u00E1wtT\u00AC\u0081\u0098\u0082.cd6\u00C6\u00A0\u00F3\x18\u00AC\u0080;*\u00CA\u009F\u00C6\u0091N\u0089\"\x05\u0083\x10\u0091\u00FC\u00DA\u0093?\u00D9\u0092\x0FJ\u00FF\u009F\u00A4NRT~QR\u00F7\u00F2\u00CC\u00C1\x03\u00F0\x00&@;\u00EFe@\x0B\u008Cf\u00F6\x04\u00A8\u00DC\u00B0\x01\u00D6\f\u0094tfM\x06\u00EF\u00F0\u00A9\x15\u00F8Zx\x01j\u00DC\x17\u00DC\u0091\u00A5\u00B3\u00CB\u00C7$-\u00C8|`Af\u00BF ?%\u00A9w@\u009F\u00F1\u00A2\u00AFppp8\r.\u00DD\u00B3\r\x1E\x0E\u00B6\u00BA\u0095\u0086\u00E1*\x00\x00\x00\x00IEND\u00AEB`\u0082", 5 + camera: "\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\b\x06\x00\x00\x00\u00C4\u00B4l;\x00\x00\x01\u0081iCCPsRGB IEC61966-2.1\x00\x00(\u0091u\u0091\u00CF+DQ\x14\u00C7?3C#\u0086Q,,,&\x06\x1B4FMl\u0094\u0091P\u0093\u00A61\u00CA`3\u00F3\u00E6\u0097\u009A\x1F\u00AF\u00F7F\u0092\u00AD\u00B2U\u0094\u00D8\u00F8\u00B5\u00E0/`\u00AB\u00AC\u0095\"R\u00B2\u00B2\u00B0&6\u00E89oF\u00CD$sn\u00E7\u009E\u00CF\u00FD\u00DE{N\u00F7\u009E\x0B\u00D6pF\u00C9\u00EA5\x1E\u00C8\u00E6\nZh\u00C2\u00EF\u009A\u008B\u00CC\u00BB\u00EC\u00CF\u00D8\u00A8\u00A3\u0089\x1E:\u00A3\u008A\u00AE\u008E\x06\u0083\x01\u00AA\u00DA\u00C7\x1D\x163\u00DE\u00F4\u0099\u00B5\u00AA\u009F\u00FB\u00D7\x1A\u00E2\t]\x01K\u009D\u00F0\u0088\u00A2j\x05\u00E1I\u00E1\u00C0JA5y[\u00B8UIG\u00E3\u00C2\u00A7\u00C2\u00BD\u009A\\P\u00F8\u00D6\u00D4c%~19U\u00E2/\u0093\u00B5ph\f\u00AC\u00CD\u00C2\u00AET\x05\u00C7*XIkYay9\u00EElfY\u00F9\u00BD\u008F\u00F9\x12G\"7;#\u00B1C\u00BC\x1D\u009D\x10\x13\u00F8q1\u00C58c\u00F8\x18`Xf\x1F}x\u00E9\u0097\x15U\u00F2=\u00C5\u00FCi\u00F2\u0092\u00AB\u00C8\u00AC\u00B2\u008A\u00C6\x12)\u00D2\x14\u00E8\x15uY\u00AA'$&EO\u00C8\u00C8\u00B0j\u00F6\u00FFo_\u00F5\u00E4\u00A0\u00B7T\u00DD\u00E1\u0087\u00DA'\u00C3x\u00EB\x02\u00FB\x16|o\x1A\u00C6\u00E7\u00A1a|\x1F\u0081\u00ED\x11.r\u00E5\u00FC\u00FC\x01\f\u00BD\u008B\u00BEY\u00D6\u00DC\u00FB\u00E0\\\u0087\u00B3\u00CB\u00B2\x16\u00DB\u0081\u00F3\rh{P\u00A3Z\u00B4(\u00D9\u00C4\u00AD\u00C9$\u00BC\u009E@c\x04Z\u00AE\u00A1~\u00A1\u00D4\u00B3\u00DF}\u008E\u00EF!\u00BC&_u\x05\u00BB{\u00D0-\u00E7\u009D\u008B?L\u00F1g\u00DA\u00922\u00E21\x00\x00\x00\tpHYs\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\u009A\u009C\x18\x00\x00\x00~IDAT8\u008D\u00ED\u00D3\u00BB\r\u00C20\x14@\u00D1g\u00EA0\r\fB\u0096\u0080\u009D2\x13\u008C\u0090,\x01\u00FDI\u0081@\u0096\"\x119q\x01\"\u00B7\u00B5t,\x7F^\u00C4\u00D6o\u0087\x16\u0083\u00B2\x06\u00B4sp)\u00FA\u00C6\u00E7\u00E0\u00C5e\u00C6\x1E\x17\u00DC\u00AA\u00C08\u00A0\u00C3=\u00DF,\u00BD\u00E0\x15O4)\u00A5\u0094v5\u00C1\u00BC\u00FF\u0084\u008F\x11\u00D1E\u00C4c\u00B2\u00B2\u00E6KdF\u00833\u00AE9\u00BCt@\u00FA\u008Fg\u00F1\x1C\u00E9\u00BE\x14\u00C5\u00A9\u00C2Un}[#\x1Fx\u00CB\u008F*\u00DD\u00AF\u00C9\x00\x00\x00\x00IEND\u00AEB`\u0082", 6 + } 9 7 10 - myPanel.grp = myPanel.add(res); 8 + res = 'group{orientation:"row",\ 9 + newCamButton: IconButton{properties:{style:"toolbutton"}}, helpTip:"New 2dCam",\ 10 + newOutputButton: IconButton{properties:{style:"toolbutton"}}, helpTip:"Create 2dCam output composition. Alt+click to enable 2dCam Output selected composition layer"},\ 11 + }'; 11 12 12 - // Defaults 13 - myPanel.grp.groupTwo.deleteCompButton.size = [25, 25]; 13 + win.grp = win.add(res); 14 + win.grp.newCamButton.image = ScriptUI.newImage(cameraIcon); 15 + // win.grp.newCamButton.image = ScriptUI.newImage('./icons/camera.png'); 16 + win.grp.newCamButton.size = [25, 25]; 17 + win.grp.newOutputButton.image = ScriptUI.newImage(screenIcon); 18 + // win.grp.newOutputButton.image = ScriptUI.newImage('./icons/screen.png'); 19 + win.grp.newOutputButton.size = [25, 25]; 20 + 21 + var createOutputComp = true; 22 + function newCamDialog(currentComp, cancel, ok) { 23 + var dialog = new Window("dialog", "New 2dCam", undefined, { resizeable: false }); 14 24 15 - // Add 2dCam 16 - myPanel.grp.groupTwo.deleteCompButton.onClick = function () { 25 + var width = currentComp.width; 26 + var height = currentComp.height; 27 + res = 'group{orientation:"column",\ 28 + panelGroup: Panel{orientation:"column", alignChildren:"left",\ 29 + nameGroup: Group{orientation:"row",\ 30 + nameText: StaticText{text:"Name:", justify:"right", preferredSize: [40, 20]},\ 31 + name: EditText{text:"A", characters:15},\ 32 + },\ 33 + widthGroup: Group{orientation:"row",\ 34 + widthText: StaticText{text:"Width:", justify:"right", preferredSize: [40, 20]},\ 35 + width: EditText{text:"'+width+'", characters:6},\ 36 + },\ 37 + heightGroup: Group{orientation:"row",\ 38 + heightText: StaticText{text:"Height:", justify:"right", preferredSize: [40, 20]},\ 39 + height: EditText{text:"'+height+'", characters:6},\ 40 + },\ 41 + createOutputCompGroup: Group{orientation:"row",\ 42 + createOutputComp: Checkbox{value:'+createOutputComp+'},\ 43 + createOutputCompText: StaticText{text:"Height:"},\ 44 + },\ 45 + },\ 46 + buttonsGroup: Group{orientation:"row",\ 47 + cancelButton: Button{text:"Cancel"},\ 48 + okButton: Button{text:"OK"},\ 49 + },\ 50 + }'; 51 + 52 + dialog.grp = dialog.add(res); 53 + 54 + dialog.grp.buttonsGroup.cancelButton.onClick = function() { 55 + dialog.close(); 56 + cancel(); 57 + } 58 + dialog.grp.buttonsGroup.okButton.onClick = function() { 59 + var options = { 60 + name: dialog.grp.panelGroup.nameGroup.name.text, 61 + width: dialog.grp.panelGroup.widthGroup.width.text, 62 + height: dialog.grp.panelGroup.heightGroup.height.text, 63 + }; 64 + dialog.close(); 65 + ok(options); 66 + } 67 + 68 + dialog.layout.layout(true); 69 + dialog.center(); 70 + dialog.show(); 71 + } 72 + 73 + // New 2dCam 74 + win.grp.newCamButton.onClick = function() { 17 75 if (app.project.activeItem == undefined || app.project.activeItem == null) { 18 - alert("Please select a comp to delete"); 19 - return false; 76 + alert('Please select a composition'); 20 77 } else { 21 - // delete comp 78 + currentComp = app.project.activeItem; 79 + 80 + // ask for name, width, height then apply preset. 81 + newCamDialog(currentComp, function() { 82 + 83 + }, function(options) { 84 + var camWidth = options.width; 85 + var camHeight = options.height; 86 + var strokeWidth = Math.ceil(Math.min(camWidth/40, camHeight/40)); 87 + 88 + app.beginUndoGroup('New 2dCam'); 89 + 90 + var shapeLayer = app.project.activeItem.layers.addShape(); 91 + shapeLayer.name = '2dCam'; 92 + shapeLayer.guideLayer = true; 93 + shapeLayer.blendingMode = BlendingMode.DIFFERENCE; 94 + 95 + var shapeContents = shapeLayer.property('ADBE Root Vectors Group'); 96 + 97 + var rectangle = shapeContents.addProperty('ADBE Vector Shape - Rect'); 98 + rectangle.name = 'Rectangle'; 99 + rectangle.property('ADBE Vector Rect Size').setValue([camWidth, camHeight]); 100 + 101 + var stroke = shapeContents.addProperty('ADBE Vector Graphic - Stroke'); 102 + stroke.name = 'Stroke'; 103 + stroke.property('ADBE Vector Stroke Color').setValue([255,255,255]); 104 + stroke.property('ADBE Vector Stroke Width').setValue(strokeWidth); 105 + 106 + var mask = shapeLayer.Masks.addProperty('Mask'); 107 + mask.name = 'Mask'; 108 + mask.locked = true; 109 + mask.property('maskShape').expression = 110 + 'w = content("Rectangle").size[0]/2;'+ 111 + 'h = content("Rectangle").size[1]/2;'+ 112 + 'createPath(points = [[-w,-h], [w,-h], [w,h], [-w,h]])'; 113 + 114 + app.endUndoGroup(); 115 + }); 116 + } 117 + } 118 + 119 + // New 2dCam output 120 + win.grp.newOutputButton.onClick = function() { 121 + if (app.project.activeItem == undefined || app.project.activeItem == null) { 122 + alert('Please select a composition'); 123 + } else { 22 124 currentComp = app.project.activeItem; 23 125 24 126 // ask for name, width, height then apply preset. 25 127 var camWidth = 1920; 26 128 var camHeight = 1080; 27 - var strokeWidth = 20; // 50 * width or height, whichever is lowest 129 + var strokeWidth = Math.ceil(Math.min(camWidth/40, camHeight/40)); 28 130 29 - // app.project.activeItem.remove(); 30 131 var shapeLayer = app.project.activeItem.layers.addShape(); 31 132 shapeLayer.name = '2dCam'; 32 133 shapeLayer.guideLayer = true; 134 + shapeLayer.blendingMode = BlendingMode.DIFFERENCE; 33 135 34 - var contents = shapeLayer.property('ADBE Root Vectors Group'); 136 + var shapeContents = shapeLayer.property('ADBE Root Vectors Group'); 35 137 36 - // rectangle 37 - var rectangle = contents.addProperty("ADBE Vector Shape - Rect"); 138 + var rectangle = shapeContents.addProperty('ADBE Vector Shape - Rect'); 38 139 rectangle.name = 'Rectangle'; 39 140 rectangle.property('ADBE Vector Rect Size').setValue([camWidth, camHeight]); 40 - rectangle.property('ADBE Vector Rect Size'); 41 141 42 - // stroke 43 - var stroke = contents.addProperty('ADBE Vector Graphic - Stroke'); 142 + var stroke = shapeContents.addProperty('ADBE Vector Graphic - Stroke'); 44 143 stroke.name = 'Stroke'; 144 + stroke.property('ADBE Vector Stroke Color').setValue([255,255,255]); 45 145 stroke.property('ADBE Vector Stroke Width').setValue(strokeWidth); 46 146 47 - // offset stroke 48 - var offsetPaths = contents.addProperty('ADBE Vector Filter - Offset'); 49 - offsetPaths.name = 'Offset Paths'; 50 - offsetPaths.property('ADBE Vector Offset Amount').expression = '-content("Stroke").strokeWidth/2'; 51 - 52 - // invert effect 53 - var effects = shapeLayer.property('ADBE Effect Parade'); 54 - effects.addProperty('ADBE Invert'); 55 - 56 - // set to adjustment layer, for invert effect 57 - shapeLayer.adjustmentLayer = true; 147 + var mask = shapeLayer.Masks.addProperty('Mask'); 148 + mask.name = 'Mask'; 149 + mask.locked = true; 150 + mask.property('maskShape').expression = 151 + 'w = content("Rectangle").size[0]/2;'+ 152 + 'h = content("Rectangle").size[1]/2;'+ 153 + 'createPath(points = [[-w,-h], [w,-h], [w,h], [-w,h]])'; 58 154 } 59 155 } 60 156 61 - myPanel.layout.layout(true); 157 + win.layout.layout(true); 62 158 63 - if (myPanel != null && myPanel instanceof Window) { 64 - myPanel.center(); 65 - myPanel.show(); 159 + if (win != null && win instanceof Window) { 160 + win.center(); 161 + win.show(); 66 162 } 67 - 68 - // log all match names of selected layer (for example "ADBE Vector Stroke Width"): 69 - 70 - // (function () { // wrap entire script in an anonymous function to create a private scope within AE's global namespace 71 - // main(); 72 - // function dumpPropTree(rootObj, nestingLevel) { 73 - // var countProps = rootObj.numProperties; 74 - // for (var propIndex = 1; propIndex <= countProps; propIndex++) { 75 - // var prop = rootObj.property(propIndex); 76 - // $.writeln(Array(nestingLevel * 4).join(" ") + "[" + nestingLevel + "-" + propIndex + "] " + "matchName: \"" + prop.matchName + "\", name: \"" + prop.name + "\""); 77 - // if (prop.numProperties > 0) 78 - // dumpPropTree(prop, nestingLevel + 1); 79 - // } 80 - // } 81 - // function main() { 82 - // var activeComp = app.project.activeItem; 83 - // if (activeComp == null) { 84 - // alert("Error: No active composition"); 85 - // return; 86 - // } 87 - // var countSelectedLayers = activeComp.selectedLayers.length; 88 - // if (countSelectedLayers == 0) { 89 - // alert("Error: No selected layer(s)"); 90 - // return; 91 - // } 92 - // for (selectedLayerIndex = 0; selectedLayerIndex < countSelectedLayers; selectedLayerIndex++) { 93 - // var layer = activeComp.selectedLayers[selectedLayerIndex]; 94 - // $.writeln("***************** [ Layer: \"" + layer.name + "\" ] *****************"); 95 - // dumpPropTree(layer, 0); 96 - // } 97 - // } 98 - // })(); // end of anonymous function that encapsulates entire script