text: 'use strict';
  
  Object.defineProperty(exports, '__esModule', { value: true });
  
  var heyListen = require('hey-listen');
  
  var prevTime = 0;
  var onNextFrame = typeof window !== 'undefined' && window.requestAnimationFrame !== undefined
      ? function (callback) { return window.requestAnimationFrame(callback); }
      : function (callback) {
          var timestamp = Date.now();
          var timeToCall = Math.max(0, 16.7 - (timestamp - prevTime));
          prevTime = timestamp + timeToCall;
          setTimeout(function () { return callback(prevTime); }, timeToCall);
      };
  
  var createStep = (function (setRunNextFrame) {
      var processToRun = [];
      var processToRunNextFrame = [];
      var numThisFrame = 0;
      var isProcessing = false;
      var i = 0;
      var cancelled = new WeakSet();
      var toKeepAlive = new WeakSet();
      var renderStep = {
          cancel: function (process) {
              var indexOfCallback = processToRunNextFrame.indexOf(process);
              cancelled.add(process);
              if (indexOfCallback !== -1) {
                  processToRunNextFrame.splice(indexOfCallback, 1);
              }
          },
          process: function (frame) {
              var _a;
              isProcessing = true;
              _a = [
                  processToRunNextFrame,
                  processToRun
              ], processToRun = _a[0], processToRunNextFrame = _a[1];
              processToRunNextFrame.length = 0;
              numThisFrame = processToRun.length;
              if (numThisFrame) {
                  var process_1;
                  for (i = 0; i < numThisFrame; i++) {
                      process_1 = processToRun[i];
                      process_1(frame);
                      if (toKeepAlive.has(process_1) === true && !cancelled.has(process_1)) {
                          renderStep.schedule(process_1);
                          setRunNextFrame(true);
                      }
                  }
              }
              isProcessing = false;
          },
          schedule: function (process, keepAlive, immediate) {
              heyListen.invariant(typeof process === 'function', 'Argument must be a function');
              var addToCurrentBuffer = immediate && isProcessing;
              var buffer = addToCurrentBuffer ? processToRun : processToRunNextFrame;
              if (keepAlive)
                  toKeepAlive.add(process);
              if (buffer.indexOf(process) === -1) {
                  buffer.push(process);
                  if (addToCurrentBuffer)
                      numThisFrame = processToRun.length;
              }
          }
      };
      return renderStep;
  });
  
  var StepId;
  (function (StepId) {
      StepId["Read"] = "read";
      StepId["Update"] = "update";
      StepId["Render"] = "render";
      StepId["PostRender"] = "postRender";
      StepId["FixedUpdate"] = "fixedUpdate";
  })(StepId || (StepId = {}));
  
  var maxElapsed = 40;
  var defaultElapsed = (1 / 60) * 1000;
  var useDefaultElapsed = true;
  var willRunNextFrame = false;
  var isProcessing = false;
  var frame = {
      delta: 0,
      timestamp: 0
  };
  var stepsOrder = [
      StepId.Read,
      StepId.Update,
      StepId.Render,
      StepId.PostRender
  ];
  var setWillRunNextFrame = function (willRun) { return (willRunNextFrame = willRun); };
  var _a = stepsOrder.reduce(function (acc, key) {
      var step = createStep(setWillRunNextFrame);
      acc.sync[key] = function (process, keepAlive, immediate) {
          if (keepAlive === void 0) { keepAlive = false; }
          if (immediate === void 0) { immediate = false; }
          if (!willRunNextFrame)
              startLoop();
          step.schedule(process, keepAlive, immediate);
          return process;
      };
      acc.cancelSync[key] = function (process) { return step.cancel(process); };
      acc.steps[key] = step;
      return acc;
  }, {
      steps: {},
      sync: {},
      cancelSync: {}
  }), steps = _a.steps, sync = _a.sync, cancelSync = _a.cancelSync;
  var processStep = function (stepId) { return steps[stepId].process(frame); };
  var processFrame = function (timestamp) {
      willRunNextFrame = false;
      frame.delta = useDefaultElapsed
          ? defaultElapsed
          : Math.max(Math.min(timestamp - frame.timestamp, maxElapsed), 1);
      if (!useDefaultElapsed)
          defaultElapsed = frame.delta;
      frame.timestamp = timestamp;
      isProcessing = true;
      stepsOrder.forEach(processStep);
      isProcessing = false;
      if (willRunNextFrame) {
          useDefaultElapsed = false;
          onNextFrame(processFrame);
      }
  };
  var startLoop = function () {
      willRunNextFrame = true;
      useDefaultElapsed = true;
      if (!isProcessing)
          onNextFrame(processFrame);
  };
  var getFrameData = function () { return frame; };
  
  exports.default = sync;
  exports.cancelSync = cancelSync;
  exports.getFrameData = getFrameData;
  