                (reset! (:state app) new-state)
                (mutate-dom (:element app) (:channels app)))))))
 
-(defn ^:export main
+(sm/defn ^:export main :- js/Object
   "Application entry point; returns the public JavaScript API"
-  [element config]
-  (let [app (load-app element (or (js->clj config) {}))]
+  [element :- js/HTMLDivElement
+   config :- AnyMap]
+  (let [app (load-app element (js->clj (or config {})))]
     (show/app (:element app) @(:state app) (:channels app))
     (init-updates app)
     (api/build (:channels app) (:state app) (:element app))))

              :set-pieces (a/chan)
              :drop-off (a/chan)
              :api-move (a/chan)
              :show-moved (a/chan)
              }
   :consumers {:toggle-orientation ctrl/toggle-orientation
               :set-orientation ctrl/set-orientation
               :set-fen ctrl/set-fen

            [chessground.data :as data]
            [chessground.api :as api]
            [chessground.show :as show]
            [chessground.ctrl :as ctrl]
            [chessground.schemas :refer [AnyMap]]
            [schema.core :as s]
            [cljs.core.async.impl.channels :refer [ManyToManyChannel]])
  (:require-macros [cljs.core.async.macros :as am]
                   [schema.macros :as sm :refer [defschema]]))

(extend-type js/NodeList ISeqable (-seq [array] (array-seq array 0)))

(defschema AppMap
  {:element   js/HTMLDivElement
   :state     Atom
   :channels  {s/Keyword ManyToManyChannel}
   :consumers {s/Keyword js/Function}})

(sm/defn load-app :- AppMap
  "Return a map containing the initial application"
  [element :- js/HTMLDivElement
   config :- js/Object]
  {:element element
   :state (atom (data/make config))
   :channels {:toggle-orientation (a/chan)
