 ;; have unsightly gaps.
 
 ;; some snippets based on mikea's code.  modified from telegenic so I
-;; could use ffmpeg.
-(def DEFAULT-OPTIONS
-  {:filename "art/a%03d.png"
-   :width (* (/ 1080 10) 3)
-   :height (* (/ 1920 10) 3)})
-
+;; could use ffmpeg.  also modified to allow for parallel runs on different
+;; systems
 (defmacro render-animation
-  "Macro to render a sequence of frames, looping with a symbolic frame counter."
-  ([[key frame-count] src]
-    `(render-animation [~key ~frame-count] ~src))
-  ([[key frame-count] src options]
+  "Macro to render a sequence of frames, looping with a symbolic frame counter.
+   Example: (render-animation [i 10] (offset [(* i 10) 0.0 0.0] (vnoise)))"
+  ([[key frame-end] src options]
+   `(render-animation [~key 0 ~frame-end 1] ~src))
+  ([[key frame-start frame-end] src options]
+   `(render-animation [~key ~frame-start ~frame-end 1] ~src))
+  ([[key frame-start frame-end frame-step] src options]
     (when-not (symbol? key) (error "render-animation needs a symbol binding for the frame number"))
-    (when-not (integer? frame-count) (error "render-animation needs an integer number of frames"))
-    `(let [mopts# (merge DEFAULT-OPTIONS ~options)
-           opts#  (mapcat identity mopts#)]
-       (doseq [~key (range ~frame-count)]    ;; loop over all frames, lazily (doseq for mem?)
+    `(let [opts#  (mapcat identity options#)]
+       (doseq [~key (range ~frame-start ~frame-end ~frame-step)] ;; loop over all frames, lazily. don't hold memory
          (let [im# (apply image ~src opts#)  ;; create the frame
-               fn# (format (:filename mopts#) ~key)]
+               fn# (format (:filename options#) ~key)]
            (apply show im# opts#)            ;; show the latest frame
            (ImageIO/write im# "png" (File. fn#))))))) ;; write the frame
 

  (:require [tweegeemee.core :as tgm]))

;; working towards http://zine.electricobjects.com/artist-program
;; Still Images
;;
;; 1080px x 1920 pixels

  (->> fn
       (scale  [(/ 16 9) (/ 16 9)])))

;; easing-like functions.  use on the key to create a scalar per frame
(def circle-cos [i max-range steps]
  (* max-range (Math/cos (* 2 Math/PI (/ i steps)))))
(def circle-sin [i max-range steps]
  (* max-range (Math/sin (* 2 Math/PI (/ i steps)))))
(def half-circle-cos [i max-range steps]
  (* max-range (Math/cos (* Math/PI (/ i steps)))))
(def half-circle-sin [i max-range steps]
  (* max-range (Math/sin (* Math/PI (/ i steps)))))

;; ======================================================================
;; Animation creation code
(comment

  ;; ======================================================================
  ;; opus1a - pastel dream
  ;; SAVE THIS -- really nice loop.
  (render-animation
   [i 3390] ;; 113 seconds
   (scale-for-vert-hd
    (vpow
     (length plasma)
     (sigmoid
      (gradient
       (green-from-hsl
        (green-from-hsl
         (rgb-from-hsl
          (v+ (offset [(circle-cos i 0.15 3390)
                       0.0
                       (circle-sin i 0.15 3390)]
                      pos)
              (blue-from-hsl [0.6035 -2.8447 0.9631]))))))))))
  {:filename "art/opus1a/a%04d.png"
   :width    (* (/ 1080 10) 3)
   :height   (* (/ 1920 10) 3)})

  ;; ======================================================================
  ;; fun noise opus1b
  ;; this is pretty good but not my favorite -- took 5.5 hours for 480 frames on MacBook Pro
  (render-animation
   [i 480]
