Skip to content

Instantly share code, notes, and snippets.

@leonoel
Created October 8, 2023 13:16
Show Gist options
  • Save leonoel/05d46a2fabda0de49063b6faba69866d to your computer and use it in GitHub Desktop.
Save leonoel/05d46a2fabda0de49063b6faba69866d to your computer and use it in GitHub Desktop.
animation in missionary
(ns animation
(:refer-clojure :exclude [cycle])
(:require [missionary.core :as m]))
;; A signal giving the current time in milliseconds.
;; On the browser, you may want to use an RAF-based clock instead.
(def <time
(->> (m/ap
(loop []
(m/amb nil
(do (m/? (m/sleep 10))
(recur)))))
(m/sample (fn [_] (System/currentTimeMillis)))
(m/signal)))
;; A helper to define a feedback loop.
(defmacro cycle [[s i] & body]
`(let [a# (atom ~i)
~s (m/?< (m/watch a#))]
(reset! a# (do ~@body))))
;; eps : error threshold
;; dt : sampling interval
;; k : proportional correction
;; init : initial value
;; <set-point : current set point value as a continuous flow
(defn pid [eps dt k init <set-point]
(m/cp
((cycle [[x t] [init nil]]
(let [sp (m/?< <set-point)
err (- sp x)]
(if (< (- eps) err eps)
[sp nil]
(if (nil? t)
[x (m/?< <time)]
(if (< t (m/?< <time))
[(+ x (* err dt k)) (+ t dt)]
[x t]))))) 0)))
;; ease : easing function transforming floating point in interval (0 < x < 1)
;; duration : time to reach a new set-point
;; init : initial value
;; <set-point : current set point value as a continuous flow
(defn transition [ease duration init <set-point]
(m/cp
((cycle [[curr anim] [init nil]]
(let [set-point (m/?< <set-point)]
(if-some [[started origin target] anim]
(if (= set-point target)
(let [age (- (m/?< <time) started)]
(if (< age duration)
[(+ origin (* (ease (/ age duration)) (- target origin))) anim]
[target nil]))
[curr [(m/?< <time) curr set-point]])
(if (= set-point curr)
[curr nil]
[curr [(m/?< <time) curr set-point]])))) 0)))
(defn ease-in-out-sine ^double [^double x]
(/ (- 1 (Math/cos (* x Math/PI))) 2))
(comment
(def !set-point (atom 0))
(def ps
(let [<input (m/signal (m/watch !set-point))]
((m/reduce (fn [_ x] (apply prn x)) nil
(m/signal (m/latest vector
(pid 0.2 1 0.005 0 <input)
(transition ease-in-out-sine 1000 0 <input))))
prn prn)))
(swap! !set-point + 10)
(ps)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment