├── .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 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/images/01.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/02.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/03.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/04.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/05.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/images/06.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/07.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /public/images/08.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/09.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/10.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /public/images/11.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /public/images/12.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/13.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /public/images/14.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /public/images/15.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /public/images/comma.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/dynamic-brush.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/emacs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/emacs.png -------------------------------------------------------------------------------- /public/images/exclamationmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/fcb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollacaster/sketches/c4c8ee52e536a7511da27f81fda04aa35b5d1a90/public/images/fcb.jpg -------------------------------------------------------------------------------- /public/images/period.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/questionmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/return.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 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 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/space2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 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 | --------------------------------------------------------------------------------