    :cur-time nil
    :down false
    :obstacles []
+   :pause false
    })
 
 (def obstacle-types

    40 (swap! state assoc :down false)
    nil))


(defn update-obstacles [{:keys [obstacles pos-x] :as state}]
  (if (< (count obstacles) 1)
    (update state :obstacles conj (assoc (rand-nth obstacle-types) :pos (+ pos-x game-width)))
    (update state :obstacles
            (fn [obstacles]
              (filter #(> (:pos %) (- pos-x (:width %))) obstacles)))))

(defn game-loop [state end]
  (let [{:keys [cur-time]} @state
        next-time (js/performance.now)
        delta (- next-time cur-time)]
    (when-not (nil? cur-time)
      (swap! state update :pos-x + (* (:speed-x @state) delta))
      (swap! state update :pos-y #(max 0 (+ % (* (:speed-y @state) delta))))
      (swap! state update :speed-y + (* gravity delta))
      (swap! state update-obstacles))
    (swap! state assoc :cur-time next-time))
  (when-not @end
    (js/requestAnimationFrame #(game-loop state end))))

  (println x)
  x)

(defn dbg- [x msg]
  (println msg x)
  x)

(def runner {:width 112 :height 72})
(def floor-y 85)
(def game-width 800)
(def jump-speed 1)
(def gravity -0.0038)
(def runner-offset 215)

;; 38 up, 40 down, 80 p
(defn handle-key [state key]
  (case (.-keyCode key)
    38 (when (= (:pos-y @state) 0)
         (swap! state assoc :speed-y jump-speed))
    40 (swap! state assoc :down true)
    80 (swap! state update :pause not)
    nil))

(defn handle-key-up [state key]
