docs: function smooth_scroll_to(element, target, duration) {
      target = Math.round(target);
      duration = Math.round(duration);
      if (duration < 0) {
          return Promise.reject('bad duration');
      }
      if (duration === 0) {
          element.scrollTop = target;
          return Promise.resolve('no-duration');
      }
  
      let start_time = Date.now();
      let end_time = start_time + duration;
  
      let start_top = element.scrollTop;
      let distance = target - start_top;
  
      // based on http://en.wikipedia.org/wiki/Smoothstep
      let smooth_step = function(start, end, point) {
          if (point <= start) {
              return 0;
          }
          if (point >= end) {
              return 1;
          }
          let x = (point - start) / (end - start); // interpolation
          return x * x * (3 - 2 * x);
      }
  
      return new Promise(function(resolve, reject) {
          // This is to keep track of where the element's scrollTop is
          // supposed to be, based on what we're doing
          let previous_top = element.scrollTop;
  
          let timer = null;
          // This is like a think function from a game loop
          let scroll_frame = function() {
              /*
              // This logic is too fragile
              if(element.scrollTop != previous_top) {
                  window.clearInterval(timer);
                  reject('interrupted');
                  return;
              }
              */
              // set the scrollTop for this frame
              let now = Date.now();
              let point = smooth_step(start_time, end_time, now);
              let frameTop = Math.round(start_top + (distance * point));
              element.scrollTop = frameTop;
  
              // check if we're done!
              if (now >= end_time) {
                  window.clearInterval(timer);
                  resolve('done');
                  return;
              }
  
              // If we were supposed to scroll but didn't, then we
              // probably hit the limit, so consider it done; not
              // interrupted.
              if (element.scrollTop === previous_top && element.scrollTop !== frameTop) {
                  window.clearInterval(timer);
                  resolve('limit');
                  return;
              }
              previous_top = element.scrollTop;
          }
  
          // boostrap the animation process
          timer = setInterval(scroll_frame, 10);
      });
  }