20200208 quil sketch

Draft of 2020.02.08

May include: programmingClojurequil&c.

This is a new variant on the one from yesterday.

Changes include:

  • I’ve compiled in :navigation-2d, meaning “scroll wheel” (and touch-based equivalent gestures) should change the sketch’s scale incrementally, and mouse-drag (including scrolling drags on many mobile browsers!) will move the center point. I haven’t added anything to reset the position and scale, so just reload if that is desired. In last-minute testing, I notice that by the time I’ve read this text and scrolled down to the sketch in the browser window, it looks more like an 80s graphic design with the little rotating colored squares showing because it’s zoomed out so far….
  • I’ve done a major refactoring (“major” is subjective, because I didn’t quite understand what I was doing), by constructing the three rotating “layers” once, in off-screen svg images, and reduced the animation to dropping them onto the canvas with a given relative rotation. As a result, a lot less heat is generated (at least in my browser) because the individual ellipses aren’t all being calculated over again in each frame.
  • I’ve added a bit of jitter to the positions of the ellipses in each layer, adding a bit of aesthetic “organicity” as I see it. I’ve also made the rotation much less smooth, by using a random small increment in each layer.

In any case:


I notice, having moved the sketch from my dev environment here to the blog, that any scrolling of the web page is passed down into the sketch, resulting in rescaling as you’re reading the text above. I like that kind of bug as an unexpected “resistance” from the deployment environment, and I’ll see if I can address it in the next iteration. In the meantime, you can reload the page once you get down to the sketch if it looks weird.

There were also, I noticed, a few strange accommodations I was driven to make in extracting the create-lattice function, since quil apparently leaves a lot of tacit global state sitting around when one writes and invokes a function like q/color. I had intended to def the lattice definitions, but as a quick fix I fell back to defn just to avoid the namespace shenanigans while I was making this version work. I may revisit that, since there’s clearly a good deal of refactoring I could do to improve this and avoid such junk.

That’s it. That’s all it does, for now.


(ns negative-space-quil.core
  (:require [quil.core :as q :include-macros true]
            [quil.middleware :as m]

(defn create-lattice
  [lattice-def edge]
  (let [w (:width lattice-def)
        h (:height lattice-def)
        r (:radius lattice-def)
        c (:color lattice-def)
        scale-x (* 1.5 (/ edge w))
        scale-y (* 1.5 (/ edge h))
        gr (q/create-graphics (* w scale-x) (* h scale-y))
    (q/with-graphics gr
        (q/fill c)
        (doseq [x (range (- scale-x) scale-x)
                y (range (- scale-y) scale-y)]
          (q/ellipse (+ -1 (* x w) (rand 2))
                     (+ -1 (* y h) (rand 2))
                     (+ (/ x 7) r) (+ (/ x 7) r))

(defn m-def
  { :width 7
    :height 7
    :color (q/color 214 200 255 255)
    :radius 2

(defn c-def
  { :width 6
    :height 6
    :color (q/color 128 230 255 128)
    :radius 2

(defn y-def
  { :width 6
    :height 6
    :color (q/color 44 100 255 64)
    :radius 2

(defn setup []
  (q/frame-rate 100)
  (q/color-mode :hsb)
  (q/blend-mode :blend)
  (q/ellipse-mode :radius)
  (q/image-mode :center)
  {:m-lattice (create-lattice (m-def) (q/width))
    :m-angle (rand-int 100)
    :c-lattice (create-lattice (c-def) (q/width))
    :c-angle (rand-int 100)
    :y-lattice (create-lattice (y-def) (q/width))
    :y-angle (rand-int 100)

(defn update-state [state]
  (-> state
    (update , :m-angle #(+ % (/ (rand) 1000)))
    (update , :c-angle #(+ % (/ (rand) -1000)))
    (update , :y-angle #(+ % (/ (rand) 1000)))

(defn draw-state [state]
  (let [magenta (:m-lattice state)
        cyan (:c-lattice state)
        yellow (:y-lattice state)
    (q/background 255)
    (q/with-translation [(/ (q/width) 2) (/ (q/height) 2)]
      (q/with-rotation [(:m-angle state)]
        (q/image magenta 0 0)
      (q/with-rotation [(:c-angle state)]
        (q/image cyan 0 0)
      (q/with-rotation [(:y-angle state)]
        (q/image yellow 0 0)

; this function is called in index.html
(defn ^:export run-sketch []
  (q/defsketch negative-space-quil
    :host "20200208-quil"
    :size [400 400]
    :setup setup
    :update update-state
    :draw draw-state
    :middleware [m/fun-mode m/navigation-2d]

; uncomment this line to reset the sketch:
; (run-sketch)