Activity › Forums › Adobe After Effects › Determine frames of approximation between a null and multiple shapes
-
Determine frames of approximation between a null and multiple shapes
Posted by Klaus Hertweck on December 3, 2025 at 4:38 pmI have a setup of multiple shape layers and one null on a comp. The shapes are static and the null is moving around. I want to determine the frame for whenever the null moves within a certain range (let’s assume 100 pixel) to each individual shape.
So far, I managed to determine the first frame this happens:
var rangeMin = 100;
var posDistance = effect(“Shortest Distance”)(“Slider”); //Distance between the shape and the null calculated on a separate Expression Control Slider.
for (i = 0; i <= timeToFrames(thisComp.duration); i++) {
if (posDistance.valueAtTime(framesToTime(i)) <= rangeMin) break
}This gives me the frame i for the first time the null comes within the range.
However, the null might pass the shape a second time, or multiple times. How can I determine all the frames this happens?
Klaus Hertweck replied 5 months, 1 week ago 3 Members · 7 Replies -
7 Replies
-
Dan Ebberts
December 3, 2025 at 5:31 pmI’m not sure what you want to do with the result, but this expression will fill the frames array with all the frames where a close encounter first occurs. However, on each frame, this expression has to examine the entire comp, so you might want to consider converting the expression to keyframes at some point if processing time becomes an issue:
var rangeMin = 100;
var posDistance = effect("Shortest Distance")("Slider");
frames = [];
inRange = false;
for (i = 0; i <= timeToFrames(thisComp.duration); i++) {
if (inRange){
if (posDistance.valueAtTime(framesToTime(i)) > rangeMin){
inRange = false;
}
}else{
if (posDistance.valueAtTime(framesToTime(i)) <= rangeMin){
frames.push(i);
inRange = true;
}
}
} -
Klaus Hertweck
December 3, 2025 at 6:09 pmThank you for the solution. It works but as I found out, as you said, I cannot really work with it.
Also, even my initial expression with a about 20 shapes and one minute comp duration brought the comp to a still stand. I have to think of a different approach.
-
Klaus Hertweck
December 3, 2025 at 7:04 pmAs I have stated above, I have a setup of multiple shape layers and one null on a comp. The shapes are static and the null is moving around. The shapes have a glow effect attached to it.
My usual approach is a linear expression: the closer the null gets to a shape, starting at a certain range, the effect opacity rises from 0 to 100 and down again when the null moves away.
However, the effect I want to achieve is a little different. As soon as the null approaches, the shape should start animating from 0 to 100 and back. But this animation should play out even if the null is no longer close to it. The proximity of the null is basically the trigger for the animation to start.
-
John Martin
December 3, 2025 at 7:43 pmHey Klaus, it’s time to solve this, I’ve worked on some code for you, i left some comments so you can orient yourself, it turns the null’s proximity into a one-shot trigger for each shape. When the null crosses into the defined distance, the expression records that moment and starts a self-contained 0→100→0 animation for that shape. The animation keeps playing even if the null leaves immediately, and it won’t restart until the null exits the range and enters again later.
Good luck and lemme know if you apprecciate the help!
// Paste this on the property you want to animate (e.g. Glow Opacity or a Slider).
// Adjust rangeMin, animLen and nullName as needed.
var rangeMin = 100; // trigger distance in pixels
var animLen = 1.0; // animation length in seconds (how long the 0->100->0 plays)
var nullName = "Null 1"; // name of your null layer
var easeInOut = true; // use ease() for smooth curve (true) or linear (false)
var nl = thisComp.layer(nullName);
var frameDur = thisComp.frameDuration;
var maxBack = animLen + 0.5; // how far back to search for a trigger (seconds)
function distAt(t){
var pShape = thisLayer.toComp(thisLayer.anchorPoint);
var pNull = nl.toComp(nl.anchorPoint);
return length(pShape, pNull);
}
// find the most recent entrance (time when distance crossed from >range to <=range)
// search backward up to maxBack, stepping by one frame
function findLastEntrance(t){
var steps = Math.ceil(maxBack / frameDur);
for (var i = 0; i <= steps; i++){
var ts = t - i*frameDur;
if (ts <= 0) break;
var dNow = distAt(ts);
var dPrev = distAt(Math.max(0, ts - frameDur));
if (dNow <= rangeMin && dPrev > rangeMin){
// refine a bit with half-step binary search for a slightly more accurate entrance time
var a = Math.max(0, ts - frameDur);
var b = ts;
for (var k = 0; k < 6; k++){ // 6 iterations -> ~1/64 frame accuracy
var m = (a + b)/2;
if (distAt(m) <= rangeMin) b = m; else a = m;
}
return b;
}
}
return -1;
}
var t = time;
var lastEnter = findLastEntrance(t);
if (lastEnter < 0){
// no recent trigger within animLen+0.5s -> idle
0
} else {
var prog = (t - lastEnter) / animLen;
if (prog < 0 || prog > 1){
0
} else {
if (easeInOut){
// go 0 -> 100 -> 0 using a triangular eased curve
var val;
if (prog <= 0.5){
val = ease(prog*2, 0, 1, 0, 100); // first half 0->100
} else {
val = ease((prog-0.5)*2, 0, 1, 100, 0); // second half 100->0
}
val
} else {
var val;
if (prog <= 0.5){
val = linear(prog*2, 0, 1, 0, 100);
} else {
val = linear((prog-0.5)*2, 0, 1, 100, 0);
}
val
}
}
} -
Klaus Hertweck
December 3, 2025 at 9:24 pmHi John, I certainly appreciate your help and what you are describing is exactly what I am looking for. I will give this a test run first thing tomorrow morning. Hopefully I can learn something as well and put it to good use for future problems ;-).
Cheers, Klaus
-
Klaus Hertweck
December 4, 2025 at 11:47 amHi John, I now had time to run your expression and sadly nothing happens.
I tried to pinpoint the issue and I am pretty sure it is the “return -1” for the “function findLastEntrance(t). Shouldn’t there be some kind of variable instead of -1?
I replaced the -1 with the number of seconds when there is the actual crossing happening, and the rest of the expression works fine.
Reply to this Discussion! Login or Sign Up