Skip to content

Instantly share code, notes, and snippets.

@gfxhacks
Created August 9, 2020 04:51
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gfxhacks/058618bf728accb85c1c9895bdb3ab1c to your computer and use it in GitHub Desktop.
Save gfxhacks/058618bf728accb85c1c9895bdb3ab1c to your computer and use it in GitHub Desktop.
Full featured Countdown Timer rig for Adobe After Effects. More info at https://gfxhacks.com/timer-rig-in-after-effects-using-expressions
// Usage: In AE 2020 (17.0) or above, create a new composition or open an existing one. Then choose File -> Scripts -> Run Script File... to launch this script.
/*
Title: timer_rig.jsx
Author: gfxhacks.com
Description: Create a new Timer object in the active After Effects composition.
More Info: https://gfxhacks.com/timer-rig-in-after-effects-using-expressions
*/
app.beginUndoGroup("Create Timer");
// define timer expression
exp = '// get Timer properties\nrate = clamp(effect("Rate")("Slider"), 0, 100);\nh = effect("Start Time - Hours")("Slider");\nm = effect("Start Time - Minutes")("Slider");\ns = effect("Start Time - Seconds")("Slider");\nc = effect("Countdown")("Checkbox").value;\nms = effect("Milliseconds")("Checkbox").value;\nformat = effect("Time Format")("Menu").value;\nn = effect("Negative Time")("Checkbox").value;\n// convert Start Times to seconds and sum.\nst = h*3600 + m*60 + s;\n// count up or count down based on checkbox value\nt = c ? st - rate*(time - inPoint) : st + rate*(time - inPoint);\n// initialize time as [HH:MM:SS:MSS]\nf = t <= 0 ? [00, 00, 00, 000] : [t/3600, (t%3600)/60, t%60, t.toFixed(3).substr(-3)];\n// Round to whole numbers and add zero padding\nfor (i in f){ f[i] = String(Math.floor(f[i])).padStart(i>2?3:2, "0") }\n// remove ms if checkbox is off\nif(!ms) f.pop();\n// change Timer display based on chosen format\nswitch (format){\n // HH:MM:SS\n case 1:\n t = f.join(":");\n break;\n // MM:SS\n case 2:\n t = f.slice(1).join(":");\n break;\n // SS\n case 3:\n t = f.slice(2).join(":");\n}\n// prepend minus symbol to time if checkbox is on\nn ? "-" + t : t;';
// define expression control effects
effects = [
{
"type": "Checkbox Control",
"name": "Countdown",
"value": "1"
},
{
"type": "Dropdown Menu Control",
"name": "Time Format",
"value": ["HH:MM:SS", "MM:SS", "SS"]
},
{
"type": "Slider Control",
"name": "Rate",
"value": "1"
},
{
"type": "Slider Control",
"name": "Start Time - Hours",
"value": "24"
},
{
"type": "Slider Control",
"name": "Start Time - Minutes",
"value": "0"
},
{
"type": "Slider Control",
"name": "Start Time - Seconds",
"value": "0"
},
{
"type": "Checkbox Control",
"name": "Milliseconds",
"value": "1"
},
{
"type": "Checkbox Control",
"name": "Negative Time",
"value": "0"
},
]
try {
// get current comp
c = app.project.activeItem;
// add new text layer
t = c.layers.addText();
// rename text layer
t.name = "Timer";
try {
for (i in effects) {
// get current expression control effect
e = effects[i];
// add current expression control effect
s = t.property('Effects').addProperty(e.type);
// get current expression control effect index
id = s.propertyIndex;
// check if effect is of type dropdown, then set values.
// Dropdown Menu effect (new in 2020) is the only effect that requires to set values with: setPropertyParameters
s.property(1).isDropdownEffect ? s.property(1).setPropertyParameters(e.value) : s.property(1).setValue(e.value);
// rename effect using index reference - previous reference is lost when setting values.
t.property('Effects')(id).name = e.name;
}
// add timer expression to source text
t.text.sourceText.expression = exp;
} catch (e) {
alert('Script Failed!\nDropdown Menu control not found. Make sure you are running AE 2020 (17.0) or above.')
}
} catch (e) {
alert('Create or open a composition first!');
}
// add expression control effects to text layer
app.endUndoGroup();
@theryanj
Copy link

theryanj commented Dec 11, 2020

Hi Dan, Thanks so much for this! I was playing around and noticed when I switch from counting down to counting up, it starts at the number I chose for the countdown. What code can I add-in for an End Time for the counting up? ie. starting at 0:00 and stopping at the End Time 0:20.

@gfxhacks
Copy link
Author

gfxhacks commented Dec 12, 2020

Hey, just duplicate each Start Time slider and rename to End Time - make sure to set the total end time to be greater than the total start time. Try this code - the timer should stop when the end time is reached (enabled only when counting up).

