To embed these individually append ?file="FILENAME"
to the embed src
link.
<script src="https://gist.github.com/fartinmartin/f6fe63328817a6eff17a07e60b2a6eb1.js?file=lookAtLayer.jsx"></script>
To embed these individually append ?file="FILENAME"
to the embed src
link.
<script src="https://gist.github.com/fartinmartin/f6fe63328817a6eff17a07e60b2a6eb1.js?file=lookAtLayer.jsx"></script>
# 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]]; | |
} |