   (apply swap! current-state f args)
   (sync-graph! @current-state))
 
+(defn swap-state-animated! [animation-signaller current-state f & args]
+  ; There's no way to arrange the arguments that isn't awkward. Luckily all the
+  ; uses will probably be right here.
+  (apply swap! current-state f args)
+  (sync-graph! @current-state :animation-signaller animation-signaller))
+
 (defn update-state! [current-state k f & args]
   (apply swap! current-state update k f args)
   (sync-graph! @current-state))

    (move-camera-on-swipe! gesture-manager current-state animation-observable)
    (switch-zoom-on-spacebar!
      current-state animation-observable animation-signaller)
    (zoom-out-on-pinch!
      gesture-manager current-state animation-observable animation-signaller)))


;; Gestures - pinch

(defn pinch-observable [manager svg]
  (.map (gesture-observable manager svg "pinchmove")
        (fn [e] {:center (math-vec (-> e .-center .-x) (-> e .-center .-y))
                 :scale (.-scale e)})))

(defn zoom-on-pinch! [manager
                      current-state
                      animation-observable
                      animation-signaller]
  (let [pinches (pinch-observable manager (:svg @current-state))
        pinch-ins (-> pinches (.filter #(< (:scale %) 0.8))
                      (suppress-while-animating animation-observable))
        pinch-outs (-> pinches (.filter #(> (:scale %) 1.2))
                       (suppress-while-animating animation-observable))]
    (.subscribe
      pinch-ins
      #(if (= (:projection @current-state) :fisheye)
         (set-projection! current-state :zoom-out animation-signaller)))
    (.subscribe
      pinch-outs
      #(if (= (:projection @current-state) :zoom-out)
         (zoom-in-to-pos! current-state
                          (zoom-out->world-pos @current-state (:center %))
                          animation-signaller)))))

;; Exported function to do magic

