                           :layer/signup-button true}})
       (clear-subscriber 201))))
 
-(defn run-animation* [owner tick-state max-tick current-tick]
-  (when (and (om/mounted? owner)
-             (>= max-tick current-tick))
-    (when-let [tick-fn (get-in tick-state [:ticks current-tick])]
-      (tick-fn owner))
-    (js/setTimeout #(run-animation* owner tick-state max-tick (inc current-tick))
-                   (:tick-ms tick-state))))
+(defn clear-ticks [tick-state ticks]
+  (update-in tick-state [:ticks] #(apply dissoc % ticks)))
+
+(defn middle-elem [v]
+  (if (seq v)
+    (nth v (quot (count v) 2))
+    nil))
+
+(defn run-animation* [owner start-ms current-ms tick-state min-tick max-tick]
+  (if (and (om/mounted? owner)
+           (seq (:ticks tick-state)))
+    (let [latest-tick (int (/ (- current-ms start-ms)
+                              (:tick-ms tick-state)))
+          tick-range (vec (range min-tick (inc latest-tick)))
+          ticks (-> (filter #(contains? (:keyframes tick-state) %) tick-range)
+                  set
+                  (conj (middle-elem tick-range)))]
+      (doseq [tick ticks]
+        (when-let [tick-fn (get-in tick-state [:ticks tick])]
+          (tick-fn owner)))
+      (utils/rAF (fn [timestamp]
+                   (run-animation* owner start-ms timestamp (clear-ticks tick-state tick-range) latest-tick max-tick))))))
 
 (defn run-animation
   "tick-state should be a map with keys :tick-ms, whose value is the number of ms between

                                        :fields {:mouse-position nil
                                                 :layers nil
                                                 :tool :text}})
                  (d/transact! (om/get-shared owner :db) [base-layer] {:bot-layer true}))))))

(defn signup-animation [document vw]
  (let [text "Sign in with Google"

  Unmount the component to stop the animation."
  [owner tick-state]
  (let [max-tick (apply max (keys (:ticks tick-state)))]
    (utils/rAF (fn [timestamp]
                 (run-animation* owner timestamp timestamp tick-state 0 max-tick)))))

(defn cleanup [owner]
  ((om/get-shared owner :cast!) :subscriber-updated {:client-id (ffirst state/subscriber-bot)