// get Timer properties
rate = clamp(effect("Rate")("Slider"), 0, 100);
h = effect("Start Time - Hours")("Slider");
eh = effect("End Time - Hours")("Slider");
m = effect("Start Time - Minutes")("Slider");
em = effect("End Time - Minutes")("Slider");
s = effect("Start Time - Seconds")("Slider");
es = effect("End Time - Seconds")("Slider");
c = effect("Countdown")("Checkbox").value;
ms = effect("Milliseconds")("Checkbox").value;
format = effect("Time Format")("Menu").value;
n = effect("Negative Time")("Checkbox").value;
// convert Start Times to seconds and sum.
st = h*3600 + m*60 + s;
// convert End Times to seconds and sum.
et = eh*3600 + em*60 + es;
// count up or count down based on checkbox value
t = c ? st - rate*(time - inPoint) : st + rate*(time - inPoint);
// if counting up and count is greater than end time, stop counting (return end time)
t = !c && (t > et) ? et : t;
// initialize time as [HH:MM:SS:MSS]
f = t <= 0 ? [00, 00, 00, 000] : [t/3600, (t%3600)/60, t%60, t.toFixed(3).substr(-3)];
// Round to whole numbers and add zero padding
for (i in f){ f[i] = String(Math.floor(f[i])).padStart(i>2?3:2, "0") }
// remove ms if checkbox is off
if(!ms) f.pop();
// change Timer display based on chosen format
switch (format){
    // HH:MM:SS
    case 1:
        t = f.join(":");
        break;
    // MM:SS
    case 2:
        t = f.slice(1).join(":");
        break;
    // SS
    case 3:
        t = f.slice(2).join(":");
}
// prepend minus symbol to time if checkbox is on
n ? "-" + t : t;

For your reference, this is the added code:

eh = effect("End Time - Hours")("Slider");

em = effect("End Time - Minutes")("Slider");

es = effect("End Time - Seconds")("Slider");

// convert End Times to seconds and sum.
et = eh*3600 + em*60 + es;

// if counting up and count is greater than end time, stop counting (return end time)
t = !c && (t > et) ? et : t;

Lmk if this is what you were looking for 😊

@theryanj
Copy link

theryanj commented Dec 12, 2020

Excuse my language but HOLYSH*T, YOU ROCK!!! It's working great for me! Is there somewhere I can donate to you for helping me with this?

@gfxhacks
Copy link
Author

No worries 🤗 happy to help!

@elaperriere
Copy link

Hello, I tried to run the script and I got an error "Dropdown Menu Control" not found. I am running AE v17.1.4

I also have an issue regarding the script, I am getting "Error: String().padStart is not a function".

Any help would be appreciated!

@gfxhacks
Copy link
Author

gfxhacks commented Jan 26, 2021

Hey, make sure to have the Expression Engine in the Project Settings set to Javascript. You can find out more about the differences here: https://helpx.adobe.com/after-effects/user-guide.html/after-effects/using/legacy-and-extend-script-engine.ug.html
Unless working with older expressions, you may want to always use the more modern Javascript engine. Hope this solves the issue..
Screen Shot 2021-01-26 at 18 20 27

@elaperriere
Copy link

Hey, make sure to have the Expression Engine in the Project Settings set to Javascript. You can find out more about the differences here: https://helpx.adobe.com/after-effects/user-guide.html/after-effects/using/legacy-and-extend-script-engine.ug.html
Unless working with older expressions, you may want to always use the more modern Javascript engine. Hope this solves the issue..
Screen Shot 2021-01-26 at 18 20 27

Alright that worked! Sorry, still new to AE scripting.

There is still that bug regarding the Dropdown Menu control but the script still works... not sure why this is giving me an error!

@gfxhacks
Copy link
Author

Cool 🙌 - Regarding the dropdown not found issue, do you see an error at the bottom of your composition panel? Similar to this: Screen Shot 2021-01-26 at 18 47 25
What line does it mention the problem is at?

@elaperriere
Copy link

elaperriere commented Jan 26, 2021

No errors. That is the odd thing. it works fine but the popup message appears after running the script.

@gfxhacks
Copy link
Author

gfxhacks commented Jan 27, 2021

I see are you getting this error? Script Failed! Dropdown Menu control not found. Make sure you are running AE 2020 (17.0) or above.

If so there might be a bug with the script running on your version of AE. You can try upgrading.. Otherwise try setting up the controls manually, following this guide: https://gfxhacks.com/timer-rig-in-after-effects-using-expressions/#quick-reference

@mackenziee4
Copy link

Hi. This is such a cool script! It beats what I've used in the past by far.
I have a question about Zero Padding.
What could changes could I make to make it so that the zero padding in the HH part of an HH:MM:SS clock does not appear but still does in the MM and SS parts?

@gfxhacks
Copy link
Author

Heya,
You can chain a second conditional within the padstart method: .padStart(i>2?3:i<1?1:2, "0")
Not very pretty but works nonetheless! - basically considering HH:MM:SS:MSS positioned in the array at [0, 1, 2, 3], if the current item's position is greater than 2 (so the MSS at pos 3), pad with 3 zeros. If the position is less than 1 (so the HH at pos 0), pad with 1 zero. MM and SS (at pos 1 and 2 respectively) will pad with 2. Hope it helps :)

@mackenziee4
Copy link

Thank you so much!! This is exactly what I was looking for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment