   "
   [x y z]
   (invoke-now
-    (let [[panel timer] (surface-panel (or x (nil-param))
-                                       (or y (nil-param))
-                                       (or z (nil-param)))
+    (let [[panel timer] (surface-panel x y z)
           f (frame :title "Surface"
                    :content panel
                    :on-close :dispose)]
       (listen f :window-closed (fn [_] (.stop timer)))
       (-> f pack! show!))))
+
+(defn surface-grid
+  "Create a grid of surfaces. params is a sequence of [x y z] triples passed
+  to (surface). Returns the frame that displays the grid. If you get an
+  empty surface, it probably means you've got an inst without sufficient
+  metadata.
+
+  See:
+    (surface)
+  "
+  [& params]
+  (let [p-and-t (for [p params] (apply surface-panel p))
+        panels (map first p-and-t)
+        timers (map second p-and-t)
+        f (frame :title "Surfaces"
+                 :content (grid-panel
+                            :columns (int (Math/ceil (Math/sqrt (count panels))))
+                            :border 5 :hgap 5 :vgap 5
+                            :background :black
+                            :items panels))]
+    (listen f :window-closed (fn [_]
+                               (doseq [t timers] (.stop t))))
+    (-> f pack! show!)))
 
 (defn synth-param
   "Create a surface param for a synth or instrument.

      :mouse-released (partial handle-release-event state t))
    [c t]))

(defn- nil-param
  []
  (let [v (atom 0.0)]
    {:name ""
    :get-value (fn [] @v)
    :set-value (fn [new-val] (reset! v new-val))
    :min 0.0
    :max 1.0}))

(defn surface
  "Create a 'surface' for controlling params. Takes three

      (repaint! c)))
  c)

(defn- nil-param
  []
  (let [v (atom 0.0)]
    {:name ""
    :get-value (fn [] @v)
    :set-value (fn [new-val] (reset! v new-val))
    :min 0.0
    :max 1.0}))

(defn surface-panel [x y z]
  (let [state {:color :blue
               :x (or x (nil-param))
               :y (or y (nil-param))
               :z (or z (nil-param))
               :dir (atom nil)}
        c (canvas :preferred-size [400 :by 300]
                  :cursor :crosshair
                  :paint (fn [c g] (paint-surface state c g)))
        t (timer (partial handle-timer state)
