Nikita Beloglazov edited this page Jul 14, 2014 · 17 revisions
What is middleware?

A Quil middleware is a function which takes a map containing options passed to defsketch or sketch and returns updated map. The simplest middleware (which does nothing) is the identity function: it takes a map and returns the map unmodified. The idea is similar to Ring middleware. Middleware support was added in Quil 2.1.0.

List of built-in middleware

You can find all built-in middleware in the quil.middleware namespace. All middleware available both in clj and cljs versions, if not stated otherwise. Here is the list:

  • fun-mode - introduces functional mode.
  • navigation-3d - enables shooter-like navigation in 3D space. Check wiki article for more details.
  • pause-on-error - pauses sketch, if some handler throws an exception. Prints info about error on screen and waits for key press. Allows user to fix the error and reload broken handler on-fly. Not available in cljs.
How to use middleware

To enable middleware you can use :middleware option for defsketch or sketch. For example, suppose that we have a my-middleware function - our custom middleware which does something. Here is how we use it:

(q/defsketch my-sketch
  :size [500 500]
  :draw draw
  :middleware [my-middleware])

You can see that the :middleware option takes a vector of middlewares so you can use multiple middleware functions at the same time. The functions in a middleware vector [f g h] are applied in following order: (f (g (h options))), just like in the comp function.

Example of a middleware

Our middleware will draw the current frame rate in the top left corner of the screen. Here is the middleware:

(ns middleware-example 
  (:require [quil.core :as q]))

(defn show-frame-rate [options]
  (let [; retrieve existing draw function or use empty one if not present
        draw (:draw options (fn []))
        ; updated-draw will replace draw
        updated-draw (fn []
                       (draw) ; call user-provided draw function
                       (q/fill 0)
                       (q/text-num (q/current-frame-rate) 10 10))]
    ; set updated-draw as :draw function
    (assoc options :draw updated-draw)))

(defn setup []
  (q/frame-rate 30)
  (q/color-mode :hsb))

; draw ellipse of random size and random color
(defn draw []
  (q/background 240)
  (let [period 100
        cur (mod (q/frame-count) period)
        angle (q/map-range cur
                           0 period
                           0 q/PI)]
    (q/fill (q/map-range cur 0 period 0 255) 255 255)
    (q/ellipse 100 100
               (* 150 (q/sin angle))
               (* 150 (q/cos angle)))))

(q/defsketch my-sketch
  :size [200 200]
  :setup setup
  :draw draw
  :middleware [show-frame-rate])

And the result:
Note: This middleware is not ideal and it can be improved. For example, it overrides fill value when it would be better if we store current fill and restore it back after we drew frame rate.

Ideas for middleware applications
  • middleware for creating gifs from sketch;
  • middleware for drag and zoom-in/zoom-out support: similar to how it is done in maps or mobiles;