Skip to content

Instantly share code, notes, and snippets.

@ChillyBwoy
Created May 22, 2014 23:54
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ChillyBwoy/38741e0005826fc84e9e to your computer and use it in GitHub Desktop.
Save ChillyBwoy/38741e0005826fc84e9e to your computer and use it in GitHub Desktop.
Simple particles in ClojureScript
(ns particles.core)
(def display (.getElementById js/document "display"))
(def context (.getContext display "2d"))
(def damping 0.999)
(def max-particles 250)
(def line-width 2)
(def app-state (atom {:width (.-innerWidth js/window)
:height (.-innerHeight js/window)}))
(defn init-canvas
[]
(let [{:keys [width height]} @app-state]
(do
(set! (.-width display) width))
(set! (.-height display) height)))
(defn rand-rgb
[]
(let [r (rand-int 255)
g (rand-int 255)
b (rand-int 255)]
(str "rgb(" r "," g "," b ")")))
(defn create-particle
[]
(let [width (:width @app-state)
height (:height @app-state)
x (rand width)
y (rand height)
color (rand-rgb)]
{:x x, :y y, :old-x x, :old-y y, :color color}))
(swap! app-state assoc :mouse {:x (* (:width @app-state) 0.5)
:y (* (:height @app-state) 0.5)})
(swap! app-state assoc :particles (vec (map create-particle (range max-particles))))
(defn integrate
[{:keys [x y old-x old-y] :as particle}]
(let [velocity-x (* (- x old-x) damping)
velocity-y (* (- y old-y) damping)]
(assoc particle :x (+ x velocity-x)
:y (+ y velocity-y)
:old-x x
:old-y y)))
(defn attract
[pos-x pos-y {:keys [x y] :as particle}]
(let [dx (- pos-x x)
dy (- pos-y y)
distance (.sqrt js/Math (+ (* dx dx) (* dy dy)))
new-x (+ x (/ dx distance))
new-y (+ y (/ dy distance))]
(assoc particle :x new-x :y new-y)))
(defn draw
[ctx {:keys [x y old-x old-y color]}]
(do
(set! (.-strokeStyle ctx) color)
(set! (.-lineWidth ctx) line-width)
(.beginPath ctx)
(.moveTo ctx old-x old-y)
(.lineTo ctx x y)
(.stroke ctx)))
(defn render
[]
(.requestAnimationFrame js/window render)
(let [{:keys [width height particles mouse]} @app-state]
(.clearRect context 0 0 width height)
(dotimes [n max-particles]
(let [particle (nth particles n)
x (:x mouse)
y (:y mouse)
p (integrate (attract x y particle))]
(draw context p)
(swap! app-state assoc-in [:particles n] p)))))
(defn mousemove-handler
[event]
(swap! app-state assoc :mouse {:x (.-clientX event)
:y (.-clientY event)}))
(defn windowresize-handler
[event]
(let [w (.-innerWidth js/window)
h (.-innerHeight js/window)]
(do
(swap! app-state assoc :width w)
(swap! app-state assoc :height h)
(init-canvas))))
(.addEventListener display "mousemove" mousemove-handler)
(.addEventListener js/window "resize" windowresize-handler)
(init-canvas)
(render)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Particles</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<canvas id="display"></canvas>
<script src="js/app.js"></script>
</body>
</html>
(defproject particles "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:source-paths ["src/clj" "src/cljs"]
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2197"]]
:plugins [[lein-cljsbuild "1.0.3"]]
:cljsbuild {:builds
[{
:source-paths ["src/cljs"]
:compiler {
:output-to "resources/public/js/app.js"
:optimizations :whitespace
:pretty-print true}}]})
html, body {
background-color: #000;
margin: 0;
padding: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment