├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── LICENSE
├── README.org
├── package-lock.json
├── package.json
├── public
├── data
│ ├── faust_kurz.txt
│ └── pride_and_prejudice.txt
├── fonts
│ └── miso-bold.ttf
├── images
│ ├── 00.svg
│ ├── 01.svg
│ ├── 02.svg
│ ├── 03.svg
│ ├── 04.svg
│ ├── 05.svg
│ ├── 06.svg
│ ├── 07.svg
│ ├── 08.svg
│ ├── 09.svg
│ ├── 10.svg
│ ├── 11.svg
│ ├── 12.svg
│ ├── 13.svg
│ ├── 14.svg
│ ├── 15.svg
│ ├── comma.svg
│ ├── dynamic-brush.svg
│ ├── emacs.png
│ ├── exclamationmark.svg
│ ├── fcb.jpg
│ ├── period.svg
│ ├── questionmark.svg
│ ├── return.svg
│ ├── shape.jpg
│ ├── sojka.jpg
│ ├── space.svg
│ ├── space2.svg
│ ├── texture-white.png
│ └── texture.png
└── index.html
├── shadow-cljs.edn
└── src
├── js
└── index.js
└── sketches
├── components.cljs
├── core.clj
├── core.cljs
├── creative_coding
├── core.cljs
├── print_art.cljs
└── webgl.cljs
├── generative_artistry
├── circle_packing.cljs
├── core.cljs
├── cubic_disarray.cljs
├── hypnotic_squares.cljs
├── joy_division.cljs
├── piet_mondarin.cljs
├── tiled_lines.cljs
├── triangular_mesh.cljs
└── un_deux_trois.cljs
├── generative_desgin
├── P_01
│ ├── P_1_0_01.cljs
│ ├── P_1_1_1_01.cljs
│ ├── P_1_1_2_01.cljs
│ ├── P_1_2_1_01.cljs
│ └── P_1_2_3_01.cljs
├── P_02
│ ├── P_2_0_01.cljs
│ ├── P_2_1_1_01.cljs
│ ├── P_2_1_2_01.cljs
│ ├── P_2_1_3_01.cljs
│ ├── P_2_1_4_01.cljs
│ ├── P_2_1_5_01.cljs
│ ├── P_2_2_1_01.cljs
│ ├── P_2_2_3_01.cljs
│ ├── P_2_2_4_01.cljs
│ ├── P_2_2_5_01.cljs
│ ├── P_2_2_6_01.cljs
│ ├── P_2_3_1_01.cljs
│ ├── P_2_3_3_01.cljs
│ ├── P_2_3_4_01.cljs
│ ├── P_2_3_6_01.cljs
│ └── P_2_3_7_01.cljs
├── P_03
│ ├── P_3_0_01.cljs
│ ├── P_3_1_2_01.cljs
│ ├── P_3_1_3_01.cljs
│ └── P_3_1_4_01.cljs
└── core.cljs
├── icons.cljs
├── mover.cljs
├── nature_of_code
├── cellular_automata
│ ├── core.cljs
│ ├── game_of_life.cljs
│ └── random_cellular_automaton.cljs
├── core.cljs
├── forces
│ ├── balloon.cljs
│ ├── core.cljs
│ ├── fluid.cljs
│ ├── force_push.cljs
│ ├── frictions.cljs
│ ├── invisible_attractors.cljs
│ ├── lift_induced_drag.cljs
│ ├── own_force.cljs
│ ├── repulse_mouse.cljs
│ └── surface_area.cljs
├── fractals
│ ├── core.cljs
│ ├── koch_curve.cljs
│ ├── own_cantor.cljs
│ └── sierpinski.cljs
├── introduction
│ ├── core.cljs
│ ├── noise_animate.cljs
│ ├── noise_detail.cljs
│ ├── noise_terrain.cljs
│ ├── paint_splatter.cljs
│ ├── random_walk.cljs
│ ├── random_walk_custom_step.cljs
│ ├── random_walk_dynamic.cljs
│ ├── random_walk_gaussian.cljs
│ └── random_walk_noise.cljs
├── oscillation
│ ├── angular_oscilliate.cljs
│ ├── asteroids.cljs
│ ├── bob.cljs
│ ├── cannon.cljs
│ ├── combined_wave.cljs
│ ├── core.cljs
│ ├── custom_waves.cljs
│ ├── insect.cljs
│ ├── multi_pendulum.cljs
│ ├── multi_springs.cljs
│ ├── perlin_wave.cljs
│ ├── rotate_baton.cljs
│ ├── spiral.cljs
│ └── vehicle.cljs
├── particle_systems
│ ├── asteroids_with_particles.cljs
│ ├── core.cljs
│ ├── dynamic_origin.cljs
│ ├── fire.cljs
│ ├── fire_blend.cljs
│ ├── fire_rainbow.cljs
│ ├── mixed_particles.cljs
│ ├── particle_force.cljs
│ ├── particles_on_click.cljs
│ ├── particles_repel.cljs
│ ├── particles_with_images.cljs
│ ├── particles_with_repellers.cljs
│ ├── rotating_particle.cljs
│ └── shutter_in_pieces.cljs
├── physics_library
│ ├── box_shapes.cljs
│ ├── circular_shapes.cljs
│ ├── core.cljs
│ └── matter.cljs
└── vectors
│ ├── bouncing_ball.cljs
│ ├── car.cljs
│ ├── core.cljs
│ ├── mouse_acceleration.cljs
│ └── noise_car.cljs
├── plotting
├── eye_of_sine.clj
└── tricles.clj
├── rac_sketches
├── core.cljs
├── fire_ball.cljs
├── fire_texture.cljs
├── flowers.cljs
├── heart_of_clojure.cljs
├── inferno.cljs
├── noise_colors.cljs
├── particle_party.cljs
├── rainbow_circles.cljs
├── reverse_roots.cljs
├── rotating_angles.cljs
└── text_snake.cljs
└── vector.cljc
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI/CD
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Clojure install
13 | run: |
14 | curl -O https://download.clojure.org/install/linux-install-1.10.1.469.sh
15 | chmod +x linux-install-1.10.1.469.sh
16 | sudo ./linux-install-1.10.1.469.sh
17 | - name: Use Node.js
18 | uses: actions/setup-node@v1
19 | - name: npm install
20 | run: npm install
21 | - name: Build JS
22 | run: npx shadow-cljs release app
23 | - name: Deploy 🚀
24 | uses: JamesIves/github-pages-deploy-action@v4
25 | with:
26 | folder: public
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .cpcache/
2 | /.nrepl-port
3 | target/
4 | node_modules/
5 | dist/
6 | /.clj-kondo/
7 | /.lsp/
8 | /.shadow-cljs/
9 | /public/js/
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Thomas Sojka
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | * Sketches by [[https://twitter.com/rollacaster][@rollacaster]]
2 | Various sketches created to learn more about creative visual programming.
3 |
4 | https://rollacaster.github.io/sketches/
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sketches",
3 | "version": "1.0.0",
4 | "description": "Various sketches I create to learn more about create visual programming.",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/rollacaster/sketches.git"
13 | },
14 | "keywords": [],
15 | "author": "Thomas Sojka",
16 | "license": "MIT",
17 | "bugs": {
18 | "url": "https://github.com/rollacaster/sketches/issues"
19 | },
20 | "homepage": "https://rollacaster.github.io/sketches/",
21 | "dependencies": {
22 | "bezier-easing": "^2.1.0",
23 | "matter-js": "^0.14.2",
24 | "nice-color-palettes": "^3.0.0",
25 | "p5": "^1.4.2",
26 | "react": "^18.2.0",
27 | "react-dom": "^18.2.0"
28 | },
29 | "devDependencies": {
30 | "shadow-cljs": "^2.20.2",
31 | "webpack": "^4.39.3",
32 | "webpack-cli": "^3.3.12"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/data/faust_kurz.txt:
--------------------------------------------------------------------------------
1 | Ihr naht euch wieder, schwankende Gestalten,
2 | Die früh sich einst dem trüben Blick gezeigt.
3 | Versuch ich wohl, euch diesmal festzuhalten?
4 | Fühl ich mein Herz noch jenem Wahn geneigt?
5 | Ihr drängt euch zu! nun gut, so mögt ihr walten,
6 | Wie ihr aus Dunst und Nebel um mich steigt;
7 | Mein Busen fühlt sich jugendlich erschüttert
8 | Vom Zauberhauch, der euren Zug umwittert.
9 |
10 | Ihr bringt mit euch die Bilder froher Tage,
11 | Und manche liebe Schatten steigen auf;
12 | Gleich einer alten, halbverklungnen Sage
13 | Kommt erste Lieb und Freundschaft mit herauf;
14 | Der Schmerz wird neu, es wiederholt die Klage
15 | Des Lebens labyrinthisch irren Lauf,
16 | Und nennt die Guten, die, um schöne Stunden
17 | Vom Glück getäuscht, vor mir hinweggeschwunden.
--------------------------------------------------------------------------------
/public/fonts/miso-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/fonts/miso-bold.ttf
--------------------------------------------------------------------------------
/public/images/00.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/public/images/01.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/02.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/03.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/public/images/04.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/05.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/public/images/06.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/public/images/07.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/public/images/08.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/09.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/public/images/10.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/public/images/11.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/public/images/12.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/public/images/13.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/public/images/14.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/public/images/15.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
--------------------------------------------------------------------------------
/public/images/comma.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/dynamic-brush.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/emacs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/emacs.png
--------------------------------------------------------------------------------
/public/images/exclamationmark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/fcb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/fcb.jpg
--------------------------------------------------------------------------------
/public/images/period.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/questionmark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/return.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/shape.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/shape.jpg
--------------------------------------------------------------------------------
/public/images/sojka.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/sojka.jpg
--------------------------------------------------------------------------------
/public/images/space.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/space2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/public/images/texture-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/texture-white.png
--------------------------------------------------------------------------------
/public/images/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/texture.png
--------------------------------------------------------------------------------
/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | {:nrepl {:port 9200}
2 | :dev-http {9201 "public"}
3 | :source-paths
4 | ["src"]
5 |
6 | :dependencies
7 | [[reagent "1.1.1"]
8 | [com.bhauman/figwheel-main "0.2.3"]
9 | [reagent "0.10.0"]
10 | [quil "3.1.0"]
11 | [thi.ng/geom "1.0.0-RC4"]
12 | [thi.ng/math "0.3.0"]
13 | [thi.ng/color "1.4.0"]]
14 |
15 | :builds
16 | {:app {:target :browser
17 | :output-dir "public/js"
18 | :asset-path "/js"
19 | :compiler-options {:output-feature-set :es-next}
20 | :modules {:main {:entries [sketches.core]}}}}}
21 |
--------------------------------------------------------------------------------
/src/js/index.js:
--------------------------------------------------------------------------------
1 | import Palettes from 'nice-color-palettes'
2 | import BezierEasing from 'bezier-easing'
3 | import Matter from 'matter-js'
4 | window['nice-color-palettes'] = Palettes
5 | window['bezier-easing'] = BezierEasing
6 | window.matter = Matter
7 |
--------------------------------------------------------------------------------
/src/sketches/components.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.components
2 | (:require [sketches.icons :refer [play-icon reload-icon stop-icon]]
3 | [quil.core :as q]
4 | [reagent.core :as r]))
5 |
6 | (defn section [title description]
7 | [:div.mb4.tc.tl-ns
8 | [:a.link.white {:href (str "#" title)}
9 | [:h2 title]]
10 | [:p description]])
11 |
12 | (defn cards-container [children]
13 | [:div.flex.flex-wrap.justify-center.justify-start-ns
14 | children])
15 |
16 | (defn card [title sub-title children]
17 | [:div.bg-white.br2.flex.flex-column.justify-between.items-center.f3.black.mb3.mr3-ns
18 | [:div.flex.justify-center.items-center
19 | children]
20 | [:div.mt3
21 | [:span.ma0 title]]
22 | [:div.mb3.f4
23 | sub-title]])
24 |
25 | (defn stop-sketch [id]
26 | (q/with-sketch (q/get-sketch-by-id id)
27 | (q/no-loop)))
28 |
29 | (defn sketch [title run-sketch run-immediately]
30 | (let [is-started (r/atom false)]
31 | (fn []
32 | (if (or @is-started run-immediately)
33 | (let [id (str title)]
34 | [(with-meta (fn [] [:div.flex.flex-column.items-center
35 | [:div.w5.h5.mt4.mh4.mb3 {:id id}]
36 | [:div.flex.h1
37 | [:button.pointer.bn.bg-transparent
38 | {:on-click #(do (stop-sketch id) (run-sketch id))}
39 | (reload-icon)]
40 | [:button.pointer.bn.bg-transparent
41 | {:on-click #(do
42 | (stop-sketch id)
43 | (reset! is-started false))}
44 | (stop-icon)]]])
45 | {:component-did-mount #(run-sketch id)})])
46 | [:div
47 | [:div.w5.h5.ma4.flex.justify-center.items-center.bg-gray
48 | [:button.button.bg-transparent.bn.white.pointer
49 | {:on-click #(reset! is-started true) :aria-label (str "Run " title " Sketch")}
50 | (play-icon :medium "white")]]]))))
51 |
52 | (defn exercise-card [title exercise-title exercise-link run-sketch run-immediately]
53 | (fn []
54 | [card
55 | title
56 | [:a.link.bb {:href exercise-link :target "_blank" :rel "noreferrer"} exercise-title]
57 | [sketch title run-sketch run-immediately]]))
58 |
--------------------------------------------------------------------------------
/src/sketches/core.clj:
--------------------------------------------------------------------------------
1 | (ns sketches.core
2 | (:require [clojure.java.io :as io]
3 | [quil.core :as q]
4 | [sketches.generative-artistry.cubic-disarray :as cd]
5 | [tech.thomas-sojka.clj-axidraw.core :as axidraw]))
6 |
7 | (defn plot-sketch []
8 | (let [file-name "temp/sketch.svg"]
9 | q/defsketch
10 | (q/sketch
11 | :draw cd/draw
12 | :size [300 300]
13 | )
14 | (io/make-parents file-name)
15 | (axidraw/estimate file-name)
16 | (io/delete-file file-name)))
17 |
18 | (comment
19 | (plot-sketch)
20 | (axidraw/raise-pen)
21 | (axidraw/lower-pen)
22 | (def file-name "temp/sketch.svg"))
23 |
--------------------------------------------------------------------------------
/src/sketches/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.core
2 | (:require [reagent.dom :as dom]
3 | [sketches.creative-coding.core :as creative-coding]
4 | [sketches.generative-artistry.core :as generative-artistry]
5 | [sketches.generative-desgin.core :as generative-design]
6 | [sketches.nature-of-code.core :as nature-of-code]
7 | [sketches.rac-sketches.core :as rac-sketches]))
8 |
9 | (defn app []
10 | [:main.sans-serif.pa4.white.mw9.center
11 | [:div.mb5.tc.tl-ns
12 | [:h1 "Sketches by "
13 | [:a.pointer.bb.link.white {:href "https://twitter.com/rollacaster"} "@rollacaster"]]]
14 | [:div.mb5
15 | [rac-sketches/main]]
16 | [:div.mb5
17 | [generative-design/main]]
18 | [:div.mb5
19 | [creative-coding/main]]
20 | [:div.mb5
21 | [generative-artistry/main]]
22 | [:div.mb5
23 | [nature-of-code/main]]])
24 |
25 | (dom/render app (.getElementById js/document "app"))
26 |
--------------------------------------------------------------------------------
/src/sketches/creative_coding/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.creative-coding.core
2 | (:require [sketches.components :refer [cards-container exercise-card section]]
3 | [sketches.creative-coding.print-art :as pa]
4 | [sketches.creative-coding.webgl :as wg]))
5 |
6 | (defn main []
7 | [:<>
8 | [section
9 | "Creative Coding with Canvas & WebGL"
10 | [:<>
11 | "Sketches of "
12 | [:a.pointer.bb.link.white {:href "https://twitter.com/mattdesl"} "Matt DesLauriers'"] " "
13 | [:a.pointer.bb.link.white {:href "https://frontendmasters.com/courses/canvas-webgl/"} "Creative Coding with Canvas & WebGL"]
14 | " implemented in ClojureScript."]]
15 | [cards-container
16 | [:<>
17 | [exercise-card "01" "Print Art with Canvas" "https://frontendmasters.com/courses/canvas-webgl/" pa/run]
18 | [exercise-card "02" "WebGL" "https://frontendmasters.com/courses/canvas-webgl/" wg/run]]]])
19 |
--------------------------------------------------------------------------------
/src/sketches/creative_coding/print_art.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.creative-coding.print-art
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [nice-color-palettes]))
5 |
6 | (def palettes (js->clj nice-color-palettes))
7 |
8 | (defn pick-random [list]
9 | (nth list (rand-int (- (count list) 1))))
10 |
11 | (defn pick-random-palette []
12 | (map
13 | #(map (fn [s] (q/unhex (apply str s)))
14 | (partition 2 (rest %)))
15 | (pick-random palettes)))
16 |
17 |
18 | (defn setup []
19 | (let [grid 40
20 | font "Helvetica"
21 | palette (pick-random-palette)
22 | points (for [x (range grid)
23 | y (range grid)]
24 | (let [u (/ x (- grid 1))
25 | v (/ y (- grid 1))]
26 | {:color (nth palette (rand-int 3))
27 | :position [u v]
28 | :radius (* (q/abs (q/noise u v)) 0.2)
29 | :rotation (* (q/abs (q/noise u v)) 0.5)}))]
30 | (doseq [{:keys [radius color rotation]
31 | [u v] :position} points]
32 | (q/push-matrix)
33 | (apply q/fill color)
34 | (q/translate (q/map-range u 0 1 0 (q/width))
35 | (q/map-range v 0 1 0 (q/height)))
36 | (q/rotate rotation)
37 | (q/text-font font (* radius (q/width)))
38 | (q/text "=" 0 0)
39 | (q/pop-matrix))))
40 |
41 | (defn run [host]
42 | (q/defsketch print-art
43 | :host host
44 | :setup setup
45 | :size [300 300]))
46 |
--------------------------------------------------------------------------------
/src/sketches/creative_coding/webgl.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.creative-coding.webgl
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [nice-color-palettes]
5 | [bezier-easing]))
6 |
7 | (def palettes (js->clj nice-color-palettes))
8 |
9 | (defn pick-random [list]
10 | (nth list (rand-int (- (count list) 1))))
11 |
12 | (defn pick-random-palette []
13 | (map
14 | #(map (fn [s] (q/unhex (apply str s)))
15 | (partition 2 (rest %)))
16 | (pick-random palettes)))
17 |
18 | (defn draw [{:keys [rotation boxes]}]
19 | (q/clear)
20 | (q/translate 0 0 -500)
21 | (q/rotate (q/radians 45) 0 1 0)
22 | (q/rotate rotation 1 0 0)
23 | (q/ambient-light 200 200 200)
24 | (q/directional-light 255 255 255 0 1 -0.5)
25 | (doseq [{:keys [scale position color]} boxes]
26 | (q/push-matrix)
27 | (apply q/ambient color)
28 | (apply q/scale scale)
29 | (apply q/translate position)
30 | (q/box 100 100 100)
31 | (q/pop-matrix)))
32 |
33 | (def ease-fn (bezier-easing 0.67 0.03 0.29 0.99))
34 |
35 | (defn update-state [state]
36 | (-> state
37 | (update :rotation #(ease-fn (q/sin (* (:play-head state) q/PI))))
38 | (update :play-head #(mod (+ % 0.01) 1))))
39 |
40 | (defn setup []
41 | (q/stroke-weight 0)
42 | (let [palette (pick-random-palette)]
43 | {:boxes (map
44 | (fn [i]
45 | (let [color (pick-random palette)]
46 | {:scale [(q/random -1 1) (q/random -1 1) (q/random -1 1)]
47 | :position [(q/random 0 (q/width))
48 | (q/random 0 (q/height))
49 | (q/random 0 (q/height))]
50 | :color color}))
51 | (range 100))
52 | :rotation 0
53 | :play-head 0}))
54 |
55 | (defn run [host]
56 | (q/defsketch webgl
57 | :host host
58 | :setup setup
59 | :draw draw
60 | :update update-state
61 | :renderer :p3d
62 | :middleware [md/fun-mode]
63 | :size [300 300]))
64 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/circle_packing.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.circle-packing
2 | (:require [quil.core :as q]
3 | [quil.middleware :as m]
4 | [clojure.pprint :as p]))
5 |
6 | (defn does-circle-have-a-collision [circles {:keys [x y radius]}]
7 | (some
8 | (fn [other-circle]
9 | (let [a (+ (/ radius 2) (/ (:radius other-circle) 2))
10 | x (- x (:x other-circle))
11 | y (- y (:y other-circle))]
12 | (>= a (Math/sqrt (+ (* x x) (* y y))))))
13 | circles))
14 |
15 | (defn create-circle []
16 | {:x (q/random (q/width))
17 | :y (q/random (q/height))
18 | :radius 2})
19 |
20 | (defn draw-circle [{:keys [x y radius]}]
21 | (q/ellipse x y radius radius))
22 |
23 | (defn setup []
24 | (q/no-fill)
25 | (let [total-circles 500
26 | max-radius 100
27 | circles (loop [i 0
28 | {:keys [radius] :as circle} (create-circle)
29 | circles ()]
30 | (cond
31 | (>= i total-circles) circles
32 | (= radius max-radius)
33 | (recur (inc i) (create-circle) (conj circles circle))
34 | (does-circle-have-a-collision circles (update circle :radius inc))
35 | (if (not (does-circle-have-a-collision circles circle))
36 | (recur (inc i) (create-circle) (conj circles circle))
37 | (recur i (create-circle) circles))
38 | (< radius max-radius) (recur i (update circle :radius inc) circles)
39 | :else (recur (inc i) (create-circle) circles)))]
40 | (doall (map draw-circle circles))))
41 |
42 |
43 | (defn run [host]
44 | (q/defsketch circle-packing
45 | :host host
46 | :setup setup
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.core
2 | (:require [sketches.components :refer [cards-container exercise-card section]]
3 | [sketches.generative-artistry.circle-packing :as cp]
4 | [sketches.generative-artistry.cubic-disarray :as cd]
5 | [sketches.generative-artistry.hypnotic-squares :as hs]
6 | [sketches.generative-artistry.joy-division :as jd]
7 | [sketches.generative-artistry.piet-mondarin :as pm]
8 | [sketches.generative-artistry.tiled-lines :as tl]
9 | [sketches.generative-artistry.triangular-mesh :as tm]
10 | [sketches.generative-artistry.un-deux-trois :as un]))
11 |
12 | (defn main []
13 | [:<>
14 | [section
15 | "Generative Artistry"
16 | [:<>
17 | "Tutorials of "
18 | [:a.pointer.bb.link.white {:href "https://twitter.com/twholman?"} "Tim Holman's"] " "
19 | [:a.pointer.bb.link.white {:href "https://generativeartistry.com/"} "Generative Artistry"]
20 | " implemented in ClojureScript."]]
21 | [cards-container
22 | [:<>
23 | [exercise-card "01" "Tiled Lines" "https://generativeartistry.com/tutorials/tiled-lines/" tl/run]
24 | [exercise-card "02" "Joy Division" "https://generativeartistry.com/tutorials/joy-division/" jd/run]
25 | [exercise-card "03" "Cubic Disarray" "https://generativeartistry.com/tutorials/cubic-disarray/" cd/run]
26 | [exercise-card "04" "Triangular Mesh" "https://generativeartistry.com/tutorials/triangular-mesh/" tm/run]
27 | [exercise-card "05" "Un Deux Trois" "https://generativeartistry.com/tutorials/un-deux-trois/" un/run]
28 | [exercise-card "06" "Circle Packing" "https://generativeartistry.com/tutorials/circle-packing/" cp/run]
29 | [exercise-card "07" "Hypnotic Squares" "https://generativeartistry.com/tutorials/hypnotic-squares/" hs/run]
30 | [exercise-card "08" "Piet Mondrian" "https://generativeartistry.com/tutorials/piet-mondrian/" pm/run]]]])
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/cubic_disarray.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.cubic-disarray
2 | (:require [quil.core :as q]))
3 |
4 | (defn setup [])
5 |
6 | (defn draw []
7 | (q/no-loop)
8 | (q/background 255)
9 | (q/stroke 0)
10 | (q/stroke-weight 2)
11 | (q/rect-mode :center)
12 | (let [step 30]
13 | (q/translate (/ step 2) (/ step 2))
14 | (doall (map
15 | (fn [xStep]
16 | (doall
17 | (map
18 | (fn [yStep]
19 | (q/push-matrix)
20 | (let [max-displacement 15
21 | max-rotation 20
22 | rotate-amt (* (/ yStep (q/height))
23 | (/ q/PI 180)
24 | (if (< (q/random 1) 0.5) -1 1)
25 | (q/random 1)
26 | max-rotation)
27 | translate-amt (* (/ yStep (q/height))
28 | (if (< (q/random 1) 0.5) -1 1)
29 | (q/random 1)
30 | max-displacement)]
31 | (q/translate (+ xStep translate-amt) (+ yStep))
32 | (q/rotate rotate-amt))
33 | (q/rect 0 0 step step)
34 | (q/pop-matrix))
35 | (range 0 (q/height) step))))
36 | (range 0 (q/width) step)))))
37 |
38 | (defn run [host]
39 | (q/defsketch cubic-dissary
40 | :host host
41 | :setup setup
42 | :draw draw
43 | :size [300 300]))
44 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/hypnotic_squares.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.hypnotic-squares
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (let [final-size 3
7 | offset 2
8 | tile-step (/ (- (q/width) (* offset 2)) 7)
9 | start-size tile-step ]
10 | (defn draw [x y width height x-movement y-movement steps start-steps]
11 | (q/rect x y width height)
12 | (if (>= steps 0)
13 | (let [new-size (+ (* start-size (/ steps start-steps)) final-size)
14 | new-x (+ x (/ (- width new-size) 2))
15 | tilted-x (- new-x (* (/ (- x new-x) (+ steps 2)) x-movement))
16 | new-y (+ y (/ (- height new-size) 2))
17 | tilted-y (- new-y (* (/ (- y new-y) (+ steps 2)) y-movement))]
18 | (draw tilted-x tilted-y new-size new-size x-movement y-movement (dec steps) start-steps))))
19 | (doall
20 | (for [x (range offset (- (q/width) offset) tile-step)
21 | y (range offset (- (q/height) offset) tile-step)]
22 | (let [start-steps (+ 2 (Math/ceil (q/random 3)))]
23 | (draw x y start-size start-size (Math/floor (q/random -1 1)) (Math/floor (q/random -1 1)) start-steps start-steps))))))
24 |
25 | (defn run [host]
26 | (q/defsketch hypnotic-squers
27 | :host host
28 | :setup setup
29 | :size [300 300]))
30 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/joy_division.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.joy-division
2 | (:require [quil.core :as q]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup [host])
6 |
7 | (defn draw []
8 | (q/no-loop)
9 | (q/background 255)
10 | (q/stroke 0)
11 | (let [step 20]
12 | (doall (map
13 | (fn [yStep]
14 | (q/begin-shape)
15 | (doall
16 | (map
17 | (fn [xStep]
18 | (let [distance-to-center (q/abs (- xStep (/ (q/width) 2)))
19 | variance (max (- (/ (q/width) 2) 50 distance-to-center) 0)
20 | r (* (q/random 1) (/ variance 2) -1)]
21 | (q/curve-vertex xStep (+ r yStep))))
22 | (range (- step) (+ step step (q/width)) step)))
23 | (q/end-shape))
24 | (range 0 (q/height) step)))))
25 |
26 | (defn run [host]
27 | (q/defsketch tiledLines
28 | :host host
29 | :setup setup
30 | :draw draw
31 | :size [300 300]))
32 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/piet_mondarin.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.piet-mondarin
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [quil.sketch]))
5 |
6 | (defn split-on-x [square split-at]
7 | (let [square-a {:x (:x square)
8 | :y (:y square)
9 | :width (- (:width square) (+ (- (:width square) split-at) (:x square)))
10 | :height (:height square)}
11 | square-b {:x split-at
12 | :y (:y square)
13 | :width (+ (- (:width square) split-at) (:x square))
14 | :height (:height square)}]
15 | [square-a square-b]))
16 |
17 | (defn split-on-y [square split-at]
18 | (let [square-a {:x (:x square)
19 | :y (:y square)
20 | :width (:width square)
21 | :height (- (:height square) (+ (- (:height square) split-at) (:y square)))}
22 | square-b {:x (:x square)
23 | :y split-at
24 | :width (:width square)
25 | :height (+ (- (:height square) split-at) (:y square))}]
26 | [square-a square-b]))
27 |
28 | (defn split-squares-with [squares {:keys [x y]}]
29 | (if (> (q/random 1) 0.5)
30 | (reduce (fn [squares square]
31 | (cond
32 | (and (> x (:x square)) (< (:x square) (+ (:x square) (:width square)))) (concat squares (split-on-x square x))
33 | (and (> y (:y square)) (< (:y square) (+ (:y square) (:height square)))) (concat squares (split-on-y square y))
34 | :else (concat squares [square])))
35 | []
36 | squares)
37 | squares))
38 |
39 | (defn draw-square [{:keys [x y width height color]}]
40 | (q/fill (if color color "#F2F5F1"))
41 | (q/rect x y width height))
42 |
43 | (defn draw [squares]
44 | (doall (map draw-square squares)))
45 |
46 | (defn add-colors [squares]
47 | (let [i1 (Math/floor (q/random 0 (count squares)))
48 | i2 (Math/floor (q/random 0 (count squares)))
49 | i3 (Math/floor (q/random 0 (count squares)))]
50 | (-> (into [] squares)
51 | (update i1 (fn [square] (assoc square :color "#D40920")))
52 | (update i2 (fn [square] (assoc square :color "#1356A2")))
53 | (update i3 (fn [square] (assoc square :color "#F7D842"))))))
54 |
55 | (defn setup []
56 | (q/stroke-weight 8)
57 | (let [squares [{:x 0 :y 0 :width (q/width) :height (q/height)}]
58 | step (/ (q/width) 6)]
59 | (draw
60 | (add-colors
61 | (doall (reduce
62 | (fn [squares i]
63 | (-> squares
64 | (split-squares-with {:y i})
65 | (split-squares-with {:x i})))
66 | squares
67 | (range 0 (* step 6) step)))))))
68 |
69 | (defn run [host]
70 | (q/defsketch pient-mondrain
71 | :host host
72 | :setup setup
73 | :size [300 300]))
74 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/tiled_lines.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.tiled-lines
2 | (:require [quil.core :as q]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup [])
6 |
7 | (defn draw []
8 | (q/no-loop)
9 | (q/background 255)
10 | (q/stroke 0)
11 | (let [step 30]
12 | (doall (map
13 | (fn [xStep]
14 | (doall
15 | (map
16 | (fn [yStep]
17 | (q/push-matrix)
18 | (q/translate xStep yStep)
19 | (let [is-inverted (< 0.5 (q/random 1))]
20 | (apply q/line (if is-inverted
21 | [0 0 step step]
22 | [step 0 0 step])))
23 | (q/pop-matrix))
24 | (range 0 (q/height) step))))
25 | (range 0 (q/width) step)))))
26 |
27 | (defn run [host]
28 | (q/defsketch tiledLines
29 | :host host
30 | :setup setup
31 | :draw draw
32 | :size [300 300]))
33 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/triangular_mesh.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.triangular-mesh
2 | (:require [quil.core :as q]
3 | [quil.middleware :as m]
4 | [clojure.pprint :as p]))
5 |
6 | (defn setup []
7 | (let [gap (/ (q/width) 8)
8 | lines (doall (for [y (range gap (q/height) gap)]
9 | (for [x (range gap (q/width) gap)
10 | :let [odd (odd? (/ y gap))]]
11 | {:x (+ x (* gap (- (* (q/random 1) 0.8) 0.4)) (if odd (/ gap 2) 0))
12 | :y (+ y (* gap (- (* (q/random 1) 0.8) 0.4)))})))
13 | dot-line (map-indexed
14 | (fn [lineIdx line]
15 | (reduce concat
16 | (let [dot-line
17 | (map-indexed
18 | (fn [idx point]
19 | (if (odd? lineIdx)
20 | [point (get (into [] (get (into [] lines) (inc lineIdx))) idx)]
21 | [(get (into [] (get (into [] lines) (inc lineIdx))) idx) point]))
22 | line)]
23 | dot-line
24 | )))
25 | (butlast lines))]
26 | (doall
27 | (map
28 | (fn [line]
29 | (doall
30 | (map-indexed
31 | (fn [idx p1]
32 | (let [p2 (get (into [] line) (inc idx))
33 | p3 (get (into [] line) (inc (inc idx)))]
34 | (q/fill (* (rand-int 16) (/ 255 16)))
35 | (q/triangle (:x p1) (:y p1) (:x p2) (:y p2) (:x p3) (:y p3))))
36 | (butlast (butlast line)))))
37 | dot-line))))
38 |
39 |
40 |
41 | (defn run [host]
42 | (q/defsketch triangular-mesh
43 | :host host
44 | :setup setup
45 | :size [300 300]))
46 |
--------------------------------------------------------------------------------
/src/sketches/generative_artistry/un_deux_trois.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-artistry.un-deux-trois
2 | (:require [quil.core :as q]
3 | [quil.middleware :as m]
4 | [clojure.pprint :as p]))
5 |
6 | (defn draw-line [x y width height positions]
7 | (q/push-matrix)
8 | (q/translate (+ x (/ width 2)) (+ y (/ height 2)))
9 | (q/rotate (q/random 5))
10 | (q/translate (- (/ width 2)) (- (/ height 2)))
11 | (doall
12 | (for [i positions]
13 | (q/line (* i width) 0 (* i width) height)))
14 | (q/pop-matrix))
15 |
16 | (defn setup []
17 | (let [step 20
18 | third-of-height (/ (q/height) 3)]
19 | (q/stroke-weight 4)
20 | (doall
21 | (for [y (range step (- (q/height) step) step)]
22 | (doall
23 | (for [x (range step (- (q/width) step) step)]
24 | (cond
25 | (< y third-of-height) (draw-line x y step step [0.5])
26 | (< y (* third-of-height 2)) (draw-line x y step step [0.2 0.8])
27 | :else (draw-line x y step step [0.1 0.5 0.9]))))))))
28 |
29 |
30 | (defn run [host]
31 | (q/defsketch un-deux-trois
32 | :host host
33 | :setup setup
34 | :size [300 300]))
35 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_01/P_1_0_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-01.P-1-0-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/no-cursor)
7 | (q/color-mode :hsb 360 100 100)
8 | (q/rect-mode :center)
9 | (q/no-stroke))
10 |
11 | (defn update-state [])
12 |
13 | (defn draw []
14 | (q/background (q/map-range (q/mouse-y) 0 300 0 360) 100 100)
15 | (q/fill (- 360 (q/map-range (q/mouse-y) 0 300 0 360)) 100 100)
16 | (q/rect 150 150 (+ (q/mouse-x) 1) (+ (q/mouse-x) 1)))
17 |
18 | (defn run [host]
19 | (q/defsketch p1001
20 | :host host
21 | :setup setup
22 | :draw draw
23 | :update update-state
24 | :middleware [md/fun-mode]
25 | :size [300 300]))
26 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_01/P_1_1_1_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-01.P-1-1-1-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/no-stroke)
7 | (q/color-mode :hsb (q/width) (q/height) 100))
8 |
9 | (defn update-state [])
10 |
11 | (defn draw []
12 | (let [step-x (+ (q/mouse-x) 2)
13 | step-y (+ (q/mouse-y) 2)]
14 | (doseq [grid-y (range 0 (q/height) step-y)
15 | grid-x (range 0 (q/width) step-x)]
16 | (q/fill grid-x (- (q/height) grid-y) 100)
17 | (q/rect grid-x grid-y step-x step-y))))
18 |
19 | (defn run [host]
20 | (q/defsketch P_1_1_1_01
21 | :host host
22 | :setup setup
23 | :draw draw
24 | :update update-state
25 | :middleware [md/fun-mode]
26 | :size [300 300]))
27 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_01/P_1_1_2_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-01.P-1-1-2-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/no-stroke)
7 | {:segment-count 360})
8 |
9 | (defn update-state [state]
10 | state)
11 |
12 | (defn draw [{:keys [segment-count]}]
13 | (q/color-mode :hsb 360 (q/width) (q/height))
14 | (q/background 360 0 (q/height))
15 |
16 | (let [angle-step (/ 360 segment-count)]
17 | (q/begin-shape :triangle-fan)
18 | (q/vertex (/ (q/width) 2) (/ (q/height) 2))
19 | (doseq [angle (range 0 (+ 360 angle-step) angle-step)]
20 | (let [radius 100
21 | vx (+ (/ (q/width) 2) (* (q/cos (q/radians angle)) radius))
22 | vy (+ (/ (q/height) 2) (* (q/sin (q/radians angle)) radius))]
23 | (q/vertex vx vy)
24 | (q/fill angle (q/mouse-x) (q/mouse-y))))
25 | (q/end-shape)))
26 |
27 | (defn key-pressed [state {:keys [key]}]
28 | (assoc state :segment-count
29 | (case key
30 | :1 360
31 | :2 45
32 | :3 24
33 | :4 12
34 | :5 6)))
35 |
36 | (defn run [host]
37 | (q/defsketch color-spectrum-in-a-circle
38 | :host host
39 | :setup setup
40 | :draw draw
41 | :update update-state
42 | :middleware [md/fun-mode]
43 | :size [300 300]
44 | :key-pressed key-pressed))
45 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_01/P_1_2_1_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-01.P-1-2-1-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn shake-colors [{:keys [tile-count-y] :as state}]
6 | (loop [i 0 state state]
7 | (let [colors-added (-> state
8 | (assoc-in [:colors-left i] (q/color (q/random 0 60) (q/random 0 100) 100))
9 | (assoc-in [:colors-right i] (q/color (q/random 160 190) 100 (q/random 0 100))))]
10 | (if (= i tile-count-y)
11 | colors-added
12 | (recur (inc i) colors-added)))))
13 |
14 | (defn setup []
15 | (q/no-stroke)
16 | (shake-colors {:tile-count-x 2
17 | :tile-count-y 10
18 | :colors-left [] :colors-right []}))
19 |
20 | (defn update-state [state]
21 | (-> state
22 | (assoc :tile-count-x (int (q/map-range (q/mouse-x) 0 (q/width) 2 100)))
23 | (assoc :tile-count-y (int (q/map-range (q/mouse-y) 0 (q/height) 2 10)))))
24 |
25 | (defn draw [{:keys [tile-count-x tile-count-y colors-left colors-right]}]
26 | (let [tile-width (/ (q/width) tile-count-x)
27 | tile-height (/ (q/height) tile-count-y)]
28 | (doseq [grid-y (range 0 tile-count-y)]
29 | (let [col1 (nth colors-left grid-y)
30 | col2 (nth colors-right grid-y)]
31 | (doseq [grid-x (range 0 tile-count-x)]
32 | (let [amount (q/map-range grid-x 0 (- tile-count-x 1) 0 1)
33 | intercol (q/lerp-color col1 col2 amount)
34 | pos-x (* tile-width grid-x)
35 | pos-y (* tile-height grid-y)]
36 | (q/fill intercol)
37 | (q/rect pos-x pos-y tile-width tile-height)))))))
38 |
39 | (defn run [host]
40 | (q/defsketch palettes-interpolation
41 | :host host
42 | :setup setup
43 | :draw draw
44 | :update update-state
45 | :mouse-released shake-colors
46 | :middleware [md/fun-mode]
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_01/P_1_2_3_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-01.P-1-2-3-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def tile-count-x 50)
6 | (def tile-count-y 10)
7 |
8 | (defn color-parts [h s b]
9 | {:hueValues (into [] (for [_ (range 0 tile-count-x)] (h)))
10 | :saturationValues (into [] (for [_ (range 0 tile-count-x)] (s)))
11 | :brightnessValues (into [] (for [_ (range 0 tile-count-x)] (b)))})
12 |
13 | (defn setup []
14 | (q/color-mode :hsb 360 100 100 100)
15 | (q/no-stroke)
16 | (color-parts #(q/random 360) #(q/random 100) #(q/random 100)))
17 |
18 | (defn update-state [state]
19 | state)
20 |
21 | (defn draw [{:keys [hueValues saturationValues brightnessValues]}]
22 | (q/background 0 0 100)
23 | (let [mx (q/constrain (q/mouse-x) 0 (q/width))
24 | my (q/constrain (q/mouse-y) 0 (q/height))
25 | current-tile-count-x (int (q/map-range mx 0 (q/width) 1 tile-count-x))
26 | current-tile-count-y (int (q/map-range my 0 (q/width) 1 tile-count-y))
27 | tile-width (/ (q/width) current-tile-count-x)
28 | tile-height (/ (q/height) current-tile-count-y)]
29 | (doseq [grid-y (range 0 tile-count-y)
30 | grid-x (range 0 tile-count-x)]
31 | (let [pos-x (* tile-width grid-x)
32 | pos-y (* tile-height grid-y)
33 | index (mod (+ grid-x (* tile-count-x grid-y)) current-tile-count-x)]
34 | (q/fill (hueValues index) (saturationValues index) (brightnessValues index))
35 | (q/rect pos-x pos-y tile-width tile-height)))))
36 |
37 | (defn key-pressed [state {:keys [key]}]
38 | (case key
39 | :1 (color-parts #(q/random 360) #(q/random 100) #(q/random 100))
40 | :2 (color-parts #(q/random 360) #(q/random 100) #(identity 100))
41 | :3 (color-parts #(q/random 360) #(identity 100) #(q/random 100))
42 | :4 (color-parts #(identity 0) #(identity 0) #(q/random 100))
43 | :5 (color-parts #(identity 195) #(identity 100) #(q/random 100))
44 | :6 (color-parts #(identity 195) #(q/random 100) #(identity 100))
45 | :7 (color-parts #(q/random 180) #(q/random 80 100) #(q/random 50 90))
46 | :8 (color-parts #(q/random 180 360) #(q/random 80 100) #(q/random 50 90))
47 | state))
48 |
49 | (defn run [host]
50 | (q/defsketch color-palettes-rules
51 | :host host
52 | :setup setup
53 | :draw draw
54 | :update update-state
55 | :key-pressed key-pressed
56 | :middleware [md/fun-mode]
57 | :size [300 300]))
58 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_0_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-0-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup [])
6 |
7 | (defn update-state [])
8 |
9 | (defn draw []
10 | (q/background 255)
11 | (q/translate (/ (q/width) 2) (/ (q/height) 2))
12 | (let [circle-resolution (q/map-range (q/mouse-y) 0 (q/height) 2 80)
13 | radius (+ (- (q/mouse-x) (/ (q/width) 2)) 0.5)
14 | angle (/ q/TWO-PI circle-resolution)]
15 | (q/stroke-weight (/ (q/mouse-y) 20))
16 | (q/begin-shape)
17 | (doseq [i (range 0 circle-resolution)]
18 | (let [x (* (q/cos (* angle i)) radius)
19 | y (* (q/sin (* angle i)) radius)]
20 | (q/line 0 0 x y)))
21 | (q/end-shape :close)))
22 |
23 | (defn run [host]
24 | (q/defsketch circle-lines
25 | :host host
26 | :setup setup
27 | :draw draw
28 | :update update-state
29 | :middleware [md/fun-mode]
30 | :size [300 300]))
31 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_1_1_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-1-1-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def tile-count 20)
6 |
7 | (defn setup [])
8 |
9 | (defn update-state [])
10 |
11 | (defn draw []
12 | (q/clear)
13 | (q/stroke-cap :round)
14 |
15 | (q/random-seed 0)
16 |
17 | (doseq [grid-y (range 0 tile-count)
18 | grid-x (range 0 tile-count)]
19 | (let [pos-x (* (/ (q/width) tile-count) grid-x)
20 | pos-y (* (/ (q/height) tile-count) grid-y)
21 | toggle (int (q/random 0 2))]
22 | (when (= toggle 0)
23 | (q/stroke-weight (/ (q/mouse-x) 20))
24 | (q/line pos-x pos-y (+ pos-x (/ (q/width) tile-count)) (+ pos-y (/ (q/height) tile-count))))
25 | (when (= toggle 1)
26 | (q/stroke-weight (/ (q/mouse-y) 20))
27 | (q/line pos-x (+ pos-y (/ (q/height) tile-count)) (+ pos-x (/ (q/width) tile-count)) pos-y)))))
28 |
29 | (defn run [host]
30 | (q/defsketch alignment-in-a-grid
31 | :host host
32 | :setup setup
33 | :draw draw
34 | :update update-state
35 | :middleware [md/fun-mode]
36 | :size [300 300]))
37 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_1_2_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-1-2-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def tile-count 20)
6 |
7 | (defn setup []
8 | (q/no-fill))
9 |
10 | (defn update-state [])
11 |
12 | (defn draw []
13 | (q/random-seed 0)
14 | (q/translate (/ (/ (q/width) tile-count) 2)
15 | (/ (/ (q/height) tile-count) 2))
16 | (q/background 255)
17 |
18 | (q/stroke 0 0 0 130)
19 | (q/stroke-weight (/ (q/mouse-y) 60))
20 |
21 | (doseq [grid-y (range 0 tile-count)
22 | grid-x (range 0 tile-count)]
23 | (let [pos-x (* (/ (q/width) tile-count) grid-x)
24 | pos-y (* (/ (q/height) tile-count) grid-y)
25 | shift-x (/ (q/random (- (q/mouse-x)) (q/mouse-x)) 20)
26 | shift-y (/ (q/random (- (q/mouse-x)) (q/mouse-x)) 20)]
27 | (q/ellipse (+ pos-x shift-x) (+ pos-y shift-y) (/ (q/mouse-y) 15) (/ (q/mouse-y) 15)))))
28 |
29 | (defn run [host]
30 | (q/defsketch movement-in-grid
31 | :host host
32 | :setup setup
33 | :draw draw
34 | :update update-state
35 | :middleware [md/fun-mode]
36 | :size [300 300]))
37 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_1_3_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-1-3-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def tile-count-x 10)
6 | (def tile-count-y 10)
7 |
8 | (defn setup []
9 | (q/no-fill)
10 | (q/stroke 0 128)
11 | {:tile-width (/ (q/width) tile-count-x)
12 | :tile-height (/ (q/height) tile-count-y)})
13 |
14 | (defn update-state [state]
15 | state)
16 |
17 | (defn draw [{:keys [tile-width tile-height]}]
18 | (q/background 255)
19 | (q/translate (/ tile-width 2) (/ tile-height 2))
20 | (q/random-seed 0)
21 | (let [circle-count (+ (/ (q/mouse-x) 30) 1)
22 | end-size (q/map-range (q/mouse-x) 0 (Math/max (q/width) (q/mouse-x)) (/ tile-width 2) 0)
23 | end-offset (q/map-range (q/mouse-y) 0 (Math/max (q/height) (q/mouse-y)) 0 (/ (- tile-width end-size) 2))]
24 | (doseq [grid-y (range 0 tile-count-y)
25 | grid-x (range 0 tile-count-x)]
26 | (q/push-matrix)
27 | (q/translate (* tile-width grid-x) (* tile-height grid-y))
28 | (q/scale 1 (/ tile-height tile-width))
29 | (case (int (q/random 0 4))
30 | 0 (q/rotate (- q/HALF-PI))
31 | 1 (q/rotate 0)
32 | 2 (q/rotate q/HALF-PI)
33 | 3 (q/rotate q/PI))
34 | (doseq [i (range 0 circle-count)]
35 | (let [diameter (q/map-range i 0 circle-count tile-width end-size)
36 | offset (q/map-range i 0 circle-count 0 end-offset)]
37 | (q/ellipse offset 0 diameter diameter)))
38 | (q/pop-matrix))))
39 |
40 | (defn run [host]
41 | (q/defsketch complex-modules-in-grid
42 | :host host
43 | :setup setup
44 | :draw draw
45 | :update update-state
46 | :middleware [md/fun-mode]
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_1_4_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-1-4-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def cols 18)
6 | (def rows 9)
7 |
8 | (defn setup [host]
9 | {:image (q/load-image "images/shape.jpg")
10 | :check-boxes (let [host-element (.getElementById js/document host)
11 | div (.createElement js/document "div")]
12 | (.remove (.-firstElementChild host-element))
13 | (set! (.-id div) "mirror")
14 | (.appendChild host-element div)
15 | (flatten
16 | (for [y (range 0 rows)]
17 | (let [checkboxes
18 | (doall (for [x (range 0 cols)]
19 | (let [check-box (.createElement js/document "input")]
20 | (set! (.-type check-box) "checkbox")
21 | (set! (.-display (.-style check-box)) "inline")
22 | (.appendChild div check-box)
23 | check-box)))]
24 | (let [span (.createElement js/document "span")]
25 | (set! (.-innerHTML span) "
")
26 | (.appendChild div span))
27 | checkboxes))))})
28 |
29 | (defn update-state [state]
30 | state)
31 |
32 | (defn draw [{:keys [image check-boxes]}]
33 | (when (q/loaded? image)
34 | (doseq [y (range 0 (.-height image))
35 | x (range 0 (.-width image))]
36 | (let [c (q/color (q/get-pixel image x y))
37 | bright (/ (+ (q/red c) (q/green c) (q/blue c)) 3)
38 | threshold 100
39 | check-index (+ x (* y cols))]
40 | (set! (.-checked (nth check-boxes check-index)) (> bright threshold))))))
41 |
42 | (defn run [host]
43 | (q/defsketch checkboxes-grid
44 | :host host
45 | :setup #(setup host)
46 | :draw draw
47 | :update update-state
48 | :middleware [md/fun-mode]
49 | :size [300 300]))
50 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_1_5_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-1-5-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/no-fill)
7 | {:draw-mode 1})
8 |
9 | (defn update-state [state]
10 | state)
11 |
12 | (defn overlay [draw-mode]
13 | (let [w (- (q/width) 100)
14 | h (- (q/height) 100)]
15 | (if (= draw-mode 1)
16 | (doseq [i (range (/ (- w) 2) (/ w 2) 5)]
17 | (q/line i (/ (- h) 2) i (/ h 2)))
18 | (doseq [i (range 0 w 10)]
19 | (q/ellipse 0 0 i i)))))
20 |
21 | (defn draw [{:keys [draw-mode]}]
22 | (q/background 255)
23 | (q/translate (/ (q/width) 2) (/ (q/height) 2))
24 | (q/stroke-weight 3)
25 | (overlay draw-mode)
26 | (let [x (q/map-range (q/mouse-x) 0 (q/width) -50 50)
27 | a (q/map-range (q/mouse-x) 0 (q/width) -0.5 0.5)
28 | s (q/map-range (q/mouse-y) 0 (q/height) 0.7 1)]
29 | (if (= draw-mode 1)
30 | (q/rotate a)
31 | (q/translate x 0))
32 | (q/scale s)
33 | (q/stroke-weight 2)
34 | (overlay draw-mode)))
35 |
36 | (defn key-pressed [state {:keys [key]}]
37 | (case key
38 | :1 (assoc state :draw-mode 1)
39 | :2 (assoc state :draw-mode 2)
40 | state))
41 |
42 | (defn run [host]
43 | (q/defsketch moire-in-a-grid
44 | :host host
45 | :setup setup
46 | :draw draw
47 | :update update-state
48 | :key-pressed key-pressed
49 | :middleware [md/fun-mode]
50 | :size [300 300]))
51 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_2_1_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-2-1-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def north 0)
6 | (def north-east 1)
7 | (def east 2)
8 | (def south-east 3)
9 | (def south 4)
10 | (def south-west 5)
11 | (def west 6)
12 | (def north-west 7)
13 |
14 | (def step-size 1)
15 | (def diameter 1)
16 |
17 | (defn setup []
18 | (q/no-stroke)
19 | (q/fill 0 40)
20 | [{:pos-x (/ (q/width) 2)
21 | :pos-y (/ (q/height) 2)}])
22 |
23 | (defn update-pos [pos]
24 | (let [direction (rand-int 8)
25 | {:keys [pos-x pos-y]}
26 | (cond
27 | (= direction north) (update pos :pos-y - step-size)
28 | (= direction north-east) (-> pos (update :pos-x + step-size) (update :pos-y - step-size))
29 | (= direction east) (update pos :pos-x + step-size)
30 | (= direction south-east) (-> pos (update :pos-x + step-size) (update :pos-y + step-size))
31 | (= direction south) (update pos :pos-y + step-size)
32 | (= direction south-west) (-> pos (update :pos-x - step-size) (update :pos-y + step-size))
33 | (= direction west) (update pos :pos-x - step-size)
34 | (= direction north-west) (-> pos (update :pos-x - step-size) (update :pos-y - step-size)))]
35 | {:pos-x (cond (> pos-x (q/width)) 0
36 | (< pos-x 0) (q/width)
37 | :else pos-x)
38 | :pos-y (cond (> pos-y (q/height)) 0
39 | (< pos-y 0) (q/height)
40 | :else pos-y)}))
41 |
42 | (defn update-state [state]
43 | (take (q/mouse-x) (iterate update-pos (last state))))
44 |
45 | (defn draw [state]
46 | (doseq [{:keys [pos-x pos-y]} state]
47 | (q/ellipse (+ pos-x (/ step-size 2)) (+ pos-y (/ step-size 2)) diameter diameter)))
48 |
49 | (defn run [host]
50 | (q/defsketch dumb-agents
51 | :host host
52 | :setup setup
53 | :draw draw
54 | :update update-state
55 | :middleware [md/fun-mode]
56 | :size [300 300]))
57 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_2_3_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-2-3-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def form-resolution 15)
6 | (def step-size 2)
7 | (def distortion-factor 1)
8 | (def init-radius 15)
9 |
10 | (defn setup []
11 | (q/stroke 0 50)
12 | (q/stroke-weight 0.75)
13 | (q/background 255)
14 | (let [angle (q/radians (/ 360 form-resolution))]
15 | {:center-x (/ (q/width) 2)
16 | :center-y (/ (q/height) 2)
17 | :x (for [i (range 0 form-resolution)] (* (q/cos (* angle i)) init-radius))
18 | :y (for [i (range 0 form-resolution)] (* (q/sin (* angle i)) init-radius))}))
19 |
20 | (defn update-state [state]
21 | (-> state
22 | (update :center-x #(+ % (* (- (q/mouse-x) %) 0.01)))
23 | (update :center-y #(+ % (* (- (q/mouse-y) %) 0.01)))
24 | (update :x #(for [i (range 0 form-resolution)] (+ (nth % i) (q/random (- step-size) step-size))))
25 | (update :y #(for [i (range 0 form-resolution)] (+ (nth % i) (q/random (- step-size) step-size))))))
26 |
27 | (defn draw [{:keys [x y center-x center-y]}]
28 | (q/begin-shape)
29 | (q/curve-vertex (+ (nth x (dec form-resolution)) center-x)
30 | (+ (nth y (dec form-resolution)) center-y))
31 | (doseq [i (range 0 form-resolution)]
32 | (q/curve-vertex (+ (nth x i) center-x) (+ (nth y i) center-y)))
33 | (q/curve-vertex (+ (nth x 0) center-x) (+ (nth y 0) center-y))
34 | (q/curve-vertex (+ (nth x 1) center-x) (+ (nth y 1) center-y))
35 | (q/end-shape))
36 |
37 | (defn mouse-pressed []
38 | (let [angle (q/radians (/ 360 form-resolution))
39 | radius (* init-radius (q/random 0.5 1))]
40 | {:center-x (q/mouse-x)
41 | :center-y (q/mouse-y)
42 | :x (for [i (range 0 form-resolution)] (* (q/cos (* angle i)) radius))
43 | :y (for [i (range 0 form-resolution)] (* (q/sin (* angle i)) radius))}))
44 |
45 | (defn run [host]
46 | (q/defsketch shapes-from-agent
47 | :host host
48 | :setup setup
49 | :draw draw
50 | :update update-state
51 | :mouse-pressed mouse-pressed
52 | :middleware [md/fun-mode]
53 | :size [300 300]))
54 |
55 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_2_4_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-2-4-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def max-count 500)
6 |
7 | (defn setup []
8 | (q/stroke-weight 0.5)
9 | {:current-count 1
10 | :x [(/ (q/width) 2)]
11 | :y [(/ (q/height) 2)]
12 | :r [10]})
13 |
14 | (defn update-state [{:keys [current-count x y r]}]
15 | (when (>= current-count max-count)
16 | (q/no-loop))
17 | (let [new-r (q/random 1 7)
18 | new-x (q/random new-r (- (q/width) new-r))
19 | new-y (q/random new-r (- (q/height) new-r))
20 | [_ closest-i]
21 | (reduce (fn [[closest-dist j] i]
22 | (let [new-dist (q/dist new-x new-y (nth x i) (nth y i))]
23 | (if (< new-dist closest-dist) [new-dist i] [closest-dist j])))
24 | [(.-MAX_VALUE js/Number) 0] (range 0 current-count))
25 | angle (q/atan2 (- new-y (nth y closest-i)) (- new-x (nth x closest-i)))]
26 | {:x (cons (+ (nth x closest-i) (* (q/cos angle) (+ (nth r closest-i) new-r))) x)
27 | :y (cons (+ (nth y closest-i) (* (q/sin angle) (+ (nth r closest-i) new-r))) y)
28 | :r (cons new-r r)
29 | :current-count (inc current-count)}))
30 |
31 | (defn draw [{:keys [x y r current-count]}]
32 | (q/clear)
33 | (q/fill 50)
34 | (doseq [i (range 0 current-count)]
35 | (q/ellipse (nth x i) (nth y i) (* (nth r i) 2) (* (nth r i) 2))))
36 |
37 | (defn run [host]
38 | (q/defsketch growth-structure-from-agents
39 | :host host
40 | :setup setup
41 | :draw draw
42 | :update update-state
43 | :middleware [md/fun-mode]
44 | :size [300 300]))
45 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_2_5_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-2-5-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def min-radius 3)
6 | (def max-radius 30)
7 |
8 | (defn setup []
9 | (q/no-fill)
10 | (q/rect-mode :radius)
11 | {:circles []})
12 |
13 | (defn update-state [{:keys [circles] :as state}]
14 | (let [new-x (q/random 0 (q/width))
15 | new-y (q/random 0 (q/height))]
16 | (assoc state :circles
17 | (loop [new-r max-radius]
18 | (if (> new-r min-radius)
19 | (let [overlapping? (some (fn [[x y r]] (< (q/dist new-x new-y x y) (+ r new-r))) circles)]
20 | (if overlapping?
21 | (recur (dec new-r))
22 | (conj circles [new-x new-y new-r])))
23 | circles)))))
24 |
25 | (defn draw [{:keys [circles]}]
26 | (q/background 255)
27 | (doseq [[x y r] circles]
28 | (q/stroke 0)
29 | (q/stroke-weight 1.5)
30 | (q/ellipse x y (* 2 r) (* 2 r))))
31 |
32 | (defn run [host]
33 | (q/defsketch structural-density-from-agents
34 | :host host
35 | :setup setup
36 | :draw draw
37 | :update update-state
38 | :middleware [md/fun-mode]
39 | :size [300 300]))
40 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_3_1_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-3-1-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | {:line-length 0
7 | :angle 0
8 | :angle-speed 1
9 | :c (q/color 181 157 0)})
10 |
11 | (defn update-state [state]
12 | (update state :angle + (:angle-speed state)))
13 |
14 | (defn draw [{:keys [c angle line-length]}]
15 | (when (and (q/mouse-pressed?) (= (q/mouse-button) :left))
16 | (q/push-matrix)
17 | (q/translate (q/mouse-x) (q/mouse-y))
18 | (q/rotate (q/radians angle))
19 | (q/stroke c)
20 | (q/line 0 0 line-length 0)
21 | (q/pop-matrix)))
22 |
23 | (defn mouse-pressed [state _]
24 | (assoc state :line-length (q/random 70 200)))
25 |
26 | (defn key-pressed [state {:keys [key]}]
27 | (case key
28 | :ArrowUp (update state :line-length + 5)
29 | :ArrowDown (update state :line-length - 5)
30 | :ArrowLeft (update state :angle-speed - 0.5)
31 | :ArrowRight (update state :angle-speed + 0.5)
32 | state))
33 |
34 | (defn key-released [state {:keys [key]}]
35 | (prn key)
36 | (case key
37 | :Backspace (do (q/background 255) state)
38 | :d (-> state
39 | (update :angle + 180)
40 | (update :angle-speed * -1))
41 | :space (assoc state :c (q/color (q/random 255) (q/random 255) (q/random 255) (q/random 80 100)))
42 | state))
43 |
44 | (defn run [host]
45 | (q/defsketch animated-brushes
46 | :host host
47 | :setup setup
48 | :draw draw
49 | :update update-state
50 | :mouse-pressed mouse-pressed
51 | :key-pressed key-pressed
52 | :key-released key-released
53 | :middleware [md/fun-mode]
54 | :size [300 300]))
55 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_3_3_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-3-3-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/background 255)
7 | (let [font "Georgia"]
8 | (q/text-font font)
9 | (q/text-align :left)
10 | (q/fill 0)
11 | (let [letters "All the worlds a stage, and all the men and women merely players. They have their exits and their entrances."]
12 | {:x (q/mouse-x)
13 | :y (q/mouse-y)
14 | :step-size 5.0
15 | :font font
16 | :letters letters
17 | :new-letter (first letters)
18 | :font-size-min 3
19 | :angle-distortion 0.0
20 | :counter 0
21 | :angle 0})))
22 |
23 | (defn update-state [{:keys [letters x y step-size counter font-size-min] :as state}]
24 | (let [d (q/dist x y (q/mouse-x) (q/mouse-y))]
25 | (q/text-size (+ font-size-min (/ d 2)))
26 | (if (and (q/mouse-pressed?) (= (q/mouse-button) :left) (> d step-size))
27 | (let [angle (q/atan2 (- (q/mouse-y) y) (- (q/mouse-x) x))
28 | counter (if (>= counter (dec (count letters))) 0 (inc counter))
29 | new-letter (nth letters counter)]
30 | (prn new-letter)
31 | (-> state
32 | (assoc :counter counter)
33 | (assoc :angle angle)
34 | (update :x (fn [x] (+ x (* (q/cos angle) step-size))))
35 | (update :y (fn [y] (+ y (* (q/sin angle) step-size))))
36 | (assoc :step-size (q/text-width new-letter))
37 | (assoc :new-letter new-letter)))
38 | state)))
39 |
40 | (defn draw [{:keys [x y font-size-min angle-distortion angle new-letter step-size]}]
41 | (when (and (q/mouse-pressed?) (= (q/mouse-button) :left))
42 | (let [d (q/dist x y (q/mouse-x) (q/mouse-y))]
43 | (q/text-size (+ font-size-min (/ d 2)))
44 | (when (> d step-size)
45 | (q/push-matrix)
46 | (q/translate x y)
47 | (q/rotate (+ angle (q/random angle-distortion)))
48 | (q/text new-letter 0 0)
49 | (q/pop-matrix)))))
50 |
51 | (defn mouse-pressed [state {:keys [x y]}]
52 | (assoc state :x x :y y))
53 |
54 | (defn run [host]
55 | (q/defsketch type-drawing
56 | :host host
57 | :setup setup
58 | :draw draw
59 | :update update-state
60 | :mouse-pressed mouse-pressed
61 | :middleware [md/fun-mode]
62 | :size [300 300]))
63 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_3_4_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-3-4-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/background 255)
7 | {:x (q/mouse-x)
8 | :y (q/mouse-y)
9 | :step-size 5
10 | :module-size 25
11 | :angle 0
12 | :d 0
13 | :line-module (q/load-image "images/dynamic-brush.svg")})
14 |
15 | (defn update-state [{:keys [x y step-size] :as state}]
16 | (if (and (q/mouse-pressed?) (= (q/mouse-button) :left))
17 | (let [d (q/dist x y (q/mouse-x) (q/mouse-y))]
18 | (if (> d step-size)
19 | (let [angle (q/atan2 (- (q/mouse-y) y) (- (q/mouse-x) x))]
20 | (-> state
21 | (assoc :d d)
22 | (assoc :angle angle )
23 | (update :x + (* (q/cos angle) step-size))))
24 | state))
25 | state))
26 |
27 | (defn draw [{:keys [angle line-module module-size d] :as state}]
28 |
29 | (when (and (q/mouse-pressed?) (= (q/mouse-button) :left))
30 | (q/push-matrix)
31 | (q/translate (q/mouse-x) (q/mouse-y))
32 | (q/rotate (+ angle q/PI))
33 | (when (q/loaded? line-module) (q/image line-module 0 0 d module-size))
34 | (q/pop-matrix)))
35 |
36 | (defn mouse-pressed [state {:keys [x y]}]
37 | (assoc state :x x :y y))
38 |
39 | (defn run [host]
40 | (q/defsketch dynamic-brushes
41 | :host host
42 | :setup setup
43 | :draw draw
44 | :update update-state
45 | :mouse-pressed mouse-pressed
46 | :middleware [md/fun-mode]
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_3_6_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-3-6-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def tile-size 30)
6 |
7 | (defn setup []
8 | (q/rect-mode :center)
9 | (q/image-mode :center)
10 | (q/stroke-weight 0.15)
11 | (q/text-size 8)
12 | (q/text-align :center :center)
13 | (let [grid-resolution-x (+ (Math/round (/ (q/width) tile-size)) 2)
14 | grid-resolution-y (+ (Math/round (/ (q/height) tile-size)) 2)]
15 | {:grid-resolution-x grid-resolution-x
16 | :grid-resolution-y grid-resolution-y
17 | :tiles (->> 0 (repeat grid-resolution-x) vec (repeat grid-resolution-y) vec)
18 | :modules (map #(q/load-image (str "images/" (.padStart (str %) 2 "0") ".svg")) (range 16))}))
19 |
20 | (defn update-state [{:keys [ grid-resolution-x grid-resolution-y] :as state}]
21 | (if (and (q/mouse-pressed?) (= (q/mouse-button) :left))
22 | (let [x (+ (q/floor (/ (q/mouse-x) tile-size)) 1)
23 | grid-x (q/constrain x 1 (- grid-resolution-x 2))
24 | y (+ (q/floor (/ (q/mouse-y) tile-size)) 1)
25 | grid-y (q/constrain y 1 (- grid-resolution-y 2))]
26 | (case (q/mouse-button)
27 | :left (update state :tiles assoc-in [grid-x grid-y] 1)
28 | :right (update state :tiles assoc-in [grid-x grid-y] 0)
29 | state))
30 | state))
31 |
32 | (defn draw [{:keys [grid-resolution-x grid-resolution-y tiles modules]}]
33 | (q/background 255)
34 | (doseq [grid-x (range grid-resolution-x)
35 | grid-y (range grid-resolution-y)]
36 | (let [pos-x (- (* tile-size grid-x) (/ tile-size 2))
37 | pos-y (- (* tile-size grid-y) (/ tile-size 2))]
38 | (when (= (nth (nth tiles grid-x) grid-y) 1)
39 | (let [north (str (nth (nth tiles grid-x) (dec grid-y)))
40 | west (nth (nth tiles (dec grid-x)) grid-y)
41 | south (nth (nth tiles grid-x) (inc grid-y))
42 | east (nth (nth tiles (inc grid-x)) grid-y)
43 | binary-result (str north west south east)
44 | decimal-result (.parseInt js/window binary-result 2)]
45 | (q/image (nth modules decimal-result) pos-x pos-y tile-size tile-size))))))
46 |
47 | (defn run [host]
48 | (q/defsketch complex-modules
49 | :host host
50 | :setup setup
51 | :draw draw
52 | :update update-state
53 | :middleware [md/fun-mode]
54 | :size [300 300]))
55 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_02/P_2_3_7_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-02.P-2-3-7-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/no-fill)
7 | (let [img (q/create-graphics (q/width) (q/height))]
8 | (.pixelDensity img 1)
9 | {:line-color (q/color 0)
10 | :img img
11 | :pen-count 1}))
12 |
13 | (defn update-state [state]
14 | state)
15 |
16 | (defn draw [{:keys [img line-color pen-count]}]
17 | (q/background 255)
18 | (q/with-graphics img
19 | (q/stroke-weight 3)
20 | (q/stroke line-color)
21 | (when (and (q/mouse-pressed?) (= (q/mouse-button) :left))
22 | (let [w (q/width)
23 | h (q/height)
24 | x (q/mouse-x)
25 | y (q/mouse-y)
26 | px (- x (- (q/mouse-x) (q/pmouse-x)))
27 | py (- y (- (q/mouse-y) (q/pmouse-y)))]
28 | (q/line x y px py)
29 | (q/line (- w x) y (- w px) py)
30 | (q/line x (- h y) px (- h py))
31 | (q/line (- w x) (- h y) (- w px) (- h py))
32 | (q/line y x py px)
33 | (q/line y (- w x) py (- w px))
34 | (q/line (- h y) x (- h py) px)
35 | (q/line (- h y) (- w x) (- h py) (- w px)))))
36 | (q/image img 0 0))
37 |
38 | (defn run [host]
39 | (q/defsketch multiple-brushes
40 | :host host
41 | :setup setup
42 | :draw draw
43 | :update update-state
44 | :middleware [md/fun-mode]
45 | :size [300 300]))
46 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_03/P_3_0_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-03.P-3-0-01
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/background 255)
7 | (q/fill 0)
8 | (q/text-font "sans-serif")
9 | (q/text-align :center :center)
10 | {:letter "A"})
11 |
12 | (defn mouse-moved [state _]
13 | (q/clear)
14 | (q/text-size (+ (* (- (q/mouse-x) (/ (q/width) 2)) 5) 1))
15 | (q/text (:letter state) (/ (q/width) 2) (q/mouse-y))
16 | state)
17 |
18 | (defn mouse-dragged [state _]
19 | (q/text-size (+ (* (- (q/mouse-x) (/ (q/width) 2)) 5) 1))
20 | (q/text (:letter state) (/ (q/width) 2) (q/mouse-y))
21 | state)
22 |
23 | (defn key-typed [state {:keys [raw-key]}]
24 | (assoc state :letter raw-key))
25 |
26 | (defn run [host]
27 | (q/defsketch hello-type
28 | :host host
29 | :setup setup
30 | :mouse-moved mouse-moved
31 | :mouse-dragged mouse-dragged
32 | :key-typed key-typed
33 | :middleware [md/fun-mode]
34 | :size [300 300]))
35 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_03/P_3_1_3_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-03.P-3-1-3-01
2 | (:require [clojure.string :as s]
3 | [quil.core :as q :include-macros true]
4 | [quil.middleware :as md]))
5 |
6 | (def text (atom ""))
7 | (-> (.fetch js/window "data/faust_kurz.txt")
8 | (.then #(.text %))
9 | (.then #(reset! text %)))
10 |
11 | (def alphabet "ABCDEFGHIJKLMNORSTUVWYZÄÖÜß,.;!? ")
12 |
13 |
14 | (defn setup []
15 | {:counts (frequencies @text)
16 | :text @text})
17 |
18 | (defn update-state [state]
19 | state)
20 |
21 | (defn draw [{:keys [text counts]}]
22 | (q/clear)
23 |
24 | (q/text-size 11)
25 | (let [padding-left 15]
26 | (loop [x padding-left
27 | idx 0
28 | y 15]
29 | (let [char (nth text idx)
30 | m (q/constrain (q/map-range (q/mouse-x) 50 (- (q/width) 50) 0 1) 0 1)
31 | alph-idx (.indexOf alphabet (s/upper-case char))
32 | inter-y (q/lerp y (+ 15 (* alph-idx 20)) m)]
33 | (q/fill 87 35 129 (* (counts char) 3))
34 | (q/text char x inter-y)
35 | (when (< idx (dec (count text)))
36 | (let [new-x (+ x (q/text-width char))
37 | new-line? (and (> new-x (- (q/width) 65)) (= char " "))]
38 | (recur (if new-line? padding-left new-x)
39 | (inc idx)
40 | (if new-line? (+ 20 y) y))))))))
41 |
42 | (defn run [host]
43 | (q/defsketch text-frequencies
44 | :host host
45 | :setup setup
46 | :draw draw
47 | :update update-state
48 | :middleware [md/fun-mode]
49 | :size [300 300]))
50 |
--------------------------------------------------------------------------------
/src/sketches/generative_desgin/P_03/P_3_1_4_01.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.generative-desgin.P-03.P-3-1-4-01
2 | (:require [clojure.string :as s]
3 | [quil.core :as q :include-macros true]
4 | [quil.middleware :as md]))
5 |
6 | (def text (atom ""))
7 | (-> (.fetch js/window "data/pride_and_prejudice.txt")
8 | (.then #(.text %))
9 | (.then #(reset! text %)))
10 |
11 | (defn setup []
12 | (q/text-align :center :baseline)
13 | (let [words (re-seq #"\w+" @text)
14 | treemap (new js/gd.Treemap 1 1 297 297 #js{:sort true :direction "both"})]
15 | (doseq [word words]
16 | (.addData treemap (s/lower-case word)))
17 | (.calculate treemap)
18 | {:treemap treemap}))
19 |
20 | (defn update-state [state]
21 | state)
22 |
23 | (defn draw [{:keys [treemap]}]
24 | (doseq [item (.-items treemap)]
25 | (q/fill 255)
26 | (q/stroke 0)
27 | (q/rect ^js (.-x item) ^js (.-y item) ^js (.-w item) ^js (.-h item))
28 | (let [word (.-data item)
29 | text-width (q/text-width word)
30 | max-font-size (/ (* 100 (* (.-w item) 0.9)) text-width)
31 | font-size (js/Math.min max-font-size (* ^js (.-h item) 0.9))]
32 | (q/text-size font-size)
33 | (q/fill 0)
34 | (q/no-stroke)
35 | (q/text word (+ ^js (.-x item) (/ ^js (.-w item) 2)) (+ ^js (.-y item) (* ^js (.-h item) 0.8)))))
36 | (q/no-loop))
37 |
38 | (defn run [host]
39 | (q/defsketch text-treemap
40 | :host host
41 | :setup setup
42 | :draw draw
43 | :update update-state
44 | :middleware [md/fun-mode]
45 | :size [300 300]))
46 |
--------------------------------------------------------------------------------
/src/sketches/icons.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.icons)
2 |
3 | ;; TODO Create macro for generating new icons
4 | (defn icon [path size color]
5 | (let [sizes {:small 12 :medium 24 :large 48}]
6 | [:svg {:width (size sizes) :height (size sizes) :viewBox "0 0 24 24"}
7 | [:path {:d path :fill color}]]))
8 |
9 | (defn play-icon
10 | ([] (icon "M3 22v-20l18 10-18 10z" :medium "black"))
11 | ([size] (icon "M3 22v-20l18 10-18 10z" size "black"))
12 | ([size color] (icon "M3 22v-20l18 10-18 10z" size color)))
13 |
14 | (defn pause-icon
15 | ([] (icon "M11 22h-4v-20h4v20zm6-20h-4v20h4v-20z" :medium "black"))
16 | ([size] (icon "M11 22h-4v-20h4v20zm6-20h-4v20h4v-20z" size "black"))
17 | ([size color] (icon "M11 22h-4v-20h4v20zm6-20h-4v20h4v-20z" size color)))
18 |
19 | (defn stop-icon
20 | ([] (icon "M2 2h20v20h-20z" :medium "black"))
21 | ([size] (icon "M2 2h20v20h-20z" size "black"))
22 | ([size color] (icon "M2 2h20v20h-20z" size color)))
23 |
24 | (defn reload-icon
25 | ([] (icon "M13.5 2c-5.629 0-10.212 4.436-10.475 10h-3.025l4.537 5.917 4.463-5.917h-2.975c.26-3.902 3.508-7 7.475-7 4.136 0 7.5 3.364 7.5 7.5s-3.364 7.5-7.5 7.5c-2.381 0-4.502-1.119-5.876-2.854l-1.847 2.449c1.919 2.088 4.664 3.405 7.723 3.405 5.798 0 10.5-4.702 10.5-10.5s-4.702-10.5-10.5-10.5z" :medium "black"))
26 | ([size] (icon "M13.5 2c-5.629 0-10.212 4.436-10.475 10h-3.025l4.537 5.917 4.463-5.917h-2.975c.26-3.902 3.508-7 7.475-7 4.136 0 7.5 3.364 7.5 7.5s-3.364 7.5-7.5 7.5c-2.381 0-4.502-1.119-5.876-2.854l-1.847 2.449c1.919 2.088 4.664 3.405 7.723 3.405 5.798 0 10.5-4.702 10.5-10.5s-4.702-10.5-10.5-10.5z" size "black"))
27 | ([size color] (icon "M13.5 2c-5.629 0-10.212 4.436-10.475 10h-3.025l4.537 5.917 4.463-5.917h-2.975c.26-3.902 3.508-7 7.475-7 4.136 0 7.5 3.364 7.5 7.5s-3.364 7.5-7.5 7.5c-2.381 0-4.502-1.119-5.876-2.854l-1.847 2.449c1.919 2.088 4.664 3.405 7.723 3.405 5.798 0 10.5-4.702 10.5-10.5s-4.702-10.5-10.5-10.5z" size color)))
28 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/cellular_automata/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.cellular-automata.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.cellular-automata.game-of-life :as gl]
4 | [sketches.nature-of-code.cellular-automata.random-cellular-automaton
5 | :as
6 | rca]))
7 |
8 | (defn main []
9 | [:div
10 | [:h3.tracked.tc.tl-ns "Cellular Automata"]
11 | [cards-container
12 | [:<>
13 | [exercise-card "Random CA" "Exercise 7.1" "https://natureofcode.com/book/chapter-7-cellular-automata/#chapter07_exercise1" rca/run]
14 | [exercise-card "Game of Life" "Exercise 7.6" "https://natureofcode.com/book/chapter-7-cellular-automata/#chapter07_exercise6" gl/run]]]])
15 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/cellular_automata/game_of_life.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.cellular-automata.game-of-life
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup-board []
6 | (let [w 5
7 | columns (/ (q/width) w)
8 | rows (/ (q/height) w)]
9 | (for [x (range 0 columns)]
10 | (for [y (range 0 rows)]
11 | (rand-int 2)))))
12 |
13 | (defn setup []
14 | (q/stroke 0)
15 | {:board (setup-board)})
16 |
17 | (defn board []
18 | (let [w 5
19 | columns (/ 50 w)
20 | rows (/ 50 w)]
21 | (for [x (range 0 columns)]
22 | (for [y (range 0 rows)]
23 | (rand-int 2)))))
24 |
25 | (defn update-state [{:keys [board] :as state}]
26 | (assoc state :board
27 | (for [x (range 0 (count board))]
28 | (for [y (range 0 (count (nth board x)))]
29 | (let [neighbour-count (-
30 | (reduce +
31 | (for [i (range -1 2)
32 | j (range -1 2)]
33 | (nth (nth board (+ x i) ()) (+ y j) 0)))
34 | 1)]
35 | (let [current (nth (nth board x) y)]
36 | (cond
37 | (and (= current 1) (< neighbour-count 2)) 0
38 | (and (= current 1) (> neighbour-count 3)) 0
39 | (and (= current 0) (= neighbour-count 3)) 1
40 | :else current)))))))
41 |
42 | (defn update-board [x y board]
43 | (map sequence
44 | (assoc-in (into [] (map #(into [] %) board)) [x y] 1)))
45 |
46 | (defn draw [{:keys [board]}]
47 | (let [updated-board
48 | (if (q/mouse-pressed?)
49 | (update-board (q/floor (/ (q/mouse-x) 5)) (q/floor (/ (q/mouse-y) 5)) board)
50 | board)]
51 | (doseq [x (range 0 (count updated-board))
52 | y (range 0 (count (nth updated-board x)))]
53 | (do
54 | (if (= (nth (nth updated-board x) y) 1)
55 | (q/fill 0)
56 | (q/fill 255))
57 | (q/rect (* x 5) (* y 5) 5 5)))))
58 |
59 | (defn mouse-clicked [{:keys [board] :as state} {:keys [x y]}]
60 | (update state :board (fn [board] (update-board (q/floor (/ x 5)) (q/floor (/ y 5)) board))))
61 |
62 | (defn run [host]
63 | (q/defsketch game-of-life
64 | :host host
65 | :setup setup
66 | :draw draw
67 | :update update-state
68 | :mouse-clicked mouse-clicked
69 | :middleware [md/fun-mode]
70 | :size [300 300]))
71 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/cellular_automata/random_cellular_automaton.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.cellular-automata.random-cellular-automaton
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup-cells []
6 | (let [w 5
7 | cell-count (/ (q/width) w)]
8 | (map-indexed (fn [idx x] (if (= idx (q/ceil (/ cell-count 2))) 1 0))
9 | (range cell-count))))
10 |
11 | (defn setup []
12 | {:cells (setup-cells)
13 | :ruleset [0 1 0 1 1 0 1 0]
14 | :generation 0})
15 |
16 | (defn rules [ruleset a b c]
17 | (get ruleset (q/unbinary (str a b c))))
18 |
19 | (defn reset-state [state]
20 | (-> state
21 | (assoc :generation 0)
22 | (assoc :cells (setup-cells))
23 | (assoc :ruleset (into [] (map (fn [x] (q/round (q/random 1))) (range 8))))))
24 |
25 | (defn update-automata [{:keys [cells ruleset] :as state}]
26 | (-> state
27 | (assoc :cells (map-indexed (fn [idx x]
28 | (cond (= idx 0) 0
29 | (= idx (- (count cells) 1)) 0
30 | :else (rules ruleset
31 | (nth cells (dec idx))
32 | (nth cells idx)
33 | (nth cells (inc idx)))))
34 | cells))
35 | (update :generation inc)))
36 |
37 | (defn update-state [{:keys [generation] :as state}]
38 | (if (> generation (/ (q/height) 5))
39 | (reset-state state)
40 | (update-automata state)))
41 |
42 | (defn draw [{:keys [cells generation]}]
43 | (doall
44 | (map-indexed
45 | (fn [idx cell]
46 | (if (= cell 1) (q/fill 0) (q/fill 255))
47 | (q/rect (* idx 5) (* 5 generation) 5 5))
48 | cells)))
49 |
50 | (defn run [host]
51 | (q/defsketch random-ca
52 | :host host
53 | :setup setup
54 | :draw draw
55 | :update update-state
56 | :middleware [md/fun-mode]
57 | :size [300 300]))
58 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.core
2 | (:require [sketches.components :refer [section]]
3 | [sketches.nature-of-code.introduction.core :as introduction]
4 | [sketches.nature-of-code.oscillation.core :as oscillation]
5 | [sketches.nature-of-code.cellular-automata.core :as cellular-automata]
6 | [sketches.nature-of-code.forces.core :as forces]
7 | [sketches.nature-of-code.vectors.core :as vectors]
8 | [sketches.nature-of-code.particle-systems.core :as particle-systems]
9 | [sketches.nature-of-code.physics-library.core :as physics-library]
10 | [sketches.nature-of-code.fractals.core :as fractals]))
11 |
12 | (defn main []
13 | [:<>
14 | [section
15 | "Nature of Code"
16 | [:<>
17 | "Exercises of "
18 | [:a.pointer.bb.link.white {:href "https://twitter.com/shiffman"} "Daniel Shiffman's"] " "
19 | [:a.pointer.bb.link.white {:href "https://natureofcode.com/"} "Nature of Code"]
20 | " implemented in ClojureScript."]]
21 | [introduction/main]
22 | [vectors/main]
23 | [forces/main]
24 | [oscillation/main]
25 | [particle-systems/main]
26 | [physics-library/main]
27 | [cellular-automata/main]
28 | [fractals/main]])
29 |
30 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/balloon.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.balloon
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn setup []
7 | {:location [(/ (q/width) 2) (/ (q/height) 2)]
8 | :velocity [0 0]
9 | :xoff 0.001})
10 |
11 | (defn keep-inside [[x y]]
12 | [(if (> x (q/width)) (q/width) (if (< x 0) 0 x))
13 | (if (> y (q/height)) (q/height) (if (< y 0) 0 y))])
14 |
15 | (defn is-stopped [{[_ y] :location [_ vy] :velocity}] (and (<= vy 0.02) (= y 0)))
16 |
17 | (defn update-state [state]
18 | (let [{:keys [xoff velocity location acceleration]} state
19 | gravity [0 -0.05]
20 | acceleration [(q/map-range (q/noise xoff) 0 1 -0.05 0.05) 0]
21 | velocity (v/add gravity (v/add velocity acceleration))
22 | location (keep-inside (v/add velocity location))]
23 | (update
24 | {:velocity (cond (<= (second location) 0) [0 (- (/ (second velocity) 2))]
25 | (is-stopped state) [0 0]
26 | :else velocity)
27 | :location (if (is-stopped state) [(/ (q/width) 2) (/ (q/height) 2)] location)
28 | :xoff (+ xoff 0.001)}
29 | :location
30 | keep-inside)))
31 |
32 | (defn draw [{[x y] :location}]
33 | (q/background 255)
34 | (q/fill 255 0 0)
35 | (q/line x (+ y 32) x (+ y 100))
36 | (q/ellipse x y 45 64))
37 |
38 | (defn run [host]
39 | (q/defsketch balloon
40 | :host host
41 | :setup setup
42 | :draw draw
43 | :update update-state
44 | :middleware [md/fun-mode]
45 | :size [300 300]))
46 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.forces.balloon :as b]
4 | [sketches.nature-of-code.forces.fluid :as fl]
5 | [sketches.nature-of-code.forces.force-push :as fp]
6 | [sketches.nature-of-code.forces.frictions :as fr]
7 | [sketches.nature-of-code.forces.invisible-attractors :as ia]
8 | [sketches.nature-of-code.forces.own-force :as of]
9 | [sketches.nature-of-code.forces.repulse-mouse :as rm]
10 | [sketches.nature-of-code.forces.surface-area :as sa]))
11 |
12 | (defn main []
13 | [:div
14 | [:h3.tracked.tc.tl-ns "Forces"]
15 | [cards-container
16 | [:<>
17 | [exercise-card "Balloon" "Exercise 2.1" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise1" b/run]
18 | [exercise-card "Force Push" "Exercise 2.3" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise3" fp/run]
19 | [exercise-card "Frictions" "Exercise 2.4" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise4" fr/run]
20 | [exercise-card "Fluid" "Exercise 2.5" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise5" fl/run]
21 | [exercise-card "Surface Area" "Exercise 2.6" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise6" sa/run]
22 | ;; Fluid resistance does not only work opposite to the velocity vector, but also perpendicular to it. This is known as “lift-induced drag” and will cause an airplane with an angled wing to rise in altitude. Try creating a simulation of lift.
23 | #_[exercise-card "Lift-induced Drag" "Exercise 2.7" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise7" ld/run true]
24 | [exercise-card "Invisible Attractors" "Exercise 2.8" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise8" ia/run]
25 | [exercise-card "Own Force" "Exercise 2.9" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise9" of/run]
26 | [exercise-card "Repulse Mouse" "Exercise 2.10" "https://natureofcode.com/book/chapter-2-forces#chapter02_exercise10" rm/run]]]])
27 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/fluid.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.fluid
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn setup []
8 | (map
9 | (fn [i] {:mass (+ 1 (rand-int 50))
10 | :location [(* i 50) (* i 50)]
11 | :velocity [0 0]
12 | :acceleration [0 0]})
13 | (range (/ (q/width) 50))))
14 |
15 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
16 | (let [velocity (v/add acceleration velocity)
17 | location (v/add velocity location)]
18 | (-> mover
19 | (assoc :acceleration [0 0])
20 | (assoc :velocity velocity)
21 | (assoc :location location))))
22 |
23 | (defn liquid [x y w h c]
24 | {:location [x y]
25 | :size [w h]
26 | :c c})
27 |
28 | (defn gravity [{:keys [mass]}]
29 | (vector 0 (* 0.1 mass)))
30 |
31 | (defn drag [mover liquid]
32 | (let [{[x y] :location :keys [velocity]} mover
33 | {:keys [c location]} liquid
34 | speed (v/mag velocity)]
35 | (if (> y (second location))
36 | (v/mult (v/normalize (v/mult velocity -1))
37 | (* c speed speed))
38 | [0 0])))
39 |
40 | (defn update-mover [mover]
41 | (-> mover
42 | (m/apply-force (gravity mover))
43 | (m/apply-force (drag mover (liquid 0 (/ (q/height) 2) (q/width) (/ (q/height) 2) 1)))
44 | compute-position
45 | m/keep-inside))
46 |
47 | (defn update-state [movers]
48 | (map update-mover movers))
49 |
50 | (defn draw [movers]
51 | (q/clear)
52 | (q/background 255)
53 | (q/fill 50 100 255)
54 | (q/rect 0 (/ (q/height) 2) (q/width) (/ (q/height) 2))
55 | (q/fill 255 0 255)
56 | (doseq [{:keys [mass velocity] [x y] :location} movers]
57 | (q/ellipse x y mass mass)))
58 |
59 | (defn run [host]
60 | (q/defsketch fluid
61 | :host host
62 | :setup setup
63 | :draw draw
64 | :update update-state
65 | :middleware [md/fun-mode]
66 | :size [300 300]))
67 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/force_push.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.force-push
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn create-mover []
8 | {:location [0 0]
9 | :velocity [0 0]
10 | :mass (q/random 10 40)})
11 |
12 | (defn setup []
13 | (map create-mover (range 0 20)))
14 |
15 | (defn push-back [{[x y] :location :as mover}]
16 | [(cond (> x (q/width)) -1
17 | (< x 0) 1
18 | :else 0)
19 | (cond (> y (q/height)) -1
20 | (< y 0) 1
21 | :else 0)])
22 |
23 | (defn update-mover [{:keys [mass] :as mover}]
24 | (let [wind [0.03 0]
25 | gravity [0 0.5]]
26 | (-> mover
27 | (m/update-mover (v/add (v/div gravity mass)
28 | (v/div wind mass)
29 | (v/div (push-back mover) mass))))))
30 |
31 | (defn update-state [state]
32 | (map update-mover state))
33 |
34 | (defn draw-mover [{[x y] :location :keys [mass]}]
35 | (q/ellipse x y mass mass))
36 |
37 | (defn draw [state]
38 | (q/clear)
39 | (doall (map draw-mover state)))
40 |
41 | (defn run [host]
42 | (q/defsketch force-push
43 | :host host
44 | :setup setup
45 | :draw draw
46 | :update update-state
47 | :middleware [md/fun-mode]
48 | :size [300 300]))
49 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/frictions.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.frictions
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn setup []
8 | {:movers (doall (map
9 | (fn [mover] {:mass (+ 1 (rand-int 50))
10 | :location [0 0]
11 | :velocity [0 0]
12 | :acceleration [0 0]})
13 | (range 50)))
14 | :friction-areas (map
15 | (fn [i]
16 | (let [width (/ (q/width) 5)
17 | colors [[0 0 255] [0 255 0] [255 255 0] [0 255 255] [255 0 0]]]
18 | {:x (* i width)
19 | :width width
20 | :color (get colors i)
21 | :friction (q/random 0.01 0.2)}))
22 | (range 5))})
23 |
24 | (defn gravity [{:keys [mass]}]
25 | (vector 0 (* 0.1 mass)))
26 |
27 | (defn compute-friction [friction {:keys [velocity]}]
28 | (-> velocity
29 | (v/mult -1)
30 | v/normalize
31 | (v/mult (or friction 0.01))))
32 |
33 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
34 | (let [velocity (v/add acceleration velocity)
35 | location (v/add location velocity)
36 | acceleration (v/mult acceleration 0)]
37 | (-> mover
38 | (assoc :velocity velocity)
39 | (assoc :location location)
40 | (assoc :acceleration acceleration))))
41 |
42 | (defn update-mover [mover friction]
43 | (let [wind [0.1 0]]
44 | (-> mover
45 | (m/apply-force wind)
46 | (m/apply-force (gravity mover))
47 | (m/apply-force (compute-friction friction mover))
48 | compute-position
49 | m/check-edges)))
50 |
51 | (defn update-state [{:keys [movers friction-areas] :as state}]
52 | {:movers (doall (map
53 | (fn [mover]
54 | (let [friction (:friction (first (filter
55 | #(< (:x %) (first (:location mover)))
56 | (reverse friction-areas))))]
57 | (update-mover mover friction)))
58 | movers))
59 | :friction-areas friction-areas})
60 |
61 | (defn draw-friction-area [{:keys [x width color friction]}]
62 | (apply q/fill color)
63 | (q/rect x 0 width (q/height)))
64 |
65 | (defn draw [{:keys [movers friction-areas]}]
66 | (q/clear)
67 | (doseq [friction-area friction-areas]
68 | (draw-friction-area friction-area))
69 | (q/fill 255 0 255)
70 | (doseq [{:keys [mass] [x y] :location} movers]
71 | (q/ellipse x y mass mass)))
72 |
73 | (defn run [host]
74 | (q/defsketch frictions
75 | :host host
76 | :setup setup
77 | :draw draw
78 | :update update-state
79 | :middleware [md/fun-mode]
80 | :size [300 300]))
81 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/invisible_attractors.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.invisible-attractors
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
8 | (let [velocity (v/add acceleration velocity)
9 | location (v/add velocity location)]
10 | (-> mover
11 | (assoc :acceleration [0 0])
12 | (assoc :velocity velocity)
13 | (assoc :location location))))
14 |
15 | (defn setup []
16 | {:movers (map (fn [x] {:mass (+ 1 (rand-int 50))
17 | :location [(rand-int (q/width)) (rand-int (q/height))]
18 | :velocity [0 0]
19 | :acceleration [0 0]})
20 | (range 0 10))
21 | :attractors (map (fn [x]
22 | {:mass (rand-int 20)
23 | :location [(rand-int (q/width)) (rand-int (q/height))]})
24 | (range 0 5))})
25 |
26 | (defn attract [mover attractor]
27 | (let [{loc1 :location} attractor
28 | {loc2 :location} mover
29 | vectorBetween (v/sub loc1 loc2)
30 | distanceBetween (q/constrain (v/mag vectorBetween) 5.0 25.0)
31 | G 0.4
32 | strength (/ (* G (:mass attractor) (:mass mover)) (* distanceBetween distanceBetween))]
33 | (v/mult (v/normalize vectorBetween) strength)))
34 |
35 | (defn update-mover [attractors mover]
36 | (compute-position
37 | (reduce #(m/apply-force mover (attract %1 %2)) mover attractors)))
38 |
39 | (defn update-state [{:keys [attractors] :as state}]
40 | (update state :movers (partial map (partial update-mover attractors))))
41 |
42 | (defn draw [{:keys [movers]}]
43 | (q/clear)
44 | (q/background 255)
45 | (doseq [{:keys [mass] [x y] :location} movers]
46 | (q/ellipse x y mass mass)))
47 |
48 | (defn run [host]
49 | (q/defsketch invisible-attractors
50 | :host host
51 | :setup setup
52 | :draw draw
53 | :update update-state
54 | :middleware [md/fun-mode]
55 | :size [300 300]))
56 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/lift_induced_drag.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.lift-induced-drag
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn setup []
8 | {:movers (map
9 | (fn [i]
10 | {:mass (+ 1 (rand-int 50))
11 | :location [(* i 50) 0]
12 | :velocity [0 0]
13 | :acceleration [0 0]})
14 | (range 50))
15 | :liquid {:location [0 (/ (q/height) 2)]
16 | :size [(q/width) (/ (q/height) 2)]
17 | :c 0.1}})
18 |
19 | (defn draw [{:keys [movers]}]
20 | (q/clear)
21 | (q/background 255)
22 | (q/fill 50 100 255)
23 | (q/rect 0 (/ (q/height) 2) (q/width) (/ (q/height) 2))
24 | (q/fill 255 0 255)
25 | (doseq [{:keys [mass] [x y] :location} movers]
26 | (q/rect x (- y mass) mass mass)))
27 |
28 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
29 | (let [velocity (v/add acceleration velocity)
30 | location (v/add velocity location)]
31 | (-> mover
32 | (assoc :acceleration [0 0])
33 | (assoc :velocity velocity)
34 | (assoc :location location))))
35 |
36 | (defn gravity [{:keys [mass]}]
37 | [0 (* 0.1 mass)])
38 |
39 | (defn drag [{[x y] :location :keys [velocity mass]}
40 | {:keys [c location]}]
41 | (let [speed (v/mag velocity)
42 | drag-magnitude (* c speed speed)
43 | A mass]
44 | (if (> y (second location))
45 | (v/mult (v/mult (v/normalize (v/mult velocity -1)) drag-magnitude) A)
46 | [0 0])))
47 |
48 | (defn update-mover [liquid mover]
49 | (-> mover
50 | (m/apply-force (gravity mover))
51 | (m/apply-force (drag mover liquid))
52 | compute-position
53 | m/keep-inside))
54 |
55 | (defn update-state [state]
56 | (update state :movers #(map (partial update-mover (:liquid state)) %)))
57 |
58 | (defn run [host]
59 | (q/defsketch lift-induced-drag
60 | :host host
61 | :setup setup
62 | :draw draw
63 | :update update-state
64 | :middleware [md/fun-mode]
65 | :size [300 300]))
66 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/own_force.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.own-force
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
8 | (let [velocity (v/add acceleration velocity)
9 | location (v/add velocity location)]
10 | (-> mover
11 | (assoc :acceleration [0 0])
12 | (assoc :velocity velocity)
13 | (assoc :location location))))
14 |
15 | (defn setup []
16 | {:movers (map (fn [x] {:mass (+ 1 (rand-int 50))
17 | :location [(rand-int 500) (rand-int 500)]
18 | :velocity [0 0]
19 | :acceleration [0 0]})
20 | (range 0 10))
21 | :attractors (map (fn [x] {:mass (rand-int 20)
22 | :location [(rand-int 500) (rand-int 500)]})
23 | (range 0 5))})
24 |
25 | (defn attract [mover attractor]
26 | (let [{loc1 :location} attractor
27 | {loc2 :location} mover
28 | vectorBetween (v/sub loc1 loc2)
29 | distanceBetween (q/constrain (v/mag vectorBetween) 5.0 25.0)
30 | G 0.4
31 | strength (/ (* distanceBetween distanceBetween) (* G (:mass attractor) (:mass mover)))]
32 | (v/mult (v/normalize vectorBetween) strength)))
33 |
34 | (defn update-mover [attractors mover]
35 | (compute-position
36 | (reduce #(m/apply-force %1 (attract %1 %2)) mover attractors)))
37 |
38 | (defn update-state [{:keys [movers attractors] :as state}]
39 | (update state :movers (partial map (partial update-mover attractors))))
40 |
41 | (defn draw [{:keys [attractors movers]}]
42 | (q/clear)
43 | (q/background 255)
44 | (doseq [{:keys [mass] [x y] :location} movers]
45 | (q/ellipse x y mass mass))
46 | (doseq [{:keys [mass] [x y] :location} attractors]
47 | (q/rect x y mass mass)))
48 |
49 | (defn run [host]
50 | (q/defsketch own-force
51 | :host host
52 | :setup setup
53 | :draw draw
54 | :update update-state
55 | :middleware [md/fun-mode]
56 | :size [300 300]))
57 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/repulse_mouse.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.repulse-mouse
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
8 | (let [velocity (v/add acceleration velocity)
9 | location (v/add velocity location)]
10 | (-> mover
11 | (assoc :acceleration [0 0])
12 | (assoc :velocity velocity)
13 | (assoc :location location))))
14 |
15 | (defn attract [mover attractor]
16 | (let [{loc1 :location} attractor
17 | {loc2 :location} mover
18 | vectorBetween (v/sub loc1 loc2)
19 | distanceBetween (q/constrain (v/mag vectorBetween) 5.0 25.0)
20 | G 0.4
21 | strength (/ (* G (:mass attractor) (:mass mover)) (* distanceBetween distanceBetween))]
22 | (v/mult (v/normalize vectorBetween) strength)))
23 |
24 | (defn repulse [mover attractor]
25 | (let [{loc1 :location} attractor
26 | {loc2 :location} mover
27 | vectorBetween (v/sub loc1 loc2)
28 | distanceBetween (q/constrain (v/mag vectorBetween) 5.0 25.0)
29 | G 0.0001
30 | strength (/ (* G (:mass attractor) (:mass mover)) (* distanceBetween distanceBetween))]
31 | (v/mult (v/mult (v/normalize vectorBetween) strength) -1)))
32 |
33 | (defn setup []
34 | {:movers (map (fn [x] {:mass (+ 10 (rand-int 50))
35 | :location [(rand-int 500) (rand-int 500)]
36 | :velocity [0 0]
37 | :acceleration [0 0]})
38 | (range 0 10))})
39 |
40 | (defn update-mover [movers mover]
41 | (let [mouse {:mass 100 :location [(q/mouse-x) (q/mouse-y)]}]
42 | (compute-position
43 | (m/apply-force
44 | (reduce #(m/apply-force %1 (repulse %1 %2)) mover movers)
45 | (attract mover mouse)))))
46 |
47 | (defn update-state [state]
48 | (update state :movers (fn [movers] (map #(update-mover movers %) movers))))
49 |
50 | (defn draw [{:keys [movers]}]
51 | (q/clear)
52 | (q/background 255)
53 | (doseq [{:keys [mass] [x y] :location} movers]
54 | (q/ellipse x y mass mass)))
55 |
56 | (defn run [host]
57 | (q/defsketch repulse-mouse
58 | :host host
59 | :setup setup
60 | :draw draw
61 | :update update-state
62 | :middleware [md/fun-mode]
63 | :size [300 300]))
64 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/forces/surface_area.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.forces.surface-area
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn setup []
8 | {:movers (map
9 | (fn [i]
10 | {:mass (+ 1 (rand-int 50))
11 | :location [(* i 50) 0]
12 | :velocity [0 0]
13 | :acceleration [0 0]})
14 | (range 50))
15 | :liquid {:location [0 (/ (q/height) 2)]
16 | :size [(q/width) (/ (q/height) 2)]
17 | :c 0.1}})
18 |
19 | (defn draw [{:keys [movers]}]
20 | (q/clear)
21 | (q/background 255)
22 | (q/fill 50 100 255)
23 | (q/rect 0 (/ (q/height) 2) (q/width) (/ (q/height) 2))
24 | (q/fill 255 0 255)
25 | (doseq [{:keys [mass] [x y] :location} movers]
26 | (q/rect x (- y mass) mass mass)))
27 |
28 | (defn compute-position [{:keys [acceleration velocity location] :as mover}]
29 | (let [velocity (v/add acceleration velocity)
30 | location (v/add velocity location)]
31 | (-> mover
32 | (assoc :acceleration [0 0])
33 | (assoc :velocity velocity)
34 | (assoc :location location))))
35 |
36 | (defn gravity [{:keys [mass]}]
37 | [0 (* 0.1 mass)])
38 |
39 | (defn drag [{[x y] :location :keys [velocity mass]}
40 | {:keys [c location]}]
41 | (let [speed (v/mag velocity)
42 | drag-magnitude (* c speed speed)
43 | A mass]
44 | (if (> y (second location))
45 | (v/mult (v/mult (v/normalize (v/mult velocity -1)) drag-magnitude) A)
46 | [0 0])))
47 |
48 | (defn update-mover [liquid mover]
49 | (-> mover
50 | (m/apply-force (gravity mover))
51 | (m/apply-force (drag mover liquid))
52 | compute-position
53 | m/keep-inside))
54 |
55 | (defn update-state [state]
56 | (update state :movers #(map (partial update-mover (:liquid state)) %)))
57 |
58 | (defn run [host]
59 | (q/defsketch surface-area
60 | :host host
61 | :setup setup
62 | :draw draw
63 | :update update-state
64 | :middleware [md/fun-mode]
65 | :size [300 300]))
66 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/fractals/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.fractals.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.fractals.koch-curve :as kc]
4 | [sketches.nature-of-code.fractals.own-cantor :as oc]
5 | [sketches.nature-of-code.fractals.sierpinski :as si]))
6 |
7 | (defn main []
8 | [:div
9 | [:h3.tracked.tc.tl-ns "Fractals"]
10 | [cards-container
11 | [:<>
12 | [exercise-card "Own Cantor" "Exercise 8.1" "https://natureofcode.com/book/chapter-8-fractals/#chapter08_exercise1" oc/run]
13 | [exercise-card "Koch Curve" "Exercise 8.2" "https://natureofcode.com/book/chapter-8-fractals/#chapter08_exercise2" kc/run]
14 | [exercise-card "Sierpinski" "Exercise 8.5" "https://natureofcode.com/book/chapter-8-fractals/#chapter08_exercise5" si/run]]]])
15 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/fractals/koch_curve.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.fractals.koch-curve
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn setup-koch-line [a b]
7 | {:start a :end b})
8 |
9 | (defn update-koch-line [lines]
10 | (reduce (fn [lines {:keys [start end]}]
11 | (let [a start
12 | b (v/add start (v/div (v/sub end start) 3))
13 | c (v/add b (v/rotate (v/div (v/sub end start) 3) (- (q/radians 60))))
14 | d (v/add start (v/mult (v/sub end start) (/ 2 3)))
15 | e end]
16 | (-> lines
17 | (conj (setup-koch-line a b))
18 | (conj (setup-koch-line b c))
19 | (conj (setup-koch-line c d))
20 | (conj (setup-koch-line d e)))))
21 | []
22 | lines))
23 |
24 | (defn setup []
25 | {:lines
26 | (->> [(setup-koch-line [0 200] [700 200])])})
27 |
28 | (defn n-times [n f]
29 | (apply comp (repeat n f)))
30 |
31 | (defn update-state [state]
32 | (q/clear)
33 | (q/background 200)
34 | (let [times (q/map-range (q/mouse-x) 0 (q/width) 0 6)]
35 | {:lines
36 | ((n-times times update-koch-line) [(setup-koch-line [(* 0.3 (q/width)) (/ (q/height) 2)] [(* 0.5 (q/width)) (/ (q/height) 4)])
37 | (setup-koch-line [(* 0.5 (q/width)) (/ (q/height) 4)] [(* 0.7 (q/width)) (/ (q/height) 2)])
38 | (setup-koch-line [(* 0.7 (q/width)) (/ (q/height) 2)] [(* 0.5 (q/width)) (* (q/height) (/ 3 4))])
39 | (setup-koch-line [(* 0.5 (q/width)) (* (q/height) (/ 3 4))] [(* 0.3 (q/width)) (/ (q/height) 2)])])}))
40 |
41 | (defn draw-koch-line [{[x1 y1] :start [x2 y2] :end}]
42 | (q/stroke 0)
43 | (q/line x1 y1 x2 y2))
44 |
45 |
46 | (defn draw [{:keys [lines]}]
47 | (doseq [koch-line lines]
48 | (draw-koch-line koch-line)))
49 |
50 | (defn run [host]
51 | (q/defsketch koch-curve
52 | :host host
53 | :setup setup
54 | :draw draw
55 | :update update-state
56 | :middleware [md/fun-mode]
57 | :size [300 300]))
58 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/fractals/own_cantor.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.fractals.own-cantor
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn draw-circle [x y r]
6 | (q/ellipse x y r r)
7 | (q/ellipse (+ x (/ r 2)) y (/ r 2) (/ r 2))
8 | (q/ellipse (- x (/ r 2)) y (/ r 2) (/ r 2)))
9 |
10 | (defn cantor [x y l]
11 | (when (>= l 1)
12 | (draw-circle x y l)
13 | #_(q/line x y (+ x l) y)
14 | (let [y2 (+ y 20)]
15 | (cantor x y2 (/ l 3))
16 | (cantor (+ x (* l (/ 2 3))) y2 (/ l 3)))))
17 |
18 | (defn draw [state]
19 | (q/clear)
20 | (q/translate 0 (/ (q/height) 2))
21 | (q/background 255)
22 | (q/stroke-weight 5)
23 | (cantor 20 20 (/ (q/width) 1)))
24 |
25 |
26 |
27 | (defn run [host]
28 | (q/defsketch own-cantor
29 | :host host
30 | :draw draw
31 | :middleware [md/fun-mode]
32 | :size [300 300]))
33 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/fractals/sierpinski.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.fractals.sierpinski
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]))
4 |
5 | (defn compute-triangles [v1 v2 v3]
6 | (let [[x1 y1] (v/mult (v/add v1 v2) 0.5)
7 | [x2 y2] (v/mult (v/add v1 v3) 0.5)
8 | [x3 y3] (v/mult (v/add v3 v2) 0.5)]
9 | [[v1 [x1 y1] [x2 y2]]
10 | [[x1 y1] v2 [x3 y3]]
11 | [[x2 y2] [x3 y3] v3]]))
12 |
13 | (defn do-sierpinski [init-triangle step]
14 | (if (= step 0)
15 | init-triangle
16 | (mapcat
17 | #(do-sierpinski % (- step 1))
18 | (apply compute-triangles init-triangle))))
19 |
20 | (defn sierpinski [init-triangle step]
21 | (partition 3 (do-sierpinski init-triangle step)))
22 |
23 | (defn draw []
24 | (q/background 200)
25 | (q/fill 0)
26 | (q/translate -50 -50)
27 | (let [step (q/round (q/map-range (q/mouse-x) 0 (q/width) 0 5))
28 | [x1 y1] [100 280]
29 | [x2 y2] [200 120]
30 | [x3 y3] [300 280]]
31 | (doall
32 | (map
33 | (fn [[[x1 y1] [x2 y2] [x3 y3]]]
34 | (q/triangle x1 y1 x2 y2 x3 y3))
35 | (sierpinski [[x1 y1] [x2 y2] [x3 y3]] step)))))
36 |
37 | (defn setup []
38 | (q/frame-rate 5))
39 |
40 | (defn run [host]
41 | (q/defsketch sierpinski-sketch
42 | :host host
43 | :draw draw
44 | :setup setup
45 | :size [300 300]))
46 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.introduction.noise-animate :as na]
4 | [sketches.nature-of-code.introduction.noise-detail :as nd]
5 | [sketches.nature-of-code.introduction.noise-terrain :as nt]
6 | [sketches.nature-of-code.introduction.paint-splatter :as p]
7 | [sketches.nature-of-code.introduction.random-walk :as rw]
8 | [sketches.nature-of-code.introduction.random-walk-custom-step :as rwc]
9 | [sketches.nature-of-code.introduction.random-walk-dynamic :as rwd]
10 | [sketches.nature-of-code.introduction.random-walk-gaussian :as rwg]
11 | [sketches.nature-of-code.introduction.random-walk-noise :as rwn]))
12 |
13 | (defn main []
14 | [:div
15 | [:h3.tracked.tc.tl-ns "Introduction"]
16 | [cards-container
17 | [:<>
18 | [exercise-card "Random Walk" "Exercise I.1" "https://natureofcode.com/book/introduction/#exercise-i1" rw/run]
19 | [exercise-card "Random Walk II" "Exercise I.3" "https://natureofcode.com/book/introduction/#exercise-i3" rwd/run]
20 | [exercise-card "Paint Splatter" "Exercise I.4" "https://natureofcode.com/book/introduction/#exercise-i4" p/run]
21 | [exercise-card "Random Walk III" "Exercise I.5" "https://natureofcode.com/book/introduction/#exercise-i5" rwg/run]
22 | [exercise-card "Random Walk IV" "Exercise I.6" "https://natureofcode.com/book/introduction/#exercise-i6" rwc/run]
23 | [exercise-card "Random Walk V" "Exercise I.7" "https://natureofcode.com/book/introduction/#exercise-i7" rwn/run]
24 | [exercise-card "Noise Detail" "Exercise I.8" "https://natureofcode.com/book/introduction/#exercise-i8" nd/run]
25 | [exercise-card "Noise Animate" "Exercise I.9" "https://natureofcode.com/book/introduction/#exercise-i9" na/run]
26 | [exercise-card "Noise Terrain" "Exercise I.10" "https://natureofcode.com/book/introduction/#exercise-i10" nt/run]]]])
27 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/noise_animate.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.noise-animate
2 | (:require [quil.core :as q :include-macros true]))
3 |
4 | (defn setup []
5 | (q/frame-rate 3)
6 | (q/background 255))
7 |
8 | (def zoff (atom 0))
9 |
10 | (defn draw [host]
11 | (q/clear)
12 | (q/background 255)
13 | (let [xoff (atom 0.0)]
14 | (doseq [x (range 0 (q/width))]
15 | (let [yoff (atom 0.0)]
16 | (doseq [y (range 0 (q/height))]
17 | (q/stroke (q/map-range (q/noise @xoff @yoff @zoff) 0 1 0 255))
18 | (q/point x y)
19 | (swap! yoff #(+ 0.05 %)))
20 | (swap! xoff #(+ 0.05 %)))))
21 | (swap! zoff #(+ 0.05 %)))
22 |
23 | (defn run [host]
24 | (q/defsketch noise
25 | :host host
26 | :setup setup
27 | :draw draw
28 | :size [300 300]))
29 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/noise_detail.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.noise-detail
2 | (:require [quil.core :as q :include-macros true]))
3 |
4 | ;; float xoff = 0.0;
5 | ;; for (int x = 0; x < width; x++) {
6 | ;; For every xoff, start yoff at 0.
7 | ;; float yoff = 0.0;
8 | ;; for (int y = 0; y < height; y++) {
9 | ;; Use xoff and yoff for noise().
10 | ;; float bright = map(noise(xoff,yoff),0,1,0,255);
11 | ;; Use x and y for pixel location.
12 | ;; pixels[x+y*width] = color(bright);
13 | ;; Increment yoff.
14 | ;; yoff += 0.01;
15 | ;; }
16 | ;; Increment xoff.
17 | ;; xoff += 0.01;
18 | ;; }
19 | (defn setup []
20 | (q/color-mode :hsb)
21 | (q/noise-detail 4 0.35)
22 | (let [xoff (atom 0.0)]
23 | (doseq [x (range 0 (q/width))]
24 | (let [yoff (atom 0.0)]
25 | (doseq [y (range 0 (q/height))]
26 | (q/stroke (q/map-range (q/noise @xoff @yoff) 0 1 0 255) 255 127)
27 | (q/point x y)
28 | (swap! yoff #(+ 0.03 %)))
29 | (swap! xoff #(+ 0.03 %))))))
30 |
31 | (defn draw [])
32 |
33 | (defn run [host]
34 | (q/defsketch noise-detail
35 | :host host
36 | :setup setup host
37 | :draw draw host
38 | :size [300 300]))
39 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/noise_terrain.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.noise-terrain
2 | (:require [quil.core :as q]))
3 |
4 | (defn setup []
5 | (q/stroke 127)
6 | (q/no-fill)
7 | (q/rotate-x (/ q/PI 3))
8 | (q/translate (/ (- (q/width)) 2) (/ (- (q/height)) 2))
9 | (let [scale 10
10 | yoff (atom 0.0)
11 | xoff (atom 0.0)
12 | cols (/ (q/width) scale)
13 | rows (/ (q/height) scale)
14 | terrain (let [col (list)]
15 | (for [y (range 0 30)]
16 | (do
17 | (swap! yoff + 0.1)
18 | (let [row (list)]
19 | (for [x (range 0 30)]
20 | (do
21 | (swap! xoff + 0.1)
22 | (q/map-range (q/noise @xoff @yoff) 0 1 -50 50)))))))]
23 | (doall
24 | (for [y (range 0 (dec rows))]
25 | (do
26 | (q/begin-shape :triangle-strip)
27 | (doall
28 | (for [x (range 0 cols)]
29 | (do
30 | (q/vertex (* x scale) (* y scale) (nth (nth terrain y) x))
31 | (q/vertex (* x scale) (* (inc y) scale) (nth (nth terrain (inc y)) x)))))
32 | (q/end-shape))))))
33 |
34 | (defn draw []
35 | )
36 |
37 | (defn run [host]
38 | (q/defsketch noise-terrain
39 | :host host
40 | :setup setup
41 | :draw draw
42 | :size [300 300]
43 | :renderer :p3d))
44 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/paint_splatter.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.paint-splatter
2 | (:require [quil.core :as q :include-macros true]))
3 |
4 | (defn draw []
5 | (let [sd 100
6 | mean (/ (q/width) 2)
7 | x (+ (* (q/random-gaussian) sd) mean)
8 | y (+ (* (q/random-gaussian) sd) mean)]
9 | (q/fill (+ (* (q/random-gaussian) 50) 128)
10 | (+ (* (q/random-gaussian) 50) 128)
11 | (+ (* (q/random-gaussian) 50) 255))
12 | (q/ellipse x y 10 10)))
13 |
14 | (defn run [host]
15 | (q/defsketch paint-splatter
16 | :host host
17 | :draw draw
18 | :size [300 300]))
19 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/random_walk.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.random-walk
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]))
4 |
5 | (defn setup []
6 | (def location (atom [(/ (q/width) 2) (/ (q/height) 2)]))
7 | (q/background 255))
8 |
9 | (defn draw []
10 | (q/stroke 0)
11 | (let [choice (q/random 1)
12 | velocity (cond
13 | (< choice 0.33) [0 1]
14 | (< choice 0.66) [1 0]
15 | (< choice 0.84) [-1 0]
16 | (< choice 1.0) [0 -1])]
17 | (let [[x y] (swap! location #(v/add % velocity))]
18 | (q/point x y))))
19 |
20 | (defn run [host]
21 | (q/defsketch random-walk
22 | :host host
23 | :setup setup
24 | :draw draw
25 | :size [300 300]))
26 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/random_walk_custom_step.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.random-walk-custom-step
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]))
4 |
5 | (defn setup []
6 | (def location (atom [(/ (q/width) 2) (/ (q/height) 2)]))
7 | (q/background 255))
8 |
9 | (defn custom-prop []
10 | (loop []
11 | (let [r1 (rand 1)
12 | r2 (rand 1)]
13 | (if (< r1 (* r2 r2))
14 | r2
15 | (recur)))))
16 |
17 | (defn draw []
18 | (q/stroke 0)
19 | (let [choice (q/random 1)
20 | step-size (custom-prop)
21 | velocity (cond
22 | (< choice 0.25) [0 step-size]
23 | (< choice 0.50) [step-size 0]
24 | (< choice 0.75) [(- step-size) 0]
25 | (< choice 1.0) [0 (- step-size)])]
26 | (let [[x y] (swap! location #(v/add % velocity))]
27 | (q/point x y))))
28 |
29 | (defn run [host]
30 | (q/defsketch random-walk-custom-step
31 | :host host
32 | :setup setup
33 | :draw draw
34 | :size [300 300]))
35 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/random_walk_dynamic.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.random-walk-dynamic
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]))
4 |
5 | (defn setup []
6 | (def location (atom [(/ (q/width) 2) (/ (q/height) 2)]))
7 | (q/background 255))
8 |
9 | (defn draw []
10 | (q/stroke 0)
11 | (let [choice (q/random 1)
12 | [x y] @location
13 | velocity (cond
14 | (< choice 0.500) [(if (> x (q/mouse-x)) -1 1)
15 | (if (> y (q/mouse-y)) -1 1)]
16 | (< choice 0.625) [0 1]
17 | (< choice 0.750) [1 0]
18 | (< choice 0.875) [-1 0]
19 | (< choice 1.000) [0 -1])]
20 | (let [[x y] (swap! location #(v/add % velocity))]
21 | (q/point x y))))
22 |
23 | (defn run [host]
24 | (q/defsketch random-walk-dynamic
25 | :host host
26 | :setup setup
27 | :draw draw
28 | :size [300 300]))
29 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/random_walk_gaussian.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.random-walk-gaussian
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]))
4 |
5 | (defn setup []
6 | (def walker (atom [150 150]))
7 | (q/background 255))
8 |
9 | (defn draw []
10 | (q/stroke 0)
11 | (q/point 150 150)
12 | (let [choice (rand-int 4)
13 | step (cond (= choice 0) [(* (q/random-gaussian) 5) 0]
14 | (= choice 1) [0 (* (q/random-gaussian) 5)]
15 | (= choice 2) [(-(* (q/random-gaussian) 5)) 0]
16 | :else [0 (-(* (q/random-gaussian) 5))])
17 | [x y] (swap! walker (fn [walker] (v/add walker step)))]
18 | (q/point x y)))
19 |
20 | (defn run [host]
21 | (q/defsketch random-walk-gaussian
22 | :host host
23 | :setup setup
24 | :draw draw
25 | :size [300 300]))
26 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/introduction/random_walk_noise.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.introduction.random-walk-noise
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]))
4 |
5 | (defn setup []
6 | (def walker (atom [(/ (q/width) 2) (/ (q/height) 2)]))
7 | (def tx (atom 0))
8 | (q/background 255))
9 |
10 | (defn draw []
11 | (q/stroke 0)
12 | (let [tx (swap! tx #(+ 0.01 %))
13 | choice (rand-int 4)
14 | step (q/map-range (q/noise tx) 0 1 0 10)
15 | new-position (cond (= choice 0) [0 step]
16 | (= choice 1) [step 0]
17 | (= choice 2) [(- step) 0]
18 | :else [0 (- step)])
19 | [x y] (swap! walker #(v/add % new-position))]
20 | (q/point x y)))
21 |
22 | (defn run [host]
23 | (q/defsketch random-walk-noise
24 | :host host
25 | :setup setup
26 | :draw draw
27 | :size [300 300]))
28 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/angular_oscilliate.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.angular-oscilliate
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn setup []
7 | (list
8 | {:angle [0 0]
9 | :velocity [0 0]
10 | :acceleration [0 0.03]
11 | :amplitude [-30 -30]
12 | :location [-50 -50]}
13 | {:angle [0 0]
14 | :velocity [0 0]
15 | :acceleration [0 0.03]
16 | :amplitude [30 30]
17 | :location [50 -50]}
18 | {:angle [0 0]
19 | :velocity [0 0]
20 | :acceleration [0 0.03]
21 | :amplitude [0 -30]
22 | :location [-100 0]}
23 | {:angle [0 0]
24 | :velocity [0 0]
25 | :acceleration [0 0.03]
26 | :amplitude [0 30]
27 | :location [100 0]}
28 | {:angle [0 0]
29 | :velocity [0 0]
30 | :acceleration [0 0.03]
31 | :amplitude [-30 -30]
32 | :location [-50 50]}
33 | {:angle [0 0]
34 | :velocity [0 0]
35 | :acceleration [0 0.03]
36 | :amplitude [30 30]
37 | :location [50 50]}))
38 |
39 | (defn draw [state]
40 | (q/background 255)
41 | (doseq [{[a1 a2] :angle
42 | [am1 am2] :amplitude
43 | [l1 l2] :location} state]
44 | (let [x (+ l1 (* am1 (q/cos a1)))
45 | y (+ l2 (* am2 (q/cos a2)))]
46 | (q/push-matrix)
47 | (q/stroke 0)
48 | (q/fill 175)
49 | (q/translate (/ (q/width) 2) (/ (q/height) 2))
50 | (q/line 0 0 x y)
51 | (q/ellipse x y 20 20)
52 | (q/pop-matrix))))
53 |
54 | (defn update-oscilliator [{:keys [acceleration velocity] :as o}]
55 | (-> o
56 | (update :velocity v/add (v/add acceleration [0.00002 0.00002]))
57 | (update :angle v/add (v/add acceleration velocity))
58 | (assoc :acceleration [0 0])))
59 |
60 | (defn update-state [state]
61 | (map update-oscilliator state))
62 |
63 | (defn run [host]
64 | (q/defsketch angular-oscilliate
65 | :host host
66 | :setup setup
67 | :draw draw
68 | :update update-state
69 | :middleware [md/fun-mode]
70 | :size [300 300]))
71 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/asteroids.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.asteroids
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn setup []
8 | (m/create-mover 50 [(/ (q/width) 2) (/ (q/height) 2)]))
9 |
10 | (defn draw [spaceship]
11 | (q/background 255)
12 | (q/fill 126)
13 | (q/stroke-weight 2)
14 | (let [{:keys [mass angle] [x y] :location} spaceship]
15 | (q/push-matrix)
16 | (q/translate x y)
17 | (q/rotate angle)
18 | (q/triangle (/ mass 2) 0 (- (/ mass 2)) (- (/ mass 2)) (- (/ mass 2)) (/ mass 2))
19 | (q/rect (- (- (/ mass 2)) 5) 5 5 5)
20 | (q/rect (- (- (/ mass 2)) 5) -5 5 5)
21 | (q/pop-matrix)))
22 |
23 | (defn update-state [{:keys [velocity] :as spaceship}]
24 | (-> spaceship
25 | (m/apply-force (v/mult velocity -0.2))
26 | (m/move-through)
27 | (m/compute-position)))
28 |
29 | (defn key-pressed [{:keys [angle] :as spaceship} {:keys [key]}]
30 | (cond (= key :a) (update spaceship :angle + 0.2)
31 | (= key :d) (update spaceship :angle - 0.2)
32 | (= key :w) (assoc spaceship :acceleration [(q/cos angle) (q/sin angle)])
33 | :else spaceship))
34 |
35 | (defn run [host]
36 | (q/defsketch asteroids
37 | :host host
38 | :setup setup
39 | :draw draw
40 | :update update-state
41 | :key-pressed key-pressed
42 | :middleware [md/fun-mode]
43 | :size [300 300]))
44 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/bob.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.bob
2 | (:require [quil.core :as q :include-macros true]))
3 |
4 | (defn draw []
5 | (q/background 255)
6 | (let [amplitude 110.0
7 | period 80.0
8 | x (* amplitude (q/cos (/ (* q/TWO-PI (q/frame-count)) period)))
9 | y (* 60 (q/abs (q/sin (/ (* q/TWO-PI (q/frame-count)) period))))]
10 | (q/push-matrix)
11 | (q/translate (/ (q/width) 2) 0)
12 | (q/line 0 0 x (+ y (/ (q/height) 2)))
13 | (q/ellipse x (+ y (/ (q/height) 2)) 80 80)
14 | (q/pop-matrix)))
15 |
16 | (defn run [host]
17 | (q/defsketch bob
18 | :host host
19 | :draw draw
20 | :size [300 300]))
21 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/cannon.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.cannon
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn setup []
8 | (q/no-stroke)
9 | {:location [(* (q/width) 0.1) (* (q/height) 0.8)]
10 | :velocity [0 0]
11 | :acceleration [0 0]
12 | :aAcceleration 0
13 | :aVelocity 0.2
14 | :angle 0
15 | :mass 20})
16 |
17 | (defn compute-position [mover]
18 | (-> mover
19 | (update :velocity #(v/add (:acceleration mover) %))
20 | (update :location #(v/add % (v/add (:acceleration mover) (:velocity mover))))
21 | (update :aVelocity #(+ (:aAcceleration mover) %))
22 | (update :angle #(+ (:aAcceleration mover) (:aVelocity mover) %))
23 | (assoc :aAcceleration 0)
24 | (assoc :acceleration [0 0])))
25 |
26 | (defn shoot [{:keys [velocity]}]
27 | (if (= (v/mag velocity) 0.0)
28 | [100 -100]
29 | [0 0]))
30 |
31 | (defn update-cannonball [cannonball]
32 | (-> cannonball
33 | (m/apply-force (v/add [0.0 3] (shoot cannonball)))
34 | compute-position))
35 |
36 | (defn update-state [cannonball]
37 | (update-cannonball cannonball))
38 |
39 | (defn draw-cannon []
40 | (q/with-translation [(* (q/width) 0.1) (* (q/height) 0.8)]
41 | (q/with-fill [0 0 0]
42 | (q/rect 0 15 30 20)
43 | (q/with-rotation [(q/radians 225)]
44 | (q/ellipse 0 0 20 20)
45 | (q/rect 0 10 20 20)))))
46 |
47 | (defn draw-cannonball [{[x y] :location
48 | :keys [angle]}]
49 | (q/rect-mode :center)
50 | (q/with-translation [x y]
51 | (q/with-fill [255 0 0]
52 | (q/with-rotation [angle]
53 | (q/rect 0 0 15 15)))))
54 |
55 | (defn draw [cannonball]
56 | (q/background 255 255 255)
57 | (draw-cannonball cannonball)
58 | (draw-cannon))
59 |
60 | (defn run [host]
61 | (q/defsketch cannon
62 | :host host
63 | :setup setup
64 | :draw draw
65 | :update update-state
66 | :middleware [md/fun-mode]
67 | :size [300 300]))
68 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/combined_wave.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.combined-wave
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (map #(vector (* % 24)
7 | [{:amplitude 200
8 | :angle-vel 0.01
9 | :angle (* % 0.1)}
10 | {:amplitude 50
11 | :angle-vel 0.03
12 | :angle (* % 0.3)}
13 | {:amplitude 150
14 | :angle-vel 0.06
15 | :angle (* % 0.5)}]) (range (/ (q/width) 24))))
16 |
17 | (defn update-state [state]
18 | (map (fn [[x ys]]
19 | [x (map (fn [{:keys [angle-vel] :as y}] (update y :angle + angle-vel)) ys)])
20 | state))
21 |
22 | (defn combine-waves [waves]
23 | (reduce (fn [total-y {:keys [angle-vel amplitude angle]}]
24 | (+ total-y (q/map-range (q/sin angle) -1 1 0 amplitude)))
25 | 0 waves))
26 |
27 | (defn draw-wave-element [[x waves]]
28 | (q/stroke 0)
29 | (q/fill 0 50)
30 | (q/ellipse x (combine-waves waves) 48 48))
31 |
32 | (defn draw [state]
33 | (q/background 255)
34 | (doseq [wave-element state]
35 | (draw-wave-element wave-element)))
36 |
37 | (defn run [host]
38 | (q/defsketch combined-wave
39 | :host host
40 | :setup setup
41 | :draw draw
42 | :update update-state
43 | :middleware [md/fun-mode]
44 | :size [300 300]))
45 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.oscillation.angular-oscilliate :as ao]
4 | [sketches.nature-of-code.oscillation.asteroids :as as]
5 | [sketches.nature-of-code.oscillation.bob :as bo]
6 | [sketches.nature-of-code.oscillation.cannon :as cn]
7 | [sketches.nature-of-code.oscillation.combined-wave :as co]
8 | [sketches.nature-of-code.oscillation.custom-waves :as cw]
9 | [sketches.nature-of-code.oscillation.insect :as in]
10 | [sketches.nature-of-code.oscillation.multi-pendulum :as mp]
11 | [sketches.nature-of-code.oscillation.multi-springs :as ms]
12 | [sketches.nature-of-code.oscillation.perlin-wave :as pw]
13 | [sketches.nature-of-code.oscillation.rotate-baton :as rb]
14 | [sketches.nature-of-code.oscillation.spiral :as sp]
15 | [sketches.nature-of-code.oscillation.vehicle :as ve]))
16 |
17 | (defn main []
18 | [:div
19 | [:h3.tracked.tc.tl-ns "Oscillation"]
20 | [cards-container
21 | [:<>
22 | [exercise-card "Rotate baton" "Exercise 3.1" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise1" rb/run]
23 | [exercise-card "Cannon" "Exercise 3.2" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise2" cn/run]
24 | [exercise-card "Vehicle" "Exercise 3.3" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise3" ve/run]
25 | [exercise-card "Spiral" "Exercise 3.4" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise4" sp/run]
26 | [exercise-card "Asteroids" "Exercise 3.5" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise5" as/run]
27 | [exercise-card "Bob" "Exercise 3.6" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise6" bo/run]
28 | [exercise-card "Insect" "Exercise 3.7" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise7" in/run]
29 | [exercise-card "Angular Oscilliate" "Exercise 3.8" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise8" ao/run]
30 | [exercise-card "Perlin Wave" "Exercise 3.9" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise9" pw/run]
31 | [exercise-card "Custom Waves" "Exercise 3.10" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise10" cw/run]
32 | [exercise-card "Combined Wave" "Exercise 3.11" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise11" co/run]
33 | [exercise-card "Multi Pendulum" "Exercise 3.12" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise12" mp/run]
34 | [exercise-card "Multi Springs" "Exercise 3.16" "https://natureofcode.com/book/chapter-3-oscillation#chapter03_exercise16" ms/run]]]])
35 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/custom_waves.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.custom-waves
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (list
7 | (let [element-counts (/ (q/width) 24)
8 | angle-vel 0.02]
9 | {:amplitude 200
10 | :angle-vel angle-vel
11 | :elements (map #(vector (* % 24) (* % angle-vel)) (range element-counts))
12 | :location [0 (* 0.1 (q/height))]})
13 | (let [element-counts (/ (q/width) 48)
14 | angle-vel 0.3]
15 | {:amplitude 50
16 | :angle-vel angle-vel
17 | :elements (map #(vector (* % 24) (* % angle-vel)) (range element-counts))
18 | :location [0 (* 0.8 (q/height))]})))
19 |
20 | (defn update-element [angle-vel [x y]]
21 | [(mod (+ 1 x) (q/width)) (+ angle-vel y)])
22 |
23 | (defn update-wave [{:keys [angle-vel] :as wave}]
24 | (update wave :elements (partial map (partial update-element angle-vel))))
25 |
26 | (defn update-state [waves]
27 | (map update-wave waves))
28 |
29 | (defn draw-wave [{:keys [angleVel elements amplitude]
30 | [l1 l2] :location}]
31 | (doseq [[x angle] elements]
32 | (let [y (q/map-range (q/sin angle) -1 1 0 amplitude)]
33 | (q/stroke 0)
34 | (q/fill 0 50)
35 | (q/ellipse (+ l1 x) (+ l2 y) 48 48))))
36 |
37 | (defn draw [waves]
38 | (q/background 255)
39 | (doseq [wave waves]
40 | (draw-wave wave)))
41 |
42 | (defn run [host]
43 | (q/defsketch custom-waves
44 | :host host
45 | :setup setup
46 | :draw draw
47 | :update update-state
48 | :middleware [md/fun-mode]
49 | :size [300 300]))
50 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/insect.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.insect
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn setup []
7 | '({:angle [0 0]
8 | :velocity [0 0.08]
9 | :amplitude [-25 -25]
10 | :location [-30 -30]}
11 | {:angle [0 0]
12 | :velocity [0 -0.08]
13 | :amplitude [25 25]
14 | :location [30 -30]}
15 | {:angle [0 0]
16 | :velocity [0 0.08]
17 | :amplitude [0 -25]
18 | :location [-80 0]}
19 | {:angle [0 0]
20 | :velocity [0 0.08]
21 | :amplitude [0 25]
22 | :location [80 0]}
23 | {:angle [0 0]
24 | :velocity [0 0.08]
25 | :amplitude [-25 -25]
26 | :location [-30 30]}
27 | {:angle [0 0]
28 | :velocity [0 0.08]
29 | :amplitude [25 25]
30 | :location [30 30]}))
31 |
32 | (defn draw-foot [{[a1 a2] :angle [am1 am2] :amplitude [l1 l2] :location}]
33 | (let [x (+ l1 (* am1 (q/cos a1)))
34 | y (+ l2 (* am2 (q/cos a2)))]
35 | (q/push-matrix)
36 | (q/stroke 175)
37 | (q/fill 175)
38 | (q/translate (/ (q/width) 2) (/ (q/height) 2))
39 | (q/stroke-weight 4)
40 | (q/line 0 0 x y)
41 | (q/ellipse x y 20 20)
42 | (q/pop-matrix)))
43 |
44 | (defn draw [state]
45 | (q/background 255)
46 | (doseq [foot state]
47 | (draw-foot foot))
48 | (q/fill 175)
49 | (q/stroke 175)
50 | (q/ellipse (/ (q/width) 2) (/ (q/height) 2) 80 120)
51 | (q/ellipse (/ (q/width) 2) (- (/ (q/height) 2) 60) 50 50)
52 | (q/fill 0)
53 | (q/ellipse (- (/ (q/width) 2) 10) (- (/ (q/height) 2) 70) 10 10)
54 | (q/ellipse (+ (/ (q/width) 2) 10) (- (/ (q/height) 2) 70) 10 10))
55 |
56 | (defn update-foot [{:keys [velocity] :as foot}]
57 | (update foot :angle v/add velocity))
58 |
59 | (defn update-state [state]
60 | (map update-foot state))
61 |
62 | (defn run [host]
63 | (q/defsketch insect
64 | :host host
65 | :setup setup
66 | :draw draw
67 | :update update-state
68 | :middleware [md/fun-mode]
69 | :size [300 300]))
70 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/multi_pendulum.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.multi-pendulum
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn create-pendulum [origin r]
7 | {:location [0 0] :origin origin :r r :angle (/ q/PI 4.0) :damping 0.995
8 | :a-velocity 0.0 :a-acceleration 0.0})
9 |
10 | (defn update-pendulum [{:keys [angle a-velocity r damping origin] :as pendulum}]
11 | (let [gravity 0.4
12 | a-acceleration (* (/ (- gravity) r) (q/sin angle))
13 | a-velocity (+ a-velocity a-acceleration)
14 | angle (+ angle a-velocity)
15 | location (v/add (vector (* r (q/sin angle)) (* r (q/cos angle))) origin)]
16 | (-> pendulum
17 | (assoc :a-acceleration a-acceleration)
18 | (assoc :angle angle)
19 | (assoc :origin origin)
20 | (assoc :location location)
21 | (assoc :a-velocity (* a-velocity damping)))))
22 |
23 | (defn draw-pendulum [{:keys [r angle] [ox oy] :origin [x y] :location}]
24 | (q/stroke 0)
25 | (q/line ox oy x y)
26 | (q/ellipse x y 16 16))
27 |
28 | (defn setup []
29 | (list
30 | (create-pendulum [(/ (q/width) 2) 0] 100.0)
31 | (create-pendulum [(/ (q/width) 2) 100] 100.0)
32 | (create-pendulum [(/ (q/width) 2) 200] 100.0)))
33 |
34 | (defn update-state [pendulums]
35 | (map-indexed
36 | (fn [idx pendulum]
37 | (update-pendulum (if (= idx 0)
38 | pendulum
39 | (assoc pendulum :origin (:location (nth pendulums (dec idx)))))))
40 | pendulums))
41 |
42 | (defn draw [pendulums]
43 | (q/background 255)
44 | (doseq [pendulum pendulums]
45 | (draw-pendulum pendulum)))
46 |
47 | (defn run [host]
48 | (q/defsketch multi-pendulum
49 | :host host
50 | :setup setup
51 | :draw draw
52 | :update update-state
53 | :middleware [md/fun-mode]
54 | :size [300 300]))
55 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/multi_springs.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.multi-springs
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn create-spring [x y l]
8 | {:location [x y] :len l})
9 |
10 | (defn connect [bob spring]
11 | (let [k 0.1
12 | force (v/sub (:location bob) (:location spring))
13 | d (v/mag force)
14 | stretch (- d (:len spring))]
15 | (m/apply-force bob (v/mult (v/normalize force) (* -1 k stretch)))))
16 |
17 | (defn setup []
18 | [{:spring (create-spring (/ (q/width) 2) 0 100)
19 | :bob (m/create-mover 50 [(- (/ (q/width) 2) 50) 50])}
20 | {:spring (create-spring (- (/ (q/width) 2) 100) 0 100)
21 | :bob (m/create-mover 50 [(- (/ (q/width) 2) 150) 50])}])
22 |
23 | (defn update-state [state]
24 | (reduce (fn [springs {:keys [spring bob]}]
25 | (conj springs
26 | {:bob
27 | (-> bob
28 | (m/apply-force [0 1])
29 | (connect spring)
30 | (m/compute-position))
31 | :spring (if-let [last-bob-location (-> springs
32 | last
33 | :bob
34 | :location)]
35 | (assoc spring :location last-bob-location)
36 | spring)}))
37 | []
38 | state))
39 |
40 | (defn draw [state]
41 | (q/background 255)
42 | (q/rect-mode :center)
43 | (doseq [{:keys [spring bob]} state]
44 | (let [{:keys [len] [a1 a2] :location} spring
45 | {:keys [mass] [x y] :location} bob]
46 | (q/line x y a1 a2)
47 | (q/rect a1 a2 10 10)
48 | (q/ellipse x y mass mass))))
49 |
50 | (defn run [host]
51 | (q/defsketch multi-springs
52 | :host host
53 | :setup setup
54 | :draw draw
55 | :update update-state
56 | :middleware [md/fun-mode]
57 | :size [300 300]))
58 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/perlin_wave.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.perlin-wave
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (map #(hash-map :angle (* % 0.1) :x (* % 24)) (range (/ (q/width) 24))))
7 |
8 | (defn draw [angles]
9 | (q/background 255)
10 | (doseq [{:keys [x angle]} angles]
11 | (let [y (q/map-range (q/noise angle) 0 1 0 (q/height))]
12 | (q/stroke 0)
13 | (q/fill 0 50)
14 | (q/ellipse x y 48 48))))
15 |
16 | (defn update-state [state]
17 | (map #(update % :angle + 0.02) state))
18 |
19 | (defn run [host]
20 | (q/defsketch perlin-wave
21 | :host host
22 | :setup setup
23 | :draw draw
24 | :update update-state
25 | :middleware [md/fun-mode]
26 | :size [300 300]))
27 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/rotate_baton.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.rotate-baton
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | 0)
7 |
8 | (defn update-state [rotation]
9 | (+ 1 rotation))
10 |
11 | (defn draw [rotation]
12 | (q/background 255)
13 | (q/fill 0)
14 | (q/translate (/ (q/width) 2) (/ (q/height) 2))
15 | (q/rotate (q/radians rotation))
16 | (q/line 0 -100 0 100)
17 | (q/ellipse 0 -100 20 20)
18 | (q/ellipse 0 100 20 20))
19 |
20 | (defn run [host]
21 | (q/defsketch rotate-baton
22 | :host host
23 | :setup setup
24 | :draw draw
25 | :update update-state
26 | :middleware [md/fun-mode]
27 | :size [300 300]))
28 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/spiral.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.spiral
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/background 255)
7 | {:radius 0
8 | :theta 0})
9 |
10 | (defn draw [{:keys [radius theta]}]
11 | (q/no-stroke)
12 | (q/fill 0)
13 | (let [x (* radius (q/cos theta))
14 | y (* radius (q/sin theta))]
15 | (q/ellipse (+ x (/ (q/width) 2)) (+ y (/ (q/height) 2)) 16 16)))
16 |
17 | (defn update-state [state]
18 | (-> state
19 | (update :theta + 0.05)
20 | (update :radius + 0.2)))
21 |
22 | (defn run [host]
23 | (q/defsketch spiral
24 | :host host
25 | :setup setup
26 | :draw draw
27 | :update update-state
28 | :middleware [md/fun-mode]
29 | :size [300 300]))
30 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/oscillation/vehicle.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.oscillation.vehicle
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]))
5 |
6 | (defn setup []
7 | (q/rect-mode :center)
8 | (m/create-mover 100 [100 100]))
9 |
10 | (defn cart-to-pol [[x y]]
11 | [(Math/sqrt (+ (* x x) (* y y))) (q/atan2 y x)])
12 |
13 | (defn pol-to-cart [[r phi]]
14 | [(* r (q/cos phi)) (* r (q/sin phi))])
15 |
16 | (defn steer [{[x y] :velocity :as mover} key]
17 | (let [[r phi] (cart-to-pol [x y])]
18 | (cond
19 | (= key :ArrowLeft) (pol-to-cart [r (+ phi 10)])
20 | (= key :ArrowRight) (pol-to-cart [r (- phi 10)])
21 | (= key :ArrowUp) (pol-to-cart [(+ r 5) phi])
22 | (= key :ArrowDown) (pol-to-cart [(- r 5) phi])
23 | :else [x y])))
24 |
25 | (defn draw [car]
26 | (q/background 255)
27 | (q/fill 123)
28 | (q/stroke 255)
29 | (q/rect-mode :center)
30 | (let [{:keys [mass]
31 | [x y] :location
32 | [vx vy] :velocity} car
33 | angle (q/atan2 vy vx)]
34 | (q/push-matrix)
35 | (q/translate x y)
36 | (q/rotate angle)
37 | (q/rect 0 0 mass (* 0.5 mass))
38 | (q/pop-matrix)))
39 |
40 | (defn update-state [car]
41 | (-> car
42 | m/move-through
43 | m/compute-position))
44 |
45 | (defn key-pressed [car {:keys [key]}]
46 | (m/apply-force car (steer car key)))
47 |
48 | (defn run [host]
49 | (q/defsketch vehicle
50 | :host host
51 | :setup setup
52 | :draw draw
53 | :update update-state
54 | :middleware [md/fun-mode]
55 | :size [300 300]
56 | :key-pressed key-pressed))
57 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.particle-systems.asteroids-with-particles
4 | :as
5 | ap]
6 | [sketches.nature-of-code.particle-systems.dynamic-origin :as do]
7 | [sketches.nature-of-code.particle-systems.fire :as f]
8 | [sketches.nature-of-code.particle-systems.fire-blend :as rib]
9 | [sketches.nature-of-code.particle-systems.fire-rainbow :as rf]
10 | [sketches.nature-of-code.particle-systems.mixed-particles :as mip]
11 | [sketches.nature-of-code.particle-systems.particle-force :as pf]
12 | [sketches.nature-of-code.particle-systems.particles-on-click :as ac]
13 | [sketches.nature-of-code.particle-systems.particles-repel :as prs]
14 | [sketches.nature-of-code.particle-systems.particles-with-images :as pi]
15 | [sketches.nature-of-code.particle-systems.particles-with-repellers
16 | :as
17 | pr]
18 | [sketches.nature-of-code.particle-systems.rotating-particle :as rp]
19 | [sketches.nature-of-code.particle-systems.shutter-in-pieces :as sip]))
20 |
21 | (defn main []
22 | [:div
23 | [:h3.tracked.tc.tl-ns "Particle Systems"]
24 | [cards-container
25 | [:<>
26 | [exercise-card "Particle Force" "Exercise 4.1" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise1" pf/run]
27 | [exercise-card "Rotating Particle" "Exercise 4.2" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise2" rp/run]
28 | [exercise-card "Dynamic Origin" "Exercise 4.3" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise3" do/run]
29 | [exercise-card "Asteroids with Particles" "Exercise 4.4" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise4" ap/run]
30 | [exercise-card "Particles on Click" "Exercise 4.5" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise5" ac/run]
31 | [exercise-card "Shutter in Pieces" "Exercise 4.6" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise6" sip/run]
32 | [exercise-card "Mixed Particles" "Exercise 4.8" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise8" mip/run]
33 | [exercise-card "Particles with Repellers" "Exercise 4.9" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise9" pr/run]
34 | [exercise-card "Particles repel" "Exercise 4.10" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise10" prs/run]
35 | [exercise-card "Fire" "Exercise 4.11" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise11" f/run]
36 | [exercise-card "Particle with Images" "Exercise 4.12" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise12" pi/run]
37 | [exercise-card "Rainbow Fire" "Exercise 4.13" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise13" rf/run]
38 | [exercise-card "Fire Blend" "Exercise 4.14" "https://natureofcode.com/book/chapter-4-particle-systems#chapter04_exercise14" rib/run]]]])
39 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/dynamic_origin.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.dynamic-origin
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn create-particle [location]
7 | {:location location
8 | :velocity [(- (rand 2) 1) (- (rand 2) 1)]
9 | :acceleration [0 0]
10 | :lifespan 255.0
11 | :aAcceleration 0.0
12 | :aVelocity 0.1
13 | :angle 0.0})
14 |
15 | (defn update-particle [{:keys [acceleration velocity location lifespan
16 | aVelocity aAcceleration angle]
17 | :as particle}]
18 | (let [velocity (v/add velocity acceleration)
19 | location (v/add velocity location)
20 | lifespan (- lifespan 2.0)
21 | aVelocity (+ aVelocity aAcceleration)
22 | angle (+ aVelocity angle)]
23 | (-> particle
24 | (assoc :velocity velocity)
25 | (assoc :location location)
26 | (assoc :acceleration [0 0])
27 | (assoc :lifespan lifespan)
28 | (assoc :aVelocity aVelocity)
29 | (assoc :angle (+ aVelocity angle))
30 | (assoc :aAcceleration 0))))
31 |
32 | (defn apply-force [particle force]
33 | (update particle :acceleration #(v/add % force)))
34 |
35 | (defn display [{:keys [lifespan angle] [x y] :location :as particle}]
36 | (q/push-matrix)
37 | (q/rect-mode :center)
38 | (q/translate x y)
39 | (q/rotate angle)
40 | (q/stroke 0 lifespan)
41 | (q/fill 127 0 0 lifespan)
42 | (q/rect 0 0 8 8)
43 | (q/pop-matrix)
44 | particle)
45 |
46 | (defn is-dead [{:keys [lifespan]}]
47 | (< lifespan 0.0))
48 |
49 | (defn setup []
50 | ())
51 |
52 | (defn update-state [particles]
53 | (->> (conj particles (create-particle [(q/mouse-x) (q/mouse-y)]))
54 | (map (fn [particle]
55 | (-> particle
56 | update-particle
57 | (apply-force [0 -0.1]))))
58 | (remove is-dead)))
59 |
60 | (defn draw [particles]
61 | (q/background 255)
62 | (doseq [particle particles]
63 | (display particle)))
64 |
65 | (defn run [host]
66 | (q/defsketch dynamic-origin
67 | :host host
68 | :setup setup
69 | :draw draw
70 | :update update-state
71 | :middleware [md/fun-mode]
72 | :size [300 300]))
73 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/fire.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.fire
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]))
5 |
6 | (defn setup []
7 | (q/blend-mode :add)
8 | {:particles () :origin [150 200]})
9 |
10 | (defn create-particle [location]
11 | (-> (m/create-mover 10 location)
12 | (assoc :velocity [(* (q/random-gaussian) 0.3) (- (* (q/random-gaussian) 0.4) 1.0)]
13 | :lifespan 255.0)))
14 |
15 | (defn is-dead [{:keys [lifespan]}] (< lifespan 0.0))
16 |
17 | (defn update-lifespan [particle] (update particle :lifespan (comp dec dec)))
18 |
19 | (defn update-state [ps]
20 | (-> ps
21 | (update :particles #(conj % (create-particle (:origin ps))))
22 | (update :particles #(conj % (create-particle (:origin ps))))
23 | (update :particles #(map (comp update-lifespan m/update-mover) %))
24 | (update :particles #(remove is-dead %))))
25 |
26 | (defn draw-particle [{:keys [lifespan] [x y] :location}]
27 | (q/color-mode :rgb)
28 | (q/fill (q/color 255 24 0 lifespan))
29 | (q/ellipse x y (q/map-range lifespan 0 255 0 24) (q/map-range lifespan 0 255 0 24)))
30 |
31 | (defn draw [{:keys [particles]}]
32 | (q/clear)
33 | (q/background 0)
34 | (doseq [particle particles]
35 | (draw-particle particle)))
36 |
37 | (defn run [host]
38 | (q/defsketch fire
39 | :host host
40 | :setup setup
41 | :draw draw
42 | :update update-state
43 | :middleware [md/fun-mode]
44 | :size [300 300]))
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/fire_blend.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.fire-blend
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn setup []
8 | (q/image-mode :center)
9 | (q/color-mode :hsb)
10 | (q/no-stroke)
11 | {:particles ()
12 | :image (q/load-image "images/texture-white.png")})
13 |
14 | (defn create-texture [location]
15 | (assoc (m/create-mover 10 location)
16 | :velocity [(* (q/random-gaussian) 0.8) (- (q/random-gaussian) 1.0)]
17 | :lifespan 255.0))
18 |
19 | (defn is-dead [{:keys [lifespan]}]
20 | (< lifespan 0.0))
21 |
22 | (defn apply-force [force {:keys [mass acceleration] :as particle}]
23 | (assoc particle :acceleration (v/add acceleration (v/div force mass))))
24 |
25 | (defn dec-lifespan [particle] (update particle :lifespan (comp dec dec)))
26 |
27 | (defn update-state [state]
28 | (update state :particles
29 | #(->> (conj % (create-texture [0 100]))
30 | (map (comp m/compute-position dec-lifespan))
31 | (remove is-dead))))
32 |
33 | (defn draw-particle [{:keys [lifespan] [x y] :location} image]
34 | (q/tint lifespan 255 255)
35 | (q/image image x y
36 | (q/map-range lifespan 255 0 100 0)
37 | (q/map-range lifespan 255 0 100 0)))
38 |
39 | (defn draw [{:keys [particles image]}]
40 | (q/blend-mode :exclusion)
41 | (q/background 255)
42 | (q/color-mode :hsb)
43 | (doseq [particle particles]
44 | (draw-particle particle image)))
45 |
46 | (defn run [host]
47 | (q/defsketch fire-blend
48 | :host host
49 | :setup setup
50 | :draw draw
51 | :update update-state
52 | :middleware [md/fun-mode]
53 | :size [300 300]
54 | :renderer :p3d))
55 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/fire_rainbow.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.fire-rainbow
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (defn setup []
8 | (q/image-mode :center)
9 | (q/color-mode :hsb)
10 | (q/no-stroke)
11 | {:particles ()
12 | :image (q/load-image "images/texture-white.png")})
13 |
14 | (defn create-texture [location]
15 | (assoc (m/create-mover 10 location)
16 | :velocity [(* (q/random-gaussian) 0.8) (- (q/random-gaussian) 1.0)]
17 | :lifespan 255.0))
18 |
19 | (defn is-dead [{:keys [lifespan]}]
20 | (< lifespan 0.0))
21 |
22 | (defn apply-force [force {:keys [mass acceleration] :as particle}]
23 | (assoc particle :acceleration (v/add acceleration (v/div force mass))))
24 |
25 | (defn dec-lifespan [particle] (update particle :lifespan (comp dec dec)))
26 |
27 | (defn update-state [state]
28 | (update state :particles
29 | #(->> (conj % (create-texture [0 100]))
30 | (map (comp m/compute-position dec-lifespan))
31 | (remove is-dead))))
32 |
33 | (defn draw-particle [{:keys [lifespan] [x y] :location} image]
34 | (q/tint lifespan 255 255)
35 | (q/image image x y
36 | (q/map-range lifespan 255 0 100 0)
37 | (q/map-range lifespan 255 0 100 0)))
38 |
39 | (defn draw [{:keys [particles image]}]
40 | (q/blend-mode :add)
41 | (q/background 0)
42 | (q/color-mode :hsb)
43 | (doseq [particle particles]
44 | (draw-particle particle image)))
45 |
46 | (defn run [host]
47 | (q/defsketch rainbow-fire
48 | :host host
49 | :setup setup
50 | :draw draw
51 | :update update-state
52 | :middleware [md/fun-mode]
53 | :size [300 300]
54 | :renderer :p3d))
55 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/mixed_particles.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.mixed-particles
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]))
5 |
6 | (defn setup []
7 | {:particles ()
8 | :origin [(/ (q/width) 2) (/ (q/height) 2)]})
9 |
10 | (defn create-particle [location]
11 | (-> (m/create-mover 100 location)
12 | (assoc :velocity [(- (rand 2) 1) (- (rand 2) 2)])
13 | (assoc :acceleration [0 0.05])
14 | (assoc :a-acceleration 0.1)
15 | (assoc :lifespan 255)))
16 |
17 | (defn create-confetti [location]
18 | (-> (create-particle location)
19 | (assoc :type :confetti)))
20 |
21 | (defmulti draw-particle :type)
22 |
23 | (defmethod draw-particle :confetti [{:keys [lifespan angle] [x y] :location :as particle}]
24 | (q/rect-mode :center)
25 | (q/fill 175 lifespan)
26 | (q/stroke 0 lifespan)
27 | (q/push-matrix)
28 | (q/translate x y)
29 | (q/rotate angle)
30 | (q/rect 0 0 8 8)
31 | (q/pop-matrix)
32 | particle)
33 |
34 |
35 | (defmethod draw-particle :default [{:keys [lifespan] [x y] :location :as particle}]
36 | (q/stroke 0 lifespan)
37 | (q/fill 0 lifespan)
38 | (q/ellipse x y 8 8)
39 | particle)
40 |
41 | (defn is-dead [{:keys [lifespan]}] (< lifespan 0.0))
42 |
43 | (defn decrease-lifespan [particle]
44 | (update particle :lifespan (comp dec dec)))
45 |
46 | (defn update-state [{:keys [origin] :as ps}]
47 | (-> ps
48 | (update :particles #(conj % (if (> (q/random 1) 0.5) (create-particle origin) (create-confetti origin))))
49 | (update :particles #(map (comp m/compute-position decrease-lifespan) %))
50 | (update :particles #(remove is-dead %))))
51 |
52 | (defn draw [{:keys [particles]}]
53 | (q/background 255)
54 | (doseq [particle particles]
55 | (draw-particle particle)))
56 |
57 | (defn run [host]
58 | (q/defsketch mixed-particles
59 | :host host
60 | :setup setup
61 | :draw draw
62 | :update update-state
63 | :middleware [md/fun-mode]
64 | :size [300 300]))
65 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/particle_force.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.particle-force
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn create-particle [location]
7 | {:location location
8 | :velocity [(- (rand 2) 1) (- (rand 2) 2)]
9 | :acceleration [0 0.05]
10 | :lifespan 255.0})
11 |
12 | (defn update-particle [{:keys [acceleration velocity location lifespan] :as particle}]
13 | (let [velocity (v/add velocity acceleration)
14 | location (v/add velocity location)
15 | lifespan (- lifespan 2.0)]
16 | (-> particle
17 | (assoc :velocity velocity)
18 | (assoc :location location)
19 | (assoc :lifespan lifespan))))
20 |
21 | (defn apply-force [particle force]
22 | (update particle :acceleration #(v/add % force)))
23 |
24 | (defn display [{:keys [lifespan] [x y] :location}]
25 | (q/stroke 0 lifespan)
26 | (q/fill 0 lifespan)
27 | (q/ellipse x y 8 8))
28 |
29 | (defn is-dead [{:keys [lifespan]}]
30 | (< lifespan 0.0))
31 |
32 | (defn setup []
33 | (create-particle [(/ (q/width) 2) (/ (q/height) 2)]))
34 |
35 | (defn update-state [particle]
36 | (if (is-dead particle)
37 | (create-particle [(/ (q/width) 2) (/ (q/height) 2)])
38 | (-> particle
39 | (apply-force [-0.01 0.01])
40 | update-particle)))
41 |
42 | (defn draw [particle]
43 | (q/background 255)
44 | (display particle))
45 |
46 | (defn run [host]
47 | (q/defsketch particle-force
48 | :host host
49 | :setup setup
50 | :draw draw
51 | :update update-state
52 | :middleware [md/fun-mode]
53 | :size [300 300]))
54 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/particles_on_click.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.particles-on-click
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn create-particle [location]
7 | {:location location
8 | :velocity [(- (rand 2) 1) (- (rand 2) 1)]
9 | :acceleration [0 0]
10 | :lifespan 255.0
11 | :aAcceleration 0.0
12 | :aVelocity 0.1
13 | :angle 0.0})
14 |
15 | (defn setup []
16 | ())
17 |
18 | (defn update-particle [{:keys [acceleration velocity location lifespan
19 | aVelocity aAcceleration angle]
20 | :as particle}]
21 | (let [velocity (v/add velocity acceleration)
22 | location (v/add velocity location)
23 | lifespan (- lifespan 2.0)
24 | aVelocity (+ aVelocity aAcceleration)
25 | angle (+ aVelocity angle)]
26 | (-> particle
27 | (assoc :velocity velocity)
28 | (assoc :location location)
29 | (assoc :acceleration [0 0])
30 | (assoc :lifespan lifespan)
31 | (assoc :aVelocity aVelocity)
32 | (assoc :angle (+ aVelocity angle))
33 | (assoc :aAcceleration 0))))
34 |
35 | (defn is-dead [{:keys [lifespan]}] (< lifespan 0.0))
36 |
37 | (defn update-particle-system [{:keys [particles count]
38 | [x y] :location
39 | :as particle-system}]
40 | (assoc particle-system
41 | :count (dec count)
42 | :particles (let [particles (if (> count 1)
43 | (conj particles (create-particle [x y]))
44 | particles)]
45 | (->> particles
46 | (map update-particle)
47 | (remove is-dead)))))
48 |
49 | (defn create-particle-system [x y count]
50 | {:location [x y]
51 | :count count
52 | :particles []})
53 |
54 | (defn update-state [particle-systems]
55 | (map update-particle-system particle-systems))
56 |
57 | (defn draw-particle [{:keys [lifespan angle] [x y] :location}]
58 | (q/push-matrix)
59 | (q/rect-mode :center)
60 | (q/translate x y)
61 | (q/rotate angle)
62 | (q/stroke 0 lifespan)
63 | (q/fill 127 0 0 lifespan)
64 | (q/rect 0 0 8 8)
65 | (q/pop-matrix))
66 |
67 | (defn draw [particle-systems]
68 | (q/background 255)
69 | (doseq [particle-system particle-systems]
70 | (doseq [particle (:particles particle-system)]
71 | (draw-particle particle))))
72 |
73 | (defn mouse-pressed [state {:keys [x y]}]
74 | (conj state (create-particle-system x y 50)))
75 |
76 | (defn run [host]
77 | (q/defsketch particles-on-click
78 | :host host
79 | :setup setup
80 | :draw draw
81 | :update update-state
82 | :middleware [md/fun-mode]
83 | :mouse-pressed mouse-pressed
84 | :size [300 300]))
85 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/particles_repel.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.particles-repel
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]
5 | [sketches.vector :as v]))
6 |
7 | (def gravity [0 0.3])
8 |
9 | (defn setup []
10 | {:particles () :origin [(/ (q/width) 2) (/ (q/height) 2)]})
11 |
12 | (defn create-particle [location]
13 | (assoc
14 | (m/create-mover 20 location)
15 | :velocity [(- (rand 2) 1) (- (rand 2) 2)]
16 | :lifespan 255.0))
17 |
18 | (defn create-confetti [location]
19 | (-> (create-particle location)
20 | (assoc :type :confetti
21 | :a-acceleration 0.1)))
22 |
23 | (defn is-dead [{:keys [lifespan]}] (< lifespan 0.0))
24 |
25 | (defn decrease-lifespan [particle] (update particle :lifespan (comp dec dec)))
26 |
27 | (defn repel [{:keys [location mass]} particle]
28 | (let [dir (v/sub location, (:location particle))
29 | d (q/constrain (v/mag dir) 5 100)
30 | force (/ (* -1 mass) (* d d))]
31 | (v/mult (v/normalize dir) force)))
32 |
33 | (defn update-state [ps]
34 | (-> ps
35 | (update :particles
36 | #(map (fn [particle]
37 | (reduce
38 | (fn [particle repeller]
39 | (m/apply-force particle (repel repeller particle)))
40 | particle
41 | %))
42 | %))
43 | (update :particles #(conj % (apply (if (> (q/random 1) 0.5)
44 | create-particle
45 | create-confetti)
46 | (list (:origin ps)))))
47 | (update :particles #(map (fn [particle] (m/apply-force particle gravity)) %))
48 | (update :particles #(map (comp decrease-lifespan m/compute-position) %))
49 | (update :particles #(remove is-dead %))))
50 |
51 | (defmulti draw-particle :type)
52 | (defmethod draw-particle :confetti [{:keys [lifespan angle] [x y] :location :as particle}]
53 | (q/rect-mode :center)
54 | (q/fill 175 lifespan)
55 | (q/stroke 0 lifespan)
56 | (q/push-matrix)
57 | (q/translate x y)
58 | (q/rotate angle)
59 | (q/rect 0 0 8 8)
60 | (q/pop-matrix)
61 | particle)
62 | (defmethod draw-particle :default [{:keys [lifespan] [x y] :location :as particle}]
63 | (q/stroke 0 lifespan)
64 | (q/fill 0 lifespan)
65 | (q/ellipse x y 8 8)
66 | particle)
67 |
68 | (defn draw [{:keys [particles]}]
69 | (q/background 255)
70 | (doseq [particle particles]
71 | (draw-particle particle)))
72 |
73 | (defn run [host]
74 | (q/defsketch particles-repel
75 | :host host
76 | :setup setup
77 | :draw draw
78 | :update update-state
79 | :middleware [md/fun-mode]
80 | :size [300 300]))
81 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/particles_with_images.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.particles-with-images
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.mover :as m]))
5 |
6 | (defn create-particle [location images]
7 | (assoc (m/create-mover 10 location)
8 | :velocity [(q/random-gaussian) (- (q/random-gaussian) 1.0)]
9 | :lifespan 255.0
10 | :mass 10
11 | :image (rand-nth images)))
12 |
13 | (defn setup []
14 | (q/frame-rate 30)
15 | {:images [(q/load-image "images/sojka.jpg")
16 | (q/load-image "images/fcb.jpg")
17 | (q/load-image "images/emacs.png")]
18 | :particles ()
19 | :origin [(/ (q/width) 2) (/ (q/height) 2)]})
20 |
21 | (defn draw-particle [{:keys [lifespan image] [x y] :location}]
22 | (q/image-mode :center)
23 | (q/tint 255 lifespan)
24 | (q/image image x y 80 80))
25 |
26 | (defn is-dead [{:keys [lifespan]}] (< lifespan 0.0))
27 | (defn dec-lifespan [particle] (update particle :lifespan (comp dec dec dec dec dec)))
28 |
29 | (defn update-state [{:keys [images] :as ps}]
30 | (-> ps
31 | (update :particles #(conj % (create-particle (:origin ps) images)))
32 | (update :particles #(map (comp m/compute-position dec-lifespan) %))
33 | (update :particles #(remove is-dead %))))
34 |
35 | (defn draw [{:keys [particles]}]
36 | (q/background 255)
37 | (doseq [particle particles]
38 | (draw-particle particle)))
39 |
40 | (defn run [host]
41 | (q/defsketch particles-with-images
42 | :host host
43 | :setup setup
44 | :draw draw
45 | :update update-state
46 | :middleware [md/fun-mode]
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/particle_systems/rotating_particle.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.particle-systems.rotating-particle
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn create-particle [location]
7 | {:location location
8 | :velocity [(- (rand 2) 1) (- (rand 2) 2)]
9 | :acceleration [0 0.05]
10 | :lifespan 255.0
11 | :aAcceleration 0.0
12 | :aVelocity 0.1
13 | :angle 0.0})
14 |
15 | (defn update-particle [{:keys [acceleration velocity location lifespan
16 | aVelocity aAcceleration angle]
17 | :as particle}]
18 | (let [velocity (v/add velocity acceleration)
19 | location (v/add velocity location)
20 | lifespan (- lifespan 2.0)
21 | aVelocity (+ aVelocity aAcceleration)
22 | angle (+ aVelocity angle)]
23 | (-> particle
24 | (assoc :velocity velocity)
25 | (assoc :location location)
26 | (assoc :acceleration [0 0])
27 | (assoc :lifespan lifespan)
28 | (assoc :aVelocity aVelocity)
29 | (assoc :angle (+ aVelocity angle))
30 | (assoc :aAcceleration 0))))
31 |
32 | (defn apply-force [particle force]
33 | (update particle :acceleration #(v/add % force)))
34 |
35 | (defn draw-particle [{:keys [lifespan angle] [x y] :location :as particle}]
36 | (q/push-matrix)
37 | (q/rect-mode :center)
38 | (q/translate x y)
39 | (q/rotate angle)
40 | (q/stroke 0 lifespan)
41 | (q/fill 0 lifespan)
42 | (q/rect 0 0 8 8)
43 | (q/pop-matrix)
44 | particle)
45 |
46 | (defn is-dead [{:keys [lifespan]}]
47 | (< lifespan 0.0))
48 |
49 | (defn setup []
50 | (create-particle [(/ (q/width) 2) (/ (q/height) 2)]))
51 |
52 | (defn update-state [particle]
53 | (if (is-dead particle)
54 | (create-particle [(/ (q/width) 2) (/ (q/height) 2)])
55 | (-> particle
56 | (apply-force [0.1 0])
57 | update-particle)))
58 |
59 | (defn draw [particle]
60 | (q/background 255)
61 | (draw-particle particle))
62 |
63 |
64 | (defn run [host]
65 | (q/defsketch rotating-particle
66 | :host host
67 | :setup setup
68 | :draw draw
69 | :update update-state
70 | :middleware [md/fun-mode]
71 | :size [300 300]))
72 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/physics_library/box_shapes.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.physics-library.box-shapes
2 | (:require matter-js
3 | [quil.core :as q :include-macros true]
4 | [quil.middleware :as md]
5 | [sketches.nature-of-code.physics-library.matter :as m]))
6 |
7 | (defn setup []
8 | (q/frame-rate 30)
9 | (let [engine (.create (.-Engine matter-js))
10 | ground (m/rect 150 300 300 60 {:isStatic true})]
11 | (m/add engine ground)))
12 |
13 | (defn update-state [engine]
14 | (m/update-engine engine))
15 |
16 | (defn draw [engine]
17 | (m/render engine))
18 |
19 | (defn mouse-pressed [engine {:keys [x y]}]
20 | (m/add engine (m/rect x y 20 20)))
21 |
22 | (defn run [host]
23 | (q/defsketch box-shapes
24 | :host host
25 | :setup setup
26 | :draw draw
27 | :update update-state
28 | :mouse-pressed mouse-pressed
29 | :middleware [md/fun-mode]
30 | :size [300 300]))
31 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/physics_library/circular_shapes.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.physics-library.circular-shapes
2 | (:require matter-js
3 | [quil.core :as q :include-macros true]
4 | [quil.middleware :as md]
5 | [sketches.nature-of-code.physics-library.matter :as m]))-
6 |
7 | (defn setup []
8 | (q/frame-rate 30)
9 | (let [engine (.create (.-Engine matter-js))
10 | ground (m/rect 150 300 300 60 {:isStatic true})]
11 | (m/add engine ground)))
12 |
13 | (defn update-state [engine]
14 | (m/update-engine engine))
15 |
16 | (defn draw [engine]
17 | (m/render engine))
18 |
19 | (defn mouse-pressed [engine {:keys [x y]}]
20 | (m/add engine (m/circle x y 20 20)))
21 |
22 | (defn run [host]
23 | (q/defsketch circular-shapes
24 | :host host
25 | :setup setup
26 | :draw draw
27 | :update update-state
28 | :middleware [md/fun-mode]
29 | :mouse-pressed mouse-pressed
30 | :size [300 300]))
31 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/physics_library/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.physics-library.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.physics-library.box-shapes :as bs]
4 | [sketches.nature-of-code.physics-library.circular-shapes :as cs]))
5 |
6 | (defn main []
7 | [:div
8 | [:h3.tracked.tc.tl-ns "Physics Libraries"]
9 | [cards-container
10 | [:<>
11 | [exercise-card "Circular Shapes" "Exercise 5.1" "https://natureofcode.com/book/chapter-5-physics-libraries/#chapter05_exercise1" cs/run]
12 | [exercise-card "Box Shapes" "Exercise 5.2" "https://natureofcode.com/book/chapter-5-physics-libraries/#chapter05_exercise2" bs/run]]]])
13 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/physics_library/matter.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.physics-library.matter
2 | (:require [matter-js]
3 | [quil.core :as q]))
4 |
5 | (def bodies (.-Bodies matter-js))
6 | (def world (.-World matter-js))
7 |
8 | (defn rect
9 | ([x y width height]
10 | (rect x y width height nil))
11 | ([x y width height params]
12 | (.rectangle bodies x y width height (clj->js params))))
13 |
14 | (defn circle
15 | ([x y width height]
16 | (circle x y width height nil))
17 | ([x y width height params]
18 | (.circle bodies x y width height (clj->js params))))
19 |
20 | (defn add [engine & composites]
21 | (.add world ^js (.-world engine) (clj->js composites))
22 | engine)
23 |
24 | (defn update-engine [engine]
25 | (.update (.-Engine matter-js) engine (/ 1000 30)))
26 |
27 | (defn render [engine]
28 | (q/clear)
29 | (doseq [body (.allBodies (.-Composite matter-js) ^js (.-world engine))]
30 | (q/begin-shape)
31 | (doseq [vert (.-vertices body)]
32 | (q/vertex (.-x vert) (.-y vert)))
33 | (q/end-shape :close)))
34 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/vectors/bouncing_ball.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.vectors.bouncing-ball
2 | (:require [quil.core :as q :include-macros true]))
3 |
4 | (def location (atom (hash-map :x 0 :y 0 :z 0)))
5 | (def velocity (atom (hash-map :x 1.5 :y 1.5 :z 3.5)))
6 |
7 | (defn add [v1 v2]
8 | (hash-map :x (+ (:x v1) (:x v2))
9 | :y (+ (:y v1) (:y v2))
10 | :z (+ (:z v1) (:z v2))))
11 |
12 | (defn setup []
13 | (q/background 255))
14 |
15 | (defn draw []
16 | (q/background 255)
17 | (q/stroke 127)
18 | (q/no-fill)
19 | (q/rotate-x q/THIRD-PI)
20 | (q/rotate-z 0.1)
21 | (let [location (swap! location #(add % @velocity))
22 | velocity (swap! velocity (fn [{:keys [x y z]}]
23 | (hash-map
24 | :x (if (or (> (:x location) 125) (< (:x location) -125))
25 | (* x -1) x)
26 | :y (if (or (> (:y location) 90) (< (:y location) -125))
27 | (* y -1) y)
28 | :z (if (or (> (:z location) 90) (< (:z location) -125))
29 | (* z -1) z))))]
30 | (q/box 250)
31 | (q/push-matrix)
32 | (q/translate (:x location) (:y location) (:z location))
33 | (q/sphere 40)
34 | (q/pop-matrix)))
35 |
36 | (defn run [host]
37 | (q/defsketch bouncing-ball
38 | :host host
39 | :setup setup
40 | :draw draw
41 | :size [500 500]
42 | :renderer :p3d))
43 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/vectors/car.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.vectors.car
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]
4 | [quil.middleware :as md]))
5 |
6 | (defn setup []
7 | (q/background 255)
8 | (q/ellipse-mode :center)
9 | {:acceleration [0 0]
10 | :velocity [0 0]
11 | :location [150 150]})
12 |
13 | (defn move-through [{[x y] :location :as vehicle}]
14 | (assoc vehicle :location [(cond
15 | (> x (q/width)) 0
16 | (< x 0) (q/width)
17 | :else x)
18 | (cond
19 | (> y (q/height)) 0
20 | (< y 0) (q/height)
21 | :else y)]))
22 |
23 | (defn update-state [{:keys [location acceleration velocity]}]
24 | (move-through
25 | {:acceleration acceleration
26 | :velocity (v/limit (v/add velocity acceleration) 10)
27 | :location (v/add (v/add velocity acceleration) location)}))
28 |
29 | (defn draw [{[x y] :location}]
30 | (q/background 255)
31 | (q/fill 0)
32 | (q/ellipse x y 16 16))
33 |
34 | (defn on-key-down [state ev]
35 | (cond (= (:key ev) :up) (update state :acceleration v/add [0 -0.001])
36 | (= (:key ev) :down) (update state :acceleration v/add [0 0.001])
37 | :else state))
38 |
39 | (defn run [host]
40 | (q/defsketch car-sketch
41 | :host host
42 | :setup setup
43 | :key-pressed on-key-down
44 | :draw draw
45 | :update update-state
46 | :middleware [md/fun-mode]
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/vectors/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.vectors.core
2 | (:require [sketches.components :refer [cards-container exercise-card]]
3 | [sketches.nature-of-code.vectors.bouncing-ball :as bb]
4 | [sketches.nature-of-code.vectors.car :as c]
5 | [sketches.nature-of-code.vectors.mouse-acceleration :as ma]
6 | [sketches.nature-of-code.vectors.noise-car :as nc]))
7 |
8 | (defn main []
9 | [:div
10 | [:h3.tracked.tc.tl-ns "Vectors"]
11 | [cards-container
12 | [:<>
13 | [exercise-card "Bouncing Ball" "Exercise 1.3" "https://natureofcode.com/book/chapter-1-vectors#chapter01_exercise3" bb/run]
14 | [exercise-card "Car" "Exercise 1.5" "https://natureofcode.com/book/chapter-1-vectors#chapter01_exercise5" c/run]
15 | [exercise-card "Noise Car" "Exercise 1.6" "https://natureofcode.com/book/chapter-1-vectors#chapter01_exercise6" nc/run]
16 | [exercise-card "Mouse Acceleration" "Exercise 1.8" "https://natureofcode.com/book/chapter-1-vectors#chapter01_exercise8" ma/run]]]])
17 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/vectors/mouse_acceleration.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.vectors.mouse-acceleration
2 | (:require [quil.core :as q :include-macros true]
3 | [sketches.vector :as v]
4 | [quil.middleware :as md]))
5 |
6 | (defn setup []
7 | (q/ellipse-mode :center)
8 | {:acceleration [0 0]
9 | :velocity [0 0]
10 | :location [0 0]})
11 |
12 | (defn update-state [{:keys [velocity location]}]
13 | (let [distance (v/sub [(q/mouse-x) (q/mouse-y)] location)
14 | acceleration (v/mult (v/normalize distance)
15 | (* 0.001 (v/mag distance)))
16 | velocity (v/limit (v/add acceleration velocity) 5)]
17 | {:acceleration acceleration
18 | :velocity velocity
19 | :location (v/add location velocity)}))
20 |
21 | (defn draw [{[x y] :location}]
22 | (q/background 255)
23 | (q/translate 32 32)
24 | (q/ellipse x y 32 32))
25 |
26 | (defn run [host]
27 | (q/defsketch mouse-acceleration
28 | :host host
29 | :setup setup
30 | :draw draw
31 | :update update-state
32 | :middleware [md/fun-mode]
33 | :size [300 300]))
34 |
--------------------------------------------------------------------------------
/src/sketches/nature_of_code/vectors/noise_car.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.nature-of-code.vectors.noise-car
2 | (:require [quil.core :as q]
3 | [sketches.vector :as v]
4 | [quil.middleware :as md]))
5 |
6 | (defn setup []
7 | (q/background 255)
8 | (q/ellipse-mode :center)
9 | {:acceleration [0 0]
10 | :velocity [0 0]
11 | :location [150 150]
12 | :xoff 0.0
13 | :yoff 0.0})
14 |
15 | (defn move-through [{[x y] :location :as vehicle}]
16 | (assoc vehicle :location [(cond
17 | (> x (q/width)) 0
18 | (< x 0) (q/width)
19 | :else x)
20 | (cond
21 | (> y (q/height)) 0
22 | (< y 0) (q/height)
23 | :else y)]))
24 |
25 | (defn update-state [{:keys [location acceleration velocity
26 | xoff yoff]}]
27 | (move-through
28 | (let [acceleration [0 (q/map-range (q/noise xoff yoff) 0 1 -0.01 0.01)]
29 | velocity (v/limit (v/add velocity acceleration) 10)]
30 | {:acceleration acceleration
31 | :velocity velocity
32 | :location (v/add (v/add velocity acceleration) location)
33 | :xoff (+ xoff 0.0001)
34 | :yoff (+ yoff 0.0001)})))
35 |
36 | (defn draw [{[x y] :location}]
37 | (q/background 255)
38 | (q/fill 0)
39 | (q/ellipse x y 16 16))
40 |
41 | (defn run [host]
42 | (q/defsketch car-sketch
43 | :host host
44 | :setup setup
45 | :draw draw
46 | :update update-state
47 | :middleware [md/fun-mode]
48 | :size [300 300]))
49 |
--------------------------------------------------------------------------------
/src/sketches/plotting/eye_of_sine.clj:
--------------------------------------------------------------------------------
1 | (ns sketches.plotting.eye-of-sine
2 | (:require [thi.ng.geom.svg.adapter :as adapt]
3 | [thi.ng.geom.svg.core :as svg :refer [ellipse]]))
4 | (def scene
5 | (svg/svg
6 | {:width 300 :height 300}
7 | (svg/group
8 | {}
9 | (let [rings 50]
10 | (map
11 | (fn [i]
12 | (let [progress-in-percent (/ i rings)
13 | cur-pi (* progress-in-percent Math/PI)
14 | min-width 0
15 | max-additional-width 80]
16 | (ellipse [150 (+ 20 (* 5 i))] (+ min-width (* max-additional-width (Math/sin cur-pi))) 10
17 | {:fill "none" :stroke "black"})))
18 | (range rings))))
19 | (svg/group
20 | {:transform "rotate(90) translate(0 -300)"}
21 | (let [rings 50]
22 | (map
23 | (fn [i]
24 | (let [progress-in-percent (/ i rings)
25 | cur-pi (* progress-in-percent Math/PI)
26 | min-width 0
27 | max-additional-width 80]
28 | (ellipse [150 (+ 20 (* 5 i))] (+ min-width (* max-additional-width (Math/sin cur-pi))) 10
29 | {:fill "none" :stroke "black"})))
30 | (range rings))))))
31 |
32 | (comment
33 | (->> scene
34 | adapt/all-as-svg
35 | svg/serialize
36 | (spit "temp.svg")))
37 |
38 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/core.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.core
2 | (:require [sketches.components :refer [card cards-container sketch]]
3 | [sketches.rac-sketches.fire-ball :as fb]
4 | [sketches.rac-sketches.fire-texture :as ft]
5 | [sketches.rac-sketches.flowers :as flo]
6 | [sketches.rac-sketches.heart-of-clojure :as hc]
7 | [sketches.rac-sketches.inferno :as i]
8 | [sketches.rac-sketches.noise-colors :as noc]
9 | [sketches.rac-sketches.particle-party :as pp]
10 | [sketches.rac-sketches.rainbow-circles :as rc]
11 | [sketches.rac-sketches.reverse-roots :as rr]
12 | [sketches.rac-sketches.rotating-angles :as ra]
13 | [sketches.rac-sketches.text-snake :as ts]))
14 |
15 | (defn rac-card [title run-sketch run-immediately]
16 | (fn []
17 | [card
18 | title
19 | ""
20 | [sketch title run-sketch run-immediately]]))
21 |
22 | (defn main []
23 | [:<>
24 | [:div
25 | [cards-container
26 | [:<>
27 | #_[rac-card "Margarete Fountain" mf/run true]
28 | [rac-card "Text Snake" ts/run]
29 | [rac-card "Noise Colors" noc/run]
30 | [rac-card "Heart of Clojure" hc/run]
31 | [rac-card "Inferno" i/run]
32 | [rac-card "Reverse Roots" rr/run]
33 | [rac-card "Fire Ball" fb/run]
34 | [rac-card "Fire Texture" ft/run]
35 | [rac-card "Flower" flo/run]
36 | [rac-card "Rainbow Circles" rc/run]
37 | [rac-card "Oscillating Angles" ra/run ]
38 | [rac-card "Particle Party" pp/run]]]]])
39 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/fire_ball.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.fire-ball
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn setup []
8 | (q/blend-mode :add)
9 | (q/no-stroke)
10 | {:particles ()})
11 |
12 | (defn update-particle [particle]
13 | (let [gravity [(* (q/random-gaussian) 0.01) (* (- (q/random-gaussian) 0.8) 0.02)]
14 | wind [(q/random -0.1 0.1) 0]]
15 | (-> particle
16 | (m/update-mover (v/add gravity wind))
17 | (update :lifespan dec))))
18 |
19 | (defn create-particle []
20 | {:acceleration [0 0]
21 | :velocity [0 0]
22 | :location [(/ (q/width) 2) (* (q/height) 0.8)]
23 | :lifespan 255})
24 |
25 | (defn update-state [{:keys [particles]}]
26 | {:particles
27 | (->> (conj particles (create-particle))
28 | (filter (fn [{:keys [lifespan]}] (>= lifespan 0)))
29 | (map update-particle))})
30 |
31 | (defn draw-particle [{[x y] :location :keys [lifespan]}]
32 | (let [blue (q/color 255 127 64 lifespan)
33 | red (q/color 0 0)]
34 | (dotimes [i 6]
35 | (q/fill (q/lerp-color red blue (/ i 5)))
36 | (q/ellipse x y
37 | (/ (* lifespan (/ 256 (inc i))) 255)
38 | (/ (* lifespan (/ 256 (inc i))) 255)))))
39 |
40 | (defn draw [{:keys [particles]}]
41 | (q/clear)
42 | (doall (map draw-particle particles)))
43 |
44 | (defn run [host]
45 | (q/defsketch particles
46 | :host host
47 | :setup setup
48 | :draw draw
49 | :update update-state
50 | :middleware [md/fun-mode]
51 | :size [300 300]))
52 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/fire_texture.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.fire-texture
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]))
5 |
6 | (defn setup []
7 | (q/no-stroke)
8 | (q/blend-mode :add)
9 | (q/image-mode :center)
10 | {:particles ()
11 | :origin [(/ (q/width) 2) (* (q/height) 0.6)]
12 | :image (q/load-image "images/texture.png")})
13 |
14 | (defn create-particle [location]
15 | {:location location
16 | :velocity [(* (q/random-gaussian) 0.3) (- (* (q/random-gaussian) 0.4) 1.0)]
17 | :acceleration [0 0]
18 | :lifespan 255.0
19 | :mass 10})
20 |
21 | (defn is-dead [{:keys [lifespan]}] (< lifespan 0.0))
22 |
23 | (defn apply-force [force {:keys [mass acceleration] :as particle}]
24 | (assoc particle :acceleration (v/add acceleration (v/div force mass))))
25 |
26 | (defn update-particle [{:keys [acceleration velocity location lifespan] :as particle}]
27 | (let [velocity (v/add velocity acceleration)
28 | location (v/add velocity location)]
29 | (-> particle
30 | (assoc :velocity velocity)
31 | (assoc :location location)
32 | (assoc :lifespan (- lifespan 2.0))
33 | (assoc :acceleration [0 0]))))
34 |
35 | (defn update-state [{:keys [origin] :as state}]
36 | (let [wind [(q/map-range (q/mouse-x) 0.0 (q/width) -0.3 0.3)
37 | (q/map-range (q/mouse-y) 0.0 (q/height) -0.3 0.3)]]
38 | (-> state
39 | (update :particles #(conj % (create-particle origin)))
40 | (update :particles #(map (partial apply-force wind) %))
41 | (update :particles #(map update-particle %))
42 | (update :particles #(remove is-dead %)))))
43 |
44 | (defn draw-particle [{:keys [lifespan] [x y] :location :as particle} image]
45 | (q/background 0 0 0)
46 | (q/tint 255 127 64 lifespan)
47 | (when (q/loaded? image) (q/image image x y)))
48 |
49 | (defn draw [{:keys [particles image]}]
50 | (q/clear)
51 | (doseq [particle particles]
52 | (draw-particle particle image)))
53 |
54 | (defn run [host]
55 | (q/defsketch fire-texture
56 | :host host
57 | :setup setup
58 | :draw draw
59 | :update update-state
60 | :middleware [md/fun-mode]
61 | :size [300 300]))
62 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/flowers.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.flowers
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/color-mode :hsb)
7 | (q/frame-rate 2)
8 | 1)
9 |
10 | (defn constrain-petal-counts [petal-count]
11 | (if (< petal-count 20) petal-count 0))
12 |
13 | (defn update-state [petal-count]
14 | (constrain-petal-counts (+ petal-count 1)))
15 |
16 | (defn draw [petal-count]
17 | (q/clear)
18 | (q/translate [(/ (q/width) 2) (/ (q/height) 2)])
19 | (q/fill (q/random 0 255) 100 255)
20 | (doseq [angle (range 0 q/TWO-PI (/ q/TWO-PI petal-count))]
21 | (q/with-rotation [angle]
22 | (q/bezier 0 0 -50 -100 50 -100 0 0)))
23 | (q/fill (q/random 0 255) 100 255)
24 | (doseq [angle (range 0 q/TWO-PI (/ q/TWO-PI petal-count))]
25 | (q/with-rotation [angle]
26 | (q/bezier 0 0 -25 -50 25 -50 0 0)))
27 | (q/fill 200 100 100)
28 | (q/ellipse 0 0 20 20))
29 |
30 |
31 | (defn run [host]
32 | (q/defsketch flowers
33 | :host host
34 | :setup setup
35 | :draw draw
36 | :update update-state
37 | :middleware [md/fun-mode]
38 | :size [300 300]))
39 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/heart_of_clojure.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.heart-of-clojure
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup-particle []
6 | {:location [(/ (q/width) 2) (/ (q/height) 2)]
7 | :speed [0 0]
8 | :lifespan 255})
9 |
10 | (defn setup []
11 | (q/no-stroke)
12 | (q/blend-mode :add)
13 | (q/color-mode :hsb)
14 | ())
15 |
16 | (defn v-add [[x1 y1] [x2 y2]]
17 | [(+ x1 x2) (+ y1 y2)])
18 |
19 | (defn update-particle [{:keys [speed location] :as particle}]
20 | (let [acc [(q/random -0.8 0.8) (q/random -0.8 0.8)]
21 | new-speed (v-add acc speed)
22 | new-location (v-add location new-speed)]
23 | (-> particle
24 | (assoc :location new-location)
25 | (assoc :speed new-speed)
26 | (update :lifespan dec))))
27 |
28 | (defn update-state [state]
29 | (filter #(> (:lifespan %) 0)
30 | (map update-particle
31 | (conj state (comp (setup-particle))))))
32 |
33 | (defn draw-particle [{[x y] :location :keys [lifespan]}]
34 | (q/fill (q/map-range lifespan 127 20 127 50)
35 | 255 100 lifespan)
36 | (q/ellipse
37 | x y
38 | (q/map-range lifespan 0 255 0 (q/map-range (q/sin (/ lifespan 3)) 0 1 0 150))
39 | (q/map-range lifespan 0 255 0 (q/map-range (q/sin lifespan) 0 1 0 150))))
40 |
41 | (defn draw [state]
42 | (q/clear)
43 | (q/background 200 127 0)
44 | (doseq [particle state]
45 | (draw-particle particle)))
46 |
47 | (defn run [host]
48 | (q/defsketch heart-of-clojure
49 | :host host
50 | :setup setup
51 | :draw draw
52 | :update update-state
53 | :middleware [md/fun-mode]
54 | :size [300 300]))
55 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/inferno.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.inferno
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn setup []
8 | (q/blend-mode :add)
9 | (q/no-stroke)
10 | {:particles ()})
11 |
12 | (defn update-particle [particle]
13 | (let [gravity [(* (q/random-gaussian) 0.01) (* (- (q/random-gaussian) 0.8) 0.02)]
14 | wind [(q/random -0.1 0.1) 0]]
15 | (-> particle
16 | (m/update-mover (v/add gravity wind))
17 | (update :lifespan dec))))
18 |
19 | (defn create-particle []
20 | {:acceleration [0 0]
21 | :velocity [0 0]
22 | :location [(/ (q/width) 2) (q/height)]
23 | :lifespan 255})
24 |
25 | (defn update-state [{:keys [particles]}]
26 | {:particles
27 | (->> (conj particles (create-particle))
28 | (filter (fn [{:keys [lifespan]}] (>= lifespan 0)))
29 | (map update-particle))})
30 |
31 | (defn draw-particle [{[x y] :location :keys [lifespan]}]
32 | (let [blue (q/color 255 127 64 lifespan)
33 | red (q/color 0 0)]
34 | (dotimes [i 6]
35 | (q/fill (q/lerp-color red blue (/ i 5)))
36 | (q/ellipse x y
37 | (/ (* 255 (/ 64 (inc i))) lifespan)
38 | (/ (* 255 (/ 64 (inc i))) lifespan)))))
39 |
40 | (defn draw [{:keys [particles]}]
41 | (q/clear)
42 | (doall (map draw-particle particles)))
43 |
44 | (defn run [host]
45 | (q/defsketch inferno
46 | :host host
47 | :setup setup
48 | :draw draw
49 | :update update-state
50 | :middleware [md/fun-mode]
51 | :size [300 300]))
52 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/noise_colors.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.noise-colors
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [nice-color-palettes]))
5 |
6 | (def palettes (js->clj nice-color-palettes))
7 |
8 | (defn pick-random [list]
9 | (nth list (rand-int (- (count list) 1))))
10 |
11 | (defn pick-random-palette []
12 | (map
13 | #(map (fn [s] (q/unhex (apply str s)))
14 | (partition 2 (rest %)))
15 | (pick-random palettes)))
16 |
17 | (defn setup []
18 | (q/no-stroke)
19 | (q/color-mode :hsl)
20 | (let [w 10
21 | seed (q/random 300)
22 | palette (pick-random-palette)]
23 | (doall
24 | (for [[row x] (map-indexed #(vector %1 (* %2 10)) (range (/ (q/width) w)))
25 | [cell y] (map-indexed #(vector %1 (* %2 10)) (range (/ (q/height) w)))
26 | :let [nx (+ seed (/ row w))
27 | ny (+ seed (/ cell w))]]
28 | (let [color (nth palette (q/round (q/map-range (q/noise nx ny) 0 1 0 (dec (count palette)))))
29 | pos-noise (q/map-range (q/noise nx ny) 0 1 -20 30)]
30 | (apply q/fill (concat color [127]))
31 | (q/rect (+ pos-noise x)
32 | (+ pos-noise y)
33 | (q/map-range (q/noise nx ny) 0 1 10 20)
34 | (q/map-range (q/noise nx ny) 0 1 10 20)))))))
35 |
36 | (defn update-state [])
37 |
38 | (defn draw [])
39 |
40 | (defn run [host]
41 | (q/defsketch no453
42 | :host host
43 | :setup setup
44 | :draw draw
45 | :update update-state
46 | :middleware [md/fun-mode]
47 | :size [300 300]))
48 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/particle_party.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.particle-party
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [nice-color-palettes]
5 | [sketches.vector :as v]
6 | [sketches.mover :as m]))
7 |
8 | (def palettes (js->clj nice-color-palettes))
9 |
10 | (defn pick-random [list]
11 | (nth list (rand-int (- (count list) 1))))
12 |
13 | (defn pick-random-palette []
14 | (map
15 | #(map (fn [s] (q/unhex (apply str s)))
16 | (partition 2 (rest %)))
17 | (pick-random palettes)))
18 |
19 |
20 | (defn create-particle [color]
21 | {:acceleration [0 0]
22 | :velocity [0 0]
23 | :location [(/ (q/width) 2) (q/height)]
24 | :lifespan 255
25 | :color color})
26 |
27 | (defn setup []
28 | (q/no-stroke)
29 | {:particles ()
30 | :colors (pick-random-palette)})
31 |
32 | (defn update-particle [particle]
33 | (let [levity [0 -0.05]
34 | wind [(q/random -0.4 0.4) 0]]
35 | (-> particle
36 | (m/update-mover (v/add levity wind))
37 | (update :lifespan dec ))))
38 |
39 | (defn update-state [{:keys [particles colors] :as state}]
40 | (assoc state :particles (if (= (mod (q/frame-count) 500) 0)
41 | ()
42 | (->> (conj particles (create-particle (rand-nth colors)))
43 | (filter (fn [{:keys [lifespan]}] (>= lifespan 0)))
44 | (map update-particle)))))
45 |
46 | (defn draw-particle [{[x y] :location :keys [lifespan color]}]
47 | (apply q/fill (conj color lifespan))
48 | (q/ellipse x y
49 | (q/map-range lifespan 0 255 0 32)
50 | (q/map-range lifespan 0 255 0 32)))
51 |
52 | (defn draw [{:keys [particles colors]}]
53 | (when (= (mod (q/frame-count) 500) 0)
54 | (q/clear))
55 | (doseq [particle particles]
56 | (draw-particle particle)))
57 |
58 | (defn run [host]
59 | (q/defsketch reverse-roots
60 | :host host
61 | :setup setup
62 | :draw draw
63 | :update update-state
64 | :middleware [md/fun-mode]
65 | :size [300 300]))
66 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/rainbow_circles.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.rainbow-circles
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | (q/text-align :center)
7 | (q/color-mode :hsb)
8 | (q/no-stroke)
9 | 0)
10 |
11 | (defn update-state [state]
12 | (mod (+ 0.02 state) q/PI))
13 |
14 | (defn draw [state]
15 | (q/background 0 0 255)
16 | (q/fill 0)
17 | (let [step (/ (q/width) 25)]
18 | (doseq [x (range 0 (+ (q/width) step) step)
19 | y (range 0 (+ (q/height) step) step)]
20 | (let [even-x (= (mod (/ x step) 2) 0)
21 | even-y (= (mod (/ y step) 2) 0)
22 | pulse (* step (cond
23 | (and even-x even-y) (q/sin state)
24 | (and (not even-x) even-y) (q/cos state)
25 | (and even-x (not even-y)) (q/cos state)
26 | (and (not even-x) (not even-y)) (q/sin state)))]
27 | (q/fill (q/map-range x 0 (+ (q/width) step) 0 255) 255 200)
28 | (q/ellipse x y
29 | (* 2 pulse (q/sin state))
30 | (* 2 pulse (q/sin state)))))))
31 |
32 | (defn run [host]
33 | (q/defsketch rainbow-circles
34 | :host host
35 | :setup setup
36 | :draw draw
37 | :update update-state
38 | :middleware [md/fun-mode]
39 | :size [300 300]))
40 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/reverse_roots.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.reverse-roots
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]
4 | [sketches.vector :as v]
5 | [sketches.mover :as m]))
6 |
7 | (defn create-particle []
8 | {:acceleration [0 0]
9 | :velocity [0 0]
10 | :location [(/ (q/width) 2) (q/height)]
11 | :lifespan 255})
12 |
13 | (defn setup []
14 | {:particles ()})
15 |
16 | (defn update-particle [particle]
17 | (let [levity [0 -0.01]
18 | wind [(q/random -0.1 0.1) 0]]
19 | (-> particle
20 | (m/update-mover (v/add levity wind))
21 | (update :lifespan dec))))
22 |
23 | (defn update-state [{:keys [particles]}]
24 | (if (= (mod (q/frame-count) 500) 0)
25 | {:particles ()}
26 | {:particles
27 | (->> (conj particles (create-particle))
28 | (filter (fn [{:keys [lifespan]}] (>= lifespan 0)))
29 | (map update-particle))}))
30 |
31 | (defn draw-particle [{[x y] :location :keys [lifespan]}]
32 | (q/fill 255 lifespan)
33 | (q/ellipse x y
34 | (q/map-range lifespan 0 255 0 32)
35 | (q/map-range lifespan 0 255 0 32)))
36 |
37 | (defn draw [{:keys [particles]}]
38 | (when (= (mod (q/frame-count) 500) 0)
39 | (q/clear))
40 | (doall (map draw-particle particles)))
41 |
42 | (defn run [host]
43 | (q/defsketch reverse-roots
44 | :host host
45 | :setup setup
46 | :draw draw
47 | :update update-state
48 | :middleware [md/fun-mode]
49 | :size [300 300]))
50 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/rotating_angles.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.rotating-angles
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (defn setup []
6 | {:angle-lights-0 0
7 | :angle (q/random 0 q/TWO-PI)})
8 | (defn update-state [state]
9 | (-> state
10 | (update :angle-lights-0 (fn [angle] (mod (+ angle 0.04) 100000)))))
11 |
12 | (defn draw-beams [[x0 y0] r angles angle]
13 | (q/with-translation [x0 y0]
14 | (q/with-rotation [angle]
15 | (doseq [angle angles]
16 | (let [x1 (* r (Math/cos angle))
17 | y1 (* r (Math/sin angle))]
18 | (q/line 0 0 x1 y1))))))
19 |
20 | (defn x [proportion]
21 | (* (q/width) (/ proportion 100)))
22 |
23 | (defn y [proportion]
24 | (* (q/height) (/ proportion 100)))
25 |
26 | (defn oscillate-value [value from to]
27 | (q/map-range (q/sin value) -1 1 from to))
28 |
29 |
30 | (defn draw [{:keys [angle-lights-0 angle]}]
31 | (q/clear)
32 | (doseq [x0 (range 0 (q/width) 20)
33 | y0 (range 0 (q/width) 20)]
34 | (draw-beams [(x x0) (y y0)]
35 | (/ (q/width) 5)
36 | (range 0 angle q/QUARTER-PI)
37 | (oscillate-value (q/sin angle-lights-0) 0 q/QUARTER-PI))))
38 |
39 | (defn run [host]
40 | (q/defsketch lights
41 | :host host
42 | :setup setup
43 | :draw draw
44 | :update update-state
45 | :middleware [md/fun-mode]
46 | :size [300 300]))
47 |
--------------------------------------------------------------------------------
/src/sketches/rac_sketches/text_snake.cljs:
--------------------------------------------------------------------------------
1 | (ns sketches.rac-sketches.text-snake
2 | (:require [quil.core :as q :include-macros true]
3 | [quil.middleware :as md]))
4 |
5 | (def x-offset 15)
6 | (def step 15)
7 | (def path-count 11)
8 | (def height 300)
9 | (def speed 3)
10 |
11 | (defn setup []
12 | (q/text-align :center)
13 | (q/text-size 30)
14 | (->> "HELLO!"
15 | (repeat 19)
16 | (apply str)
17 | (map-indexed
18 | (fn [i letter]
19 | {:i 0
20 | :start (* i 10)
21 | :letter (str letter)}))))
22 |
23 | (defmulti length first)
24 | (defmethod length :arc [[_ _ _ _ height start stop]]
25 | (Math/abs (* (/ height 2) (- stop start))))
26 | (defmethod length :line [[_ _ y1 _ y2]]
27 | (Math/abs (- y2 y1)))
28 |
29 | (defmulti position first)
30 | (defmethod position :arc [[_ x y _ height start stop up] t]
31 | (let [r (/ height 2)
32 | angle (- start stop)
33 | phi (* angle (if up t (- 1 t)))]
34 | [((if (>= start q/PI) + -) x (* r (Math/cos phi)))
35 | ((if (>= start q/PI) + -) y (* r (Math/sin phi)))]))
36 | (defmethod position :line [[_ x1 y1 _ y2 up] t]
37 | [x1 (+ y1 (* (- y2 y1) (if up (- 1 t) t)))])
38 |
39 | (def curved-path
40 | (->> path-count
41 | range
42 | (mapcat (fn [i]
43 | (let [x (+ x-offset (* i 2 step))]
44 | [[:arc (- x step)
45 | (if (even? i) (- 300 step) step)
46 | (* 2 step)
47 | (* 2 step)
48 | (if (even? i) 0 q/PI)
49 | (if (even? i) q/PI q/TWO-PI)
50 | (even? i)]
51 | [:line x step x (- height step) (even? i)]])))))
52 |
53 | (def curve-length (reduce + (map length curved-path)))
54 |
55 | (defn path-pos [t]
56 | (->> curved-path
57 | (reduce (fn [total-length el]
58 | (let [el-length (length el)]
59 | (if (>= (Math/ceil (+ total-length el-length speed)) t)
60 | (reduced (position el (/ (- t total-length) el-length)))
61 | (+ total-length (length el))))) 0)))
62 |
63 | (defn draw [letters]
64 | (q/clear)
65 | (doseq [{:keys [i letter]} letters]
66 | (let [[x y] (path-pos i)
67 | [nx ny] (path-pos (+ i speed))]
68 | (q/push-matrix)
69 | (q/translate x y)
70 |
71 | (q/rotate (+ (Math/atan2 (- ny y) (- nx x)) (- q/HALF-PI)))
72 | (q/fill 0)
73 | (q/rotate q/PI)
74 | (q/text letter 0 0)
75 | (q/pop-matrix))))
76 |
77 | (defn update-letter [{:keys [start] :as letter}]
78 | (update letter :i (fn [i] (if (and (< i curve-length) (< start (q/frame-count)))
79 | (+ i speed)
80 | 0))))
81 |
82 | (defn update-state [letters]
83 | (map update-letter letters))
84 |
85 | (defn run [host]
86 | (q/defsketch text-snake
87 | :host host
88 | :setup setup
89 | :draw draw
90 | :update update-state
91 | :middleware [md/fun-mode]
92 | :size [300 300]))
93 |
94 | (comment
95 | (defn stop-sketch [id]
96 | (q/with-sketch (q/get-sketch-by-id id)
97 | (q/no-loop)))
98 | (do (stop-sketch "Text Snake")
99 | (run "Text Snake")))
100 |
--------------------------------------------------------------------------------
/src/sketches/vector.cljc:
--------------------------------------------------------------------------------
1 | (ns sketches.vector)
2 |
3 | (defn add
4 | ([v] v)
5 | ([[x1 y1] [x2 y2]]
6 | [(+ x1 x2) (+ y1 y2)])
7 | ([v1 v2 & vs]
8 | (apply add (add v1 v2) vs)))
9 |
10 | (defn sub [v1 v2]
11 | (vector (- (first v1) (first v2))
12 | (- (second v1) (second v2))))
13 |
14 | (defn mult [v1 n] (vector (* (first v1) n) (* (second v1) n)))
15 |
16 | (defn div [[x y] n] (if (or (= n 0) (= n 0.0))
17 | (vector x y)
18 | (vector (/ x n) (/ y n))))
19 |
20 | (defn mag [[x y]] (Math/sqrt (+ (* x x) (* y y))))
21 |
22 | (defn normalize [v]
23 | (let [m (mag v)]
24 | (if (not (= m 0.0)) (div v m) v)))
25 |
26 | (defn limit [[x y] top]
27 | (if (> (mag [x y]) top)
28 | (mult (normalize [x y]) top)
29 | [x y]))
30 |
31 | (defn rotate [[x y] angle]
32 | [(- (* (Math/cos angle) x) (* (Math/sin angle) y))
33 | (+ (* (Math/sin angle) x) (* (Math/cos angle) y))])
34 |
35 | (defn from-angle
36 | ([angle]
37 | (from-angle angle 1))
38 | ([angle length]
39 | [(* length (Math/cos angle)) (* length (Math/sin angle))]))
40 |
41 |
42 |
--------------------------------------------------------------------------------