Skip to Content


Time actions (or groups of actions).

JavaScript April 7, 2021


nebula.timer(uniqueID, action, name)


(Required) (String) A unique ID to identify this timer
Default: None

(Optional) (String) What action to be performed
Default: "start" or "stop" (See below)

(Optional) (String) The name of the action being timed
Default: false

Parameter Notes

action can be one of the following:

  • “start”: Begin timing (or if timer already running, trigger an “out lap”).
  • “lap”: Stop a previous timer and immediately start again.
  • “end”: End timing (it can not be modified once it has ended).

Request or provide clarification »


jQuery('.start-timer a').on('click touch tap', function(){
    nebula.timer('example', 'start');
    return false;

jQuery('.lap-timer a').on('click touch tap', function(){
    nebula.timer('example', 'lap');
    return false;

jQuery('.end-timer a').on('click touch tap', function(){
    nebula.timer('example', 'end');
    return false;



Open the JavaScript console to see the data for this example.

Start Timer

New Lap


Additional Notes

This function stores timing data using in a window nebulaTimings object- this object is organized by uniqueID.

Each uniqueID contains an object of data including:

  • started: When the timer was started
  • cumulative: The total time of all laps
  • total: The total time of current and previous laps.
  • lap: An object of lap data including:
    • name: The name of the lap
    • out: Whether this an out lap (an inactive time between two “hot” laps).
    • started: The time this lap was started
    • stopped: The time this lap was stopped
    • duration: How long this lap took
    • progress: The total time from when all timings started until the end of this lap.

For further clarification, an “out” lap is an inactive lap that is between two “hot” laps. This can happen when the user does some other action in between two timed actions. An out lap is triggered when a second (or more) “start” action is used- when this happens, the previous lap is labeled an “out” lap.

This function also adds performance.mark() for each individual item and performance.measure() for each uniqueID. This data can be accessed using the User Timing API with functions such as performance.getEntries() or performance.getEntriesByType.

Was this page helpful? Yes No

    A feedback message is required to submit this form.

    Please check that you have entered a valid email address.

    Enter your email address if you would like a response.

    Thank you for your feedback!

    Source File

    Located in /assets/js/modules/utilities.js on line 471.

    No Hooks

    This function does not have any filters or actions available. Request one?

    Note: This function contains 1 to-do comment.

    nebula.timer = function(uniqueID, action, name){
        if ( !window.performance ){ //Safari 11+
            return false;
        if ( typeof nebula.timings === 'undefined' ){
            nebula.timings = [];
        //uniqueID is required
        if ( !uniqueID || uniqueID === 'start' || uniqueID === 'lap' || uniqueID === 'end' ){
  'nebula.timer() requires a uniqueID.', '/functions/timer/');
            return false;
        if ( !action ){
            if ( typeof nebula.timings[uniqueID] === 'undefined' ){
                action = 'start';
            } else {
                action = 'lap';
        //Can not lap or end a timing that has not started.
        if ( action !== 'start' && typeof nebula.timings[uniqueID] === 'undefined' ){
  'nebula.timer() cannot lap or end a timing that has not started.', '/functions/timer/');
            return false;
        //Can not modify a timer once it has ended.
        if ( typeof nebula.timings[uniqueID] !== 'undefined' && nebula.timings[uniqueID].total > 0 ){
            return nebula.timings[uniqueID].total;
        //Update the timing data!
        let currentTime =;
        if ( action === 'start' && typeof nebula.timings[uniqueID] === 'undefined' ){
            nebula.timings[uniqueID] = {
                started: currentTime,
                cumulative: 0,
                total: 0,
                lap: [],
                laps: 0
            let thisLap = {
                name: false,
                started: currentTime,
                stopped: 0,
                duration: 0,
                progress: 0,
            if ( typeof name !== 'undefined' ){
                nebula.timings[uniqueID].lap[0].name = name;
            //Add the time to User Timing API (if supported)
            if ( typeof performance.measure !== 'undefined' ){
                performance.mark(uniqueID + ' [Start]');
        } else {
            let lapNumber = nebula.timings[uniqueID].lap.length;
            //Finalize the times for the previous lap
            nebula.timings[uniqueID].lap[lapNumber-1].stopped = currentTime;
            nebula.timings[uniqueID].lap[lapNumber-1].duration = currentTime-nebula.timings[uniqueID].lap[lapNumber-1].started;
            nebula.timings[uniqueID].lap[lapNumber-1].progress = currentTime-nebula.timings[uniqueID].started;
            nebula.timings[uniqueID].cumulative = currentTime-nebula.timings[uniqueID].started;
            //An "out" lap means the timing for this lap may not be associated directly with the action (Usually resetting for the next actual timed lap).
            if ( action === 'start' ){
                nebula.timings[uniqueID].lap[lapNumber-1].out = true; //If another 'start' was sent, then the previous lap was an out lap
            } else {
                nebula.timings[uniqueID].lap[lapNumber-1].out = false;
            //Prepare the current lap
            if ( action !== 'end' ){
                if ( lapNumber > 0 ){
                    nebula.timings[uniqueID].lap[lapNumber] = {};
                    nebula.timings[uniqueID].lap[lapNumber].started = nebula.timings[uniqueID].lap[lapNumber-1].stopped;
                if ( typeof name !== 'undefined' ){
                    nebula.timings[uniqueID].lap[lapNumber].name = name;
                //Add the time to User Timing API (if supported)
                if ( typeof performance.measure !== 'undefined' ){
                    let lapID = name || lapNumber;
                    performance.mark(uniqueID + ' [Lap ' + lapID + ']');
            //Return individual lap times unless 'end' is passed- then return total duration. Note: 'end' can not be updated more than once per uniqueID! Subsequent calls will return the total duration from first call.
            if ( action === 'end' ){
                //Add the time to User Timing API (if supported)
                if ( typeof performance.measure !== 'undefined' ){
                    performance.mark(uniqueID + ' [End]');
                    if ( performance.getEntriesByName(uniqueID + ' [Start]', 'mark') ){ //Make sure the start mark exists
                        performance.measure(uniqueID, uniqueID + ' [Start]', uniqueID + ' [End]');
                nebula.timings[uniqueID].stopped = currentTime;
                nebula.timings[uniqueID].total = currentTime-nebula.timings[uniqueID].started;
                //@todo "Nebula" 0: Add all hot laps together (any non-"out" laps)
                return nebula.timings[uniqueID].total;
            } else if ( !nebula.timings[uniqueID].lap[lapNumber-1].out ){
                return nebula.timings[uniqueID].lap[lapNumber-1].duration;


    To override or disable this JavaScript function, simply redeclare it with the exact same function name.

    nebula.timer = function(uniqueID, action, name){
        //Write your own code here, leave it blank, or return false.