{"id":13801049,"url":"https://github.com/pleasetrythisathome/bardo","last_synced_at":"2025-12-25T00:52:59.565Z","repository":{"id":16748407,"uuid":"19505990","full_name":"pleasetrythisathome/bardo","owner":"pleasetrythisathome","description":"A clojure(script) library to assist with transitions between dimensions","archived":false,"fork":false,"pushed_at":"2018-10-24T21:11:01.000Z","size":75,"stargazers_count":94,"open_issues_count":1,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-06T23:03:07.035Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pleasetrythisathome.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-05-06T18:35:48.000Z","updated_at":"2023-10-12T01:02:47.000Z","dependencies_parsed_at":"2022-09-06T02:10:51.903Z","dependency_job_id":null,"html_url":"https://github.com/pleasetrythisathome/bardo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pleasetrythisathome%2Fbardo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pleasetrythisathome%2Fbardo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pleasetrythisathome%2Fbardo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pleasetrythisathome%2Fbardo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pleasetrythisathome","download_url":"https://codeload.github.com/pleasetrythisathome/bardo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225198967,"owners_count":17437008,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:01:19.028Z","updated_at":"2025-12-25T00:52:59.475Z","avatar_url":"https://github.com/pleasetrythisathome.png","language":"Clojure","funding_links":[],"categories":["Awesome ClojureScript"],"sub_categories":["Miscellaneous"],"readme":"# bardo\n\nA clojure(script) library to assist with transitions between dimensions. Bardo defines semantics for represting interpolators between data and provides a suite of tools for manipulating them. \n\nMore eastern themed names! Really? But I have a good reason for this one, I promise! From [wikipedia](http://en.wikipedia.org/wiki/Bardo),\n\n```\nThe Tibetan word bardo (བར་དོ་ Wylie: bar do) means literally \"intermediate state\"\n—also translated as \"transitional state\" or \"in-between state\" or \"liminal state\".\n```\n\nGenerally, the term \"bardo\" represents the inbetween state between life and death, during which one's consciousness is not connected to the outside world. \n\n## Installation\n\nBardo is available in [clojars](https://clojars.org/bardo). Add this to your ```:dependencies``` vector.\n\n```clj\n[bardo \"0.1.2-SNAPSHOT\"]\n```\n\n```clj\n;; import vars used in feature examples below. available in both clojure and clojurescript\n(ns bardo.features\n  (require [bardo.ease :refer [wrap ease shift clamp]]\n           [bardo.interpolate :refer [interpolate into-lazy-seq mix blend chain pipeline]]\n           [bardo.transition :refer [transition]]\n```\n\n## What is an interpolator?\n\nBardo defines an interpolator as a higher order function that returns a single-arity function ```(fn [t])``` where ```t``` is a float ```(\u003c= 0 t 1)``` that produces a corresponding intermediate value.\n\nan interpolator between two numbers ```a``` and ```b``` can be defined as\n```clj\n(defn intrpl-nums [a b]\n  (fn [t]\n    (+ a (* t (- b a)))))\n    \n(def zero-\u003eten (intrpl-nums 0 10))\n(zero-\u003eten 0.5)\n;; =\u003e 5.0\n```\n\ninterpolators can be used to produce a sequence of values, or to produce an intermediate value at a point in time. We can produce sequences of values from an interpolator using normal clojure functions.\n\n```clj\n(mapv zero-\u003eten [0 0.5 1])\n;; =\u003e [0 5.0 10]\n```\n\nYou can produce lazy sequences using ```bardo.interpolate/into-lazy-seq```\n\n```clj\n(take 100 (interpolate/into-lazy-seq zero-\u003eten (iterate #(/ % 2) 1)))\n;; only 100 are computed\n```\n\n## Features\n\nBardo provides features for automatic and extensible interpolation between values of a variety of types. \n\n```clj\n(def times [0 0.5 1])\n\n;; primatives\n(map (interpolate 0 10) times)\n;; =\u003e (0 5.0 10)\n\n;; sequences\n(map (interpolate [0 1] [5 9]) times)\n;; =\u003e ([0 1] [2.5 5.0] [5 9])\n\n(map (interpolate {:a 0 :b 1} {:a 5 :b 0}) times)\n;; =\u003e ({:a 0, :b 1} {:b 0.5, :a 2.5} {:a 5, :b 0})\n\n;; different dimensions\n(map (interpolate [0] [5 9]) times)\n;; =\u003e ([0] [2.5 4.5] [5 9])\n(map (interpolate [0 nil] [5 9]) times)\n;; =\u003e ([0 0] [2.5 4.5] [5 9])\n\n(map (interpolate {:b 1} {:a 5}) times)\n;; =\u003e ({:b 1} {:b 0.5, :a 2.5} {:a 5})\n\n;; coerce sequence types\n(map (interpolate [1 2] (repeat 5)) times)\n;; =\u003e ([1 2] [3.0 3.5] [5 5])\n\n(map (interpolate (repeat 5) (repeat 5)) times)\n;; =\u003e java.lang.Exception: Cannot interpolate between two uncounted sequences\n\n;; throw errors if you can't interpolate\n(map (interpolate [1 2] {:a 5 :b 0}) times)\n;; =\u003e java.lang.Exception: Cannot interpolate between a seq and something else\n\n;; make lazy sequences if you want them\n(take 10 (into-lazy-seq (interpolate 0 10) (range 0 1 (/ 1 10000))))\n\n```\n\nCompose interpolators\n\n```clj\n(def times [0 0.25 0.5 0.75 1])\n\n;; interpolate between outputs\n(-\u003e (interpolate 0 5)\n    (mix (interpolate 0 10))\n    (map times))\n;; =\u003e (0 1.5625 3.75 6.5625 10)\n\n;; blend to new target\n(-\u003e (interpolate 0 5)\n    (blend 10)\n    (map times))\n;; =\u003e (0 3.4375 6.25 8.4375 10)\n\n;; chaining\n(-\u003e (interpolate 0 5)\n    (chain 20)\n    (map times))\n;; =\u003e (0.0 2.5 5.0 12.5 20.0)\n\n;; set midpoint\n(-\u003e (interpolate 0 5)\n    (chain 20 0.8)\n    (map times))\n;; =\u003e (0.0 1.5625 3.125 4.6875 20.0)\n\n;; pipeline\n(-\u003e (pipeline [0 10 50 3000])\n    (map times))\n;; =\u003e (0.0 7.5 30.0 787.4999999999993 3000.0)\n\n;; set input steps\n(-\u003e (pipeline [0 10 50 3000] [0 0.1 0.9 1])\n    (map times))\n;; =\u003e (0.0 17.5 30.0 42.5 3000.0)\n\n```\n\nCombine with easing functions\n\n```clj\n(def times (concat (range 0 1 (/ 1 20)) [1]))\n(defn sig [n]\n  (fn [x]\n    (-\u003e x\n        (* (Math/pow 10 n))\n        Math/round\n        (/ (Math/pow 10 n)))))\n\n(-\u003e (interpolate 0 5)\n    (wrap (ease :cubic-in-out))\n    (map times)\n    (-\u003e\u003e (map (sig 2))))\n;; =\u003e (0.0 0.0 0.02 0.07 0.16 0.31 0.54 0.86 1.28 1.82 2.5 3.18 3.72 4.14 4.46 4.69 4.84 4.93 4.98 5.0 5.0)\n\n(-\u003e (interpolate 0 5)\n    (clamp)\n    (shift 0.5 1)\n    (map times)\n    (-\u003e\u003e (map (sig 2))))\n;; =\u003e (0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0)\n\n```\n\nOutput values over time\n\n```clj\n(transition 0 5 {:duration 1000 :easing :cubic-in-out})\n;; =\u003e channel onto which values are placed that closes 1000ms later.\n;; resolution is 60 values/second by default\n```\n\n## Easing\n\nBardo defines an easing function as a single-arity function ```(fn [t] (f t))``` where f produces a new value t. Easing functions are most commonly used to provide different curves to time values, but can be used to produce a varity of effects.\n\n```clj\n(defn faster [t]\n  (+ 0.1 t))\n(faster 0)\n;; =\u003e 0.1\n\n;; we can also write this as a higher order function\n(defn easer [f]\n  (fn [t]\n    (f t)))\n(def faster (easer (partial + 0.1)))\n(faster 0)\n;; =\u003e 0.1\n       \n```\n\nEasing functions can also be used to define or change input boundaries. ```clamp``` and ```shift``` can be found in ```bardo.ease```\n\n```clj\n(defn clamp\n  [f]\n  (fn [t]\n    (f (cond\n        (\u003c t 0) 0\n        (\u003e t 1) 1\n        :else t))))\n\n(def not-too-fast (easer (clamp #(/ % 2))))\n(not-too-fast 1)\n;; =\u003e 1/2\n(not-too-fast 1.5)\n;; =\u003e 1/2\n \n(defn shift\n  \"shifts the domain of input from [cmin cmax] to [nmin nmax]\"\n  ([f cmin cmax] (shift f cmin cmax 0 1))\n  ([f cmin cmax nmin nmax]\n     (fn [t]\n       (f (-\u003e t\n              (- cmin)\n              (/ (- cmax cmin))\n              (* (- nmax nmin))\n              (+ nmin))))))\n              \n(def percent (shift slower 0 100))\n(percent 50)\n;; =\u003e 1/4\n```\n\nBardo provides a higher level api for creating functions for common easing curves in ```bardo.ease/ease```. All of the [standard easing functions](http://easings.net/) are provided in skewer case (ie. ```clj \"cubicInOut\" -\u003e :cubic-in-out```)\n\n```clj\n(def cubic (ease/ease :cubic-in-out))\n(mapv cubic (range 0 1 (/ 1 10)))\n;; =\u003e [0.0 0.004 0.032 0.108 0.256 0.5 0.744 0.892 0.968 0.996]\n```\n\n## Interpolation Protocol Extension\n\nBardo can automatically create interpolation functions from data. Bardo supports sequences, hashmaps, and numbers out of the box, but can be extended to support any clojure value. Interpolateable types satisfy:\n\n```clj\n;; perform interpolation\n(defprotocol IInterpolate\n  (-interpolate [start end]))\n\n;; return \"fresh\" value in case of nil or nonexistent\n(defprotocol IFresh\n  (fresh [x]))\n```\n\n```bardo.interpolate/interpolate``` provides an entry point that wraps nil values, checks for type compatibility, and wraps differently shaped data. ```interpolate``` should be used instead of ```-interpolate``` unless you want to bypass these wrapping mechanisms.\n\nHere's an example of extending bardo to interpolate between garden colors. \n\n```clj\n(ns garden\n  (:require [bardo.interpolate :refer [IFresh IInterpolate -interpolate interpolate]]\n            [garden.color :as color]))\n\n(extend-protocol IFresh\n  garden.color.CSSColor\n  (fresh [s]\n    (color/rgb 255 255 255)))\n\n(extend-protocol IInterpolate\n  garden.color.CSSColor\n  (-interpolate [start end]\n    (let [[start end] (map color/as-rgb [start end])]\n      (fn [t]\n        (color/color+ start (color/color* t (color/color- end start)))))))\n\n(-\u003e (interpolate (color/hsl 10 50 50) (color/rgb 0 255 0))\n    (map [0 0.25 0.5 0.75 1])\n    clojure.pprint/pprint)\n;; =\u003e\n;; ({:alpha nil,\n;;   :lightness nil,\n;;   :saturation nil,\n;;   :hue nil,\n;;   :blue 64,\n;;   :green 85,\n;;   :red 191}\n;;  {:red 191.0,\n;;   :green 127.5,\n;;   :blue 64.0,\n;;   :hue nil,\n;;   :saturation nil,\n;;   :lightness nil,\n;;   :alpha nil}\n;;  {:red 191.0,\n;;   :green 170.0,\n;;   :blue 64.0,\n;;   :hue nil,\n;;   :saturation nil,\n;;   :lightness nil,\n;;   :alpha nil}\n;;  {:red 191.0,\n;;   :green 212.5,\n;;   :blue 64.0,\n;;   :hue nil,\n;;   :saturation nil,\n;;   :lightness nil,\n;;   :alpha nil}\n;;  {:alpha nil,\n;;   :lightness nil,\n;;   :saturation nil,\n;;   :hue nil,\n;;   :blue 64,\n;;   :green 255,\n;;   :red 191})\n```                  \n\n## Examples and Development\n\nI've been using the [boot](https://github.com/boot-clj/boot) build tool, it's great. To build bardo from source, install boot, and run ```boot development``` to get a full development setup complete with file server, cljx, cljs-repl, and js reloading. \n\n## Graphics Integration\n\nBardo is well suited for integration into graphical context like [Om](https://github.com/swannodette/om) (or [Reagent](http://holmsand.github.io/reagent/), [Quil](https://github.com/quil/quil), [libGDX](https://github.com/oakes/play-clj), etc. etc.). \n\nA simple Om example using the transition helper.\n```clj\n(defn mover\n  [{:keys [x y]} owner]\n  (reify\n    om/IInitState\n    (init-state [_]\n      {:x x\n       :y y})\n    om/IWillReceiveProps\n    (will-receive-props [_ {:keys [x y]}]\n      (let [[px py] ((juxt :x :y) (om/get-props owner))\n            intrpl-ch (transition {:x px :y py} {:x x :y y} {:duration 1000})]\n        (go-loop []\n          (when-let [{:keys [x y]} (\u003c! intrpl-ch)]\n            (om/set-state! owner :x x)\n            (om/set-state! owner :y y)\n            (recur)))))\n    om/IRenderState\n    (render-state [_ {:keys [x y]}]\n      (html\n       [:div\n        {:style {:position \"fixed\"\n                 :top y\n                 :left x}}\n        [:div\n         \"Location\"]\n        [:div\n         (str \"x: \" (int x))]\n        [:div\n         (str \"y: \" (int y))]]))))\n```\n\nMixes between interpolators that represent overlapping time domains can be mixed by shifting the domains of the interpolators. \n\n```clj\n(def a 0)\n(def b 10)\n(def intrpl (interpolate a b))\n(map intrpl [0 0.5 1])\n;; =\u003e (0 5.0 10)\n;; =\u003e (fn [t]) : t [0 -\u003e 1] : a -\u003e b\n\n;; interrupt at dt and interpolate to c\n(def dt 0.6)\n(def c 50)\n(def dintrpl (interpolate (intrpl dt) c))\n(map dintrpl [0 0.5 1])\n;; =\u003e (6.0 28.0 50.0)\n;; (fn [t]) : t [0 -\u003e 1] : (intrpl dt) -\u003e c\n\n;; to mix, we need to shift the domain of the input to intrpl\n(def sintrpl (ease/shift intrpl 0 (- 1 dt) dt 1))\n(map sintrpl [0 (- 1 dt) 1])\n;; =\u003e (6.0 10.0 16.0)\n;; we get a higher output at 1 because we've extended the domain\n;; (fn [t]) ; t [0 -\u003e (- 1 dt)] : (intrpl dt) -\u003e b\n(-\u003e identity\n    (ease/shift 0 (- 1 dt) dt 1)\n    (map [0 (- 1 dt) 1]))\n;; =\u003e (0.6 1.0 1.6)\n\n(def mixed (mix sintrpl dintrpl))\n(map mixed [0 0.25 0.5 0.75 1])\n;; =\u003e (6.0 10.625 19.5 32.625 50.0)\n```\n\nA full om example is [here](https://github.com/pleasetrythisathome/bardo/blob/master/examples/om.cljs). More examples coming soon...\n\n## Disclaimer\n\nBardo is very much alpha software. It's been used in production in some form, but is still under active development. The API is subject to change. Thoughts, comments, feature, and pull requests welcome.\n\n## License\n\nCopyright © 2014 Dylan Butman\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpleasetrythisathome%2Fbardo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpleasetrythisathome%2Fbardo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpleasetrythisathome%2Fbardo/lists"}