Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@fartinmartin
Last active September 29, 2022 11:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fartinmartin/f6fe63328817a6eff17a07e60b2a6eb1 to your computer and use it in GitHub Desktop.
Save fartinmartin/f6fe63328817a6eff17a07e60b2a6eb1 to your computer and use it in GitHub Desktop.
After Effects Snippets
# from the directory containing the source files
for x in *.webp; do ffmpeg -i "$x" "${x%.*}.jpg"; done
# ^input file extention ^output file extension
# text file with links on new line
youtube-dl -a links.txt
# if video's are overwriten/skipped, use the id etc to allow all to download:
youtube-dl -a links.txt -o '%(id)s_%(title)s_%(url)s_%(autonumber)s'
// blend between two expressions using a slider
blend = thisComp.layer("Control").effect("Blend")("Slider");
// two states, a & b, can be changed
a = transform.position;
b = thisComp.layer("Target").toWorld([0,0,0]);
linear(blend, 0, 100, a, b)
// on scale property
l = thisLayer; // whatever is scaling (could be parent, or shape group, or thisLayer, etc)
value * (100 / l.transform.scale[0]);
// requires slider called "Text Reveal" and checkbox called "Toggle"
textReveal = effect("Slider Control")("Text Reveal");
toggle = effect("Checkbox Control")("Toggle");
blink = Math.round(time % 1);
pipe = " ";
if (((blink == 1) || (textReveal.speed > 0)) && (toggle == true)) {
pipe = "|"
}
substr(0, textReveal) + pipe;
// apply to an elipse's dashes property
dashes = effect("Slider Control")("Slider");
radius = content("Ellipse").content("Ellipse Path").size[0] / 2;
gap = content("Ellipse").content("Stroke").dash.gap;
segments = dashes <= 0 ? 1 : dashes;
2 * Math.PI * radius / segments - gap;
// apply to the stroke's offset property
content("Ellipse").content("Stroke").dash.dash / 2;
w = content("Rectangle").content("Rectangle Path").size[0];
h = content("Rectangle").content("Rectangle Path").size[1];
l = (w * 2) + (h * 2);
l / 60; // adjust as necessary
// adjust offset manually!
// create null layer at same position (etc) of object (shift parent)
// unparent the null, and parent the object to the null
// for use in null layer name: ၑ // https://unicode-table.com/en/#1051 || https://unicode-table.com/en/#buginese
// TODO: okay, but what happens after you un-enable? it moves back to neurtral/starting values 🤔
// on position (for example) of null:
self = OBJECT_LAYER; // set layer here
enabled = self.effect("Parent — Enabled")("Checkbox") == true;
parent = self.effect("Parent — Layer")("Layer");
if (!enabled) {
value + self.transform.position;
}
else {
// TODO: check if parent hasParent, if so: parent.parent.rotation instead of parent.rotation (eg)
parent.toComp(parent.anchorPoint);
}
// apply to opacity property
// requires two sliders to init the start and end point of fade (in z position)
startFade = effect("Start Fade")("Slider"); // 500
endFade = effect("End Fade")("Slider"); // 3000
try {
// check if there is a camera
camera = thisComp.activeCamera.toWorld([0,0,0]);
} catch(err) {
// if no camera, assume 50mm
compWidth = thisComp.width * thisComp.pixelAspect;
zPosition = (compWidth / 2)/Math.tan(degreesToRadians(19.799));
camera = [0,0,-zPosition];
}
position = toWorld(anchorPoint);
distance = length(camera, position);
linear(distance, startFade, endFade, 100, 0);
fade = 1; // fade duration in seconds
fadeIn = (time - inPoint) / fade;
fadeOut = (outPoint - time) / fade;
if (time < inPoint + fade) {
ease(fadeIn, 0, 1) * value;
} else if (time > outPoint - fade) {
ease(fadeOut, 0, 1) * value;
} else {
value;
}
// JavaScript For Loop Example - Created by Animoplex: www.animoplex.com
// The JavaScript For Loop and how it can be used in After Effects.
// Full Tutorial: https://www.youtube.com/watch?v=SG3NyHmfc0s&t=91s
myArray = [];
for (i = 0; i < thisComp.numLayers; i++) {
myArray[i] = thisComp.layer(i+1).name;
}
myArray.slice(0, thisComp.numLayers).join("\r")
# from @marcusround via the MDA Slack
ffmpeg -i input.avi -filter_complex "split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" output.gif
// calculates the length (in pixels) of two positions or points in 2D or 3D space.
// apply to camera's focus distance property
length(pointOfInterest, position)
// link two layers to obj1 and obj2 for their length
obj1 = thisComp.layer("OBJECT 1 LAYER NAME").transform.position;
obj2 = thisComp.layer("OBJECT 2 LAYER NAME").transform.position;
length(obj1, obj2)
// apply to the orientation property of a 3D layer
// this example looks at a layer called "Look At Me"
lookAt(thisComp.layer("Look At Me").position, position);
// loopIn and loopOut
loopIn() + loopOut() - value;
// works with all loop types
loopIn("pingpong") + loopOut("pingpong") - value;
loopIn("offset") + loopOut("offset") - value;
loopIn("offset") + loopOut("continue") - value;
// and with modifiers
loopIn("pingpong") + loopOut("pingpong", 1) - value;
freq = 1; // regular wiggle controls
amp = 110; // regular wiggle controls
octaves = 1; // default value (required for full wiggle expression: no need to edit)
ampMultiplier = 0.5; // default value (required for full wiggle expression: no need to edit)
layerLength = thisLayer.outPoint - thisLayer.inPoint; // length of layer in seconds
loopTime = layerLength; // loop for length of the layer: this can be changed!
t = time % loopTime; // loop reset: every `loopTime` t = 0
originalWiggle = wiggle(freq, amp, octaves, ampMultiplier, t);
wiggleWiggle = wiggle(freq, amp, octaves, ampMultiplier, t - loopTime);
linear(t, 0, loopTime, originalWiggle, wiggleWiggle)
// shift + parent shape layer to text layer
// below is applied to the shape layer's size property
sourceLayer = thisLayer.parent; // change source
sourceLayerWidth = sourceLayer.sourceRectAtTime().width;
sourceLayerHeight = sourceLayer.sourceRectAtTime().height;
sourceLayerScaleX = sourceLayer.transform.scale[0] / 100;
sourceLayerScaleY = sourceLayer.transform.scale[1] / 100;
// requires slider called "Padding"
padding = effect("Padding")("Slider");
// just width
// x = (sourceLayerWidth + padding) * sourceLayerScaleX;
// y = value[1];
// just height
// x = value[0];
// y = (sourceLayerHeight + padding) * sourceLayerScaleY;
// both width and height
x = (sourceLayerWidth + padding) * sourceLayerScaleX;
y = (sourceLayerHeight + padding) * sourceLayerScaleY;
[x,y]
// below is applied to the shape layer's scale property
sourceLayer = thisLayer.parent; // change source
x = value[0] / (sourceLayer.transform.scale[0] / 100);
y = value[1] / (sourceLayer.transform.scale[1] / 100);
[x, y]
// give 2D effects or properties the ability to use 3D positioning
// toComp is a layer space transform method that transforms values from a layer space to a composition space.
src = thisComp.layer('Layer 1');
src.toComp([0,0,0]);
// requires a four checkbox controls (named "Top", "Right", "Bottom", "Left") on this layer
// below is applied to this layer's position property
// this keeps the layer in the same visual position
// note this breaks if you separate dimensions (in that case apply individually with no array syntax for `value`)
// additionally, if your layer is scaled from 100% it may not work as expected (todo: fix that)
x = value[0] + transform.anchorPoint[0];
y = value[1] + transform.anchorPoint[1];
[x, y]
// below is applied to this layer's anchor point property
sourceLayer = thisLayer.sourceRectAtTime();
sourceLayerHeight = sourceLayer.height;
sourceLayerWidth = sourceLayer.width;
sourceLayerTop = sourceLayer.top;
sourceLayerLeft = sourceLayer.left;
if ((effect("Top")("Checkbox") == true) && (effect("Left")("Checkbox") == true)) { // top left
x = sourceLayerLeft;
y = sourceLayerTop;
[x,y];
} else if ((effect("Bottom")("Checkbox") == true) && (effect("Right")("Checkbox") == true)) { // bottom right
x = sourceLayerLeft + sourceLayerWidth;
y = sourceLayerTop + sourceLayerHeight;
[x,y];
} else if ((effect("Top")("Checkbox") == true) && (effect("Right")("Checkbox") == true)) { // top right
x = sourceLayerLeft + sourceLayerWidth;
y = sourceLayerTop;
[x,y];
} else if ((effect("Bottom")("Checkbox") == true) && (effect("Left")("Checkbox") == true)) { // bottom left
x = sourceLayerLeft;
y = sourceLayerTop + sourceLayerHeight;
[x,y];
} else if (effect("Top")("Checkbox") == true) { // top center
x = sourceLayerLeft + (sourceLayerWidth / 2);
y = sourceLayerTop;
[x,y];
} else if (effect("Right")("Checkbox") == true) { // right center
x = sourceLayerLeft + sourceLayerWidth;
y = sourceLayerTop + (sourceLayerHeight / 2);
[x,y];
} else if (effect("Bottom")("Checkbox") == true) { // bottom center
x = sourceLayerLeft + (sourceLayerWidth / 2);
y = sourceLayerTop + sourceLayerHeight;
[x,y];
} else if (effect("Left")("Checkbox") == true) { // left center
x = sourceLayerLeft;
y = sourceLayerTop + (sourceLayerHeight / 2);
[x,y];
} else [0, 0]
// apply to any property to limit its framerate
posterizeTime(5); // 5 fps
valueAtTime(time);
// compIndex = thisComp.layer("Comp Index").text.sourceText.value
// or just regular ol' layer index:
seedRandom(index,true);
h = random(); // mess with..
s = random(); // these values..
l = random(); // individually
hslToRgb([h,s,l,1]);
// similar to positionAnchorPoint.jsx, except meant for a rectangle shape on a shape layer...
// will require checkbox controls (named "Top", "Right", "Bottom", "Left") on this layer
// below goes on Layer > Contents > Rectangle 1 > Transform > Anchor Point
w = content("Rectangle 1").content("Rectangle Path 1").size[0];
h = content("Rectangle 1").content("Rectangle Path 1").size[1];
top = effect("Top")("Checkbox") == 1;
right = effect("Right")("Checkbox") == 1;;
bottom = effect("Bottom")("Checkbox") == 1;;
left = effect("Left")("Checkbox") == 1;;
x = 0;
y = 0;
if (top) y = h / -2;
if (right) x = w / 2;
if (bottom) y = h / 2;
if (left) x = w / -2;
[x, y];
// and this goes on Layer > Transform > Position
x = content("Rectangle 1").transform.anchorPoint[0];
y = content("Rectangle 1").transform.anchorPoint[1];
[x, y];
// a few basic ways to manipulate and combine source text with other elements.
// concat strings to source
"(" + text.sourceText + ")"
// countdown example
"T minus " + effect("Controller")("Slider").value + " seconds"
# split video file by `n` seconds
# run in terminal
#
# https://unix.stackexchange.com/a/212518
# set length here
ffmpeg -i input.mp4 -c copy -map 0 -segment_time 00:20:00 -f segment -reset_timestamps 1 output%03d.mp4
# ^20 minutes!
# https://superuser.com/questions/630124/dividing-a-video-clip-by-4-areas
# sub `-acodec copy` for `-an` for no audio!
ffmpeg -i in.mp4 -vf crop=iw/2:ih/2:0:0 -acodec copy v1.mp4
ffmpeg -i in.mp4 -vf crop=iw/2:ih/2:iw/2:0 -acodec copy v2.mp4
ffmpeg -i in.mp4 -vf crop=iw/2:ih/2:0:ih/2 -acodec copy v3.mp4
ffmpeg -i in.mp4 -vf crop=iw/2:ih/2:iw/2:ih/2 -acodec copy v4.mp4
// find out info about another layer's properties and methods
// apply to the `source text` property of an empty text layer, used for debugging
//
// https://helpx.adobe.com/after-effects/using/legacy-and-extend-script-engine.html#reflect-properties-reflect-methods
let obj = thisProperty; // pickwhip property here
let props = [];
do {
Object.getOwnPropertyNames(obj).forEach(prop => {
if (props.indexOf(prop) === -1) {
props.push(prop);
}
});
} while (obj = Object.getPrototypeOf(obj));
props.join("\n");
// requires two sliders ("Frequency", "Amplitude")..
freq = effect("Frequency")("Slider");
amp = effect("Amplitude")("Slider");
wiggle(freq, amp);
// ..or with checkbox named "Toggle"
toggle = src("Toggle")("Checkbox");
if (toggle == true) {
freq = effect("Frequency")("Slider");
amp = effect("Amplitude")("Slider");
wiggleValue = wiggle(freq, amp);
} else {
wiggleValue = value;
}
// include this if you can make a dropdown to select dimensions (pseudo effect maker/xml)
switch (src("Axis").value) {
case 1:
wiggleValue;
break;
case 2:
[wiggleValue[0], value[1], value[2]];
break;
case 3:
[value[0], wiggleValue[1], value[2]];
break;
case 4:
[value[0], value[1], wiggleValue[2]];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment