Created
October 8, 2023 13:16
-
-
Save leonoel/05d46a2fabda0de49063b6faba69866d to your computer and use it in GitHub Desktop.
animation in missionary
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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