threeagent is a ClojureScript library for building reactive, three.js applications in a Reagent-like fashion.
Include the threeagent library in your project:
threeagent depends on three.js, so it will need to be added as a dependency to your project as well.
For shadow-cljs, install three.js using npm:
npm install --save three
For lein-cljsbuild, add an npm-deps entry for three.js:
:cljsbuild {:builds [{...
:compiler {...
:install-deps true
:npm-deps {:three "0.100.0"}}}]}
(ns my-app.core
(:require [threeagent.alpha.core :as th]))
;; Use reactive atom for storing state
(defonce state (th/atom {:ticks 0}))
;; Tick every second
(.setInterval js/window #(swap! state update :ticks inc) 1000)
;; Form-1 component example
(defn color-box [color size]
[:box {:width size
:height size
:depth size
:material {:color color}])
;; Form-2 component example
(defn growing-sphere []
(let [s (atom 0)]
(.setInterval js/window #(swap! s inc) 5000)
(fn []
[:sphere {:radius @s}])))
;; Root component render function
(defn root []
[:object {:position [1.0 0 -4.0]
:rotation [0 (js/Math.sin (:ticks @state)) 0]}
[color-box "red" 1.0] ; Don't forget to use square brackets!
[growing-sphere]])
;; Initialize and begin rendering threeagent scene
(defn init []
(th/render root (.getElementById js/document "my-canvas")))
(defn ^:dev/after-reload on-code-reload [] ;; For hot-code reloading, just call the render function again
(th/render root (.getElementById js/document "my-canvas")))
In threeagent, you use a hiccup-like syntax for defining the components of your scene. A component is defined by a vector with 3 parts:
:box
:sphere
or :object
:position
:rotation
and :scale
, but other properties can also be defined based on the component type. For instance the :circle
component expects a :radius
property to be defined.Here's an example:
[:object {:position [0 1.0 0]
:scale [1.0 2.0 1.0]}
[:box {:position [2.0 0 0]
:width 2.0}]
[:box {:position [2.0 0 0]
:scale [2.0 1.0 0.5]
:width 3.0}]]
The threeagent.core/render
function is used to initialize threeagent and start the rendering loop.
For example:
(defn root []
[:object
[:ambient-light {:intensity 0.8}]
[:box {:position [0 0 -10]}]])
(defn on-page-load []
(threeagent/render root (.getElementById js/document "my-canvas")))
Just like reagent, threeagent allows you to break your scene down into reusable functions.
For example, if we wanted to define a reusable component to represent a row of boxes, we would define a function like this:
(defn row-of-boxes [count color]
[:object
(for [i (range count)]
[:box {:position [i 0 0]
:material {:color color}}])])
To use a component function, you simply reference the function from another component:
(defn root []
[:object
[:object {:position [0 1 0]}
[row-of-boxes 5 "red"]]
[:object {:position [0 2 0]}
[row-of-boxes 8 "blue"]]])
Remember to use the square brackets instead of invoking the function directly!
While threeagent provides a number of built-in components such as :box
:object
or :sphere
, you will eventually want to define your own components.
Using the defcomponent
macro you can define your own components which you can use to generate new three.js objects.
The defcomponent
macro is used to build a function that will receive the component property and return an instance of a three.js object.
For example, if we wanted the ability to place custom 3D models in our scene, we could define our own :model
component:
(ns example.core
(:require-macros [threeagent.alpha.macros :refer [defcomponent]]))
(defcomponent :model [config]
(let [type (:model-type config)
mesh (fetch-mesh-of-type type)]
mesh))
We could then use this custom component in our scene:
(defn root []
[:object
[:model {:model-type "teapot"}]])
For more examples, you can check out how threeagent defines the default components
threeagent's atom
function actually just returns a reagent reactive atom. This allows you to share your state atoms between reagent and threeagent, meaning you don't need to manually synchronize your reagent-managed user interface and your threeagent-managed 3D scene.
threeagent provides a number of components out-of-the-box, allowing you to quickly get started building 3D scenes.
:object
Properties: :position
:rotation
:scale
Corresponds to the Object3D class from three.js
:box
Properties: :width
:height
:depth
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close