Orchestrating everything is now as easy as this. And implementing the timeline class wasn't too difficult either: push timelines to a global array in their constructor, and call each timelines' step() function in a requestAnimationFrame loop. Depending on the current state, step will do nothing (pending promise or awaiting user input) or call the current function in the stack.