   [el type fn]
   (.addEventListener el type fn false))
 
+;;-----------------------------------------------------------------------------
+;; Object Definitions
 ;;-----------------------------------------------------------------------------
 
 (defrecord Rect [x y width height color])

  (let [ctx (.getContext (by-id "canvas") "2d")
        events (chan (sliding-buffer 10) control-stream)]
    (event-loop! state events)
    (listen! js/window   "resize"  #(resize! ctx))
    (listen! js/document "keydown" #(put! events (.-keyCode %)))
    (resize! ctx)
    (animate! ctx)))

(set! (.-onload js/window) main)

;;-----------------------------------------------------------------------------

(defn draw-phase!
  [state ctx]
  (.clearRect ctx 0 0 SCALE-W SCALE-H)
  (doseq [object (vals @state)]
    (when (satisfies? IDrawable object)
      (draw! object ctx))))

(defn move-phase!
  [{:keys [ball] :as state}]
  (merge state {:ball (move ball)}))

(defn hit?
  [ball paddle]
  (let [{x1 :x y1 :y} paddle
        x2 (+ x1 (:width paddle))
        y2 (+ y1 (:height paddle))
        {x :x y :y radius :radius} ball]
    ;; janky when the ball hits a corner, I think.
    (or (and (<= y1 y y2) (<= x1 x x2))
        ;; Need to indicate if x or y direction is reversed
        (and (<= y1 y y2) (or (>= radius (dist x2 y x y))
                              (>= radius (dist x1 y x y))))
        (and (<= x1 x x2) (or (>= radius (dist x y2 x y))
                              (>= radius (dist x y1 x y)))))))

(defn collision-phase!
  [{:keys [ball paddle-1 paddle-2] :as state}]
  (if (or (hit? ball paddle-1)
          (hit? ball paddle-2))
    (assoc state :ball (assoc ball :vx (* -1 (:vx ball))))
    state))

(defn animate-loop!
  [state ctx]
  (swap! state #(-> % move-phase! collision-phase!))
  (draw-phase! state ctx)
  (.requestAnimationFrame js/window (partial animate-loop! state ctx)))

;;-----------------------------------------------------------------------------
;; Control
;;-----------------------------------------------------------------------------

(defn resize!
  [state ctx]
  (let [w (- (.-innerWidth js/window) 40)
        h (- (int (/ (* w 9) 16)) 40)]
    (-> (by-id "canvas")
        (attr! "width" w)
        (attr! "height" h))
    (.scale ctx (/ w SCALE-W) (/ h SCALE-H))
    (draw-phase! state ctx)))

(defn- event-loop!
  [state ch]
