├── js
├── examples
│ ├── dev
│ │ └── reflection.js
│ ├── p5setup.js
│ ├── random
│ │ ├── random_noise2.js
│ │ ├── random.js
│ │ ├── random_squared.js
│ │ ├── random_noise.js
│ │ ├── random_average.js
│ │ ├── random_norm.js
│ │ ├── random_power.js
│ │ ├── random_average2.js
│ │ └── random_walk.js
│ ├── physics
│ │ ├── position.js
│ │ ├── velocity.js
│ │ ├── acceleration.js
│ │ ├── gravity.js
│ │ ├── orbit.js
│ │ └── spring.js
│ ├── math
│ │ ├── distance.js
│ │ ├── rotate2d.js
│ │ ├── manhattan_distance.js
│ │ ├── dot_product.js
│ │ ├── raycasting.js
│ │ ├── sine_cosine.js
│ │ ├── cross_product.js
│ │ └── perspective.js
│ ├── wave
│ │ ├── wave_equation.js
│ │ ├── sine_wave.js
│ │ ├── square_wave.js
│ │ ├── triangle_wave.js
│ │ ├── saw_wave.js
│ │ └── simple_harmonic.js
│ ├── machines
│ │ ├── crank.js
│ │ ├── piston.js
│ │ └── crank2.js
│ ├── drawings
│ │ ├── line.js
│ │ ├── circle.js
│ │ ├── line_segments.js
│ │ ├── centroid.js
│ │ ├── spinner.js
│ │ ├── incenter.js
│ │ ├── orthocenter.js
│ │ ├── reuleaux.js
│ │ ├── bezier.js
│ │ ├── circumcenter.js
│ │ ├── excenter.js
│ │ └── bspline.js
│ ├── easing
│ │ ├── colliding.js
│ │ ├── composite01.js
│ │ ├── composite02.js
│ │ ├── tweens.js
│ │ ├── bouncing.js
│ │ ├── tweens2.js
│ │ └── sequence.js
│ ├── collision
│ │ ├── collision_line_circle.js
│ │ ├── collision_circles.js
│ │ ├── collision_rectangles.js
│ │ └── collision_triangles.js
│ ├── verlet
│ │ ├── verlet_points.js
│ │ ├── verlet_sticks.js
│ │ ├── pendulum.js
│ │ ├── ragdoll.js
│ │ └── ragdoll3d.js
│ ├── distance
│ │ ├── circle.js
│ │ ├── rectangle.js
│ │ └── rotated_rectangle.js
│ ├── light_path
│ │ ├── reflection.js
│ │ ├── parabola.js
│ │ ├── refraction.js
│ │ └── mirrors.js
│ └── sound
│ │ ├── equal_temperament.js
│ │ └── just_intonation.js
├── .DS_Store
└── main.js
├── .DS_Store
├── extra
├── .DS_Store
└── wave_function
│ ├── .DS_Store
│ ├── screenshot.png
│ ├── shaders
│ ├── flat.vert
│ ├── render.frag
│ └── update.frag
│ ├── index.html
│ ├── package.json
│ └── index.js
├── css
├── example.css
└── style.css
├── README.md
├── vector2d.html
├── dev.html
├── .gitignore
├── machines.html
├── index.html
├── easing.html
├── physics.html
├── light_path.html
├── distance.html
├── verlet.html
├── pitch.html
├── random.html
├── collision.html
├── wave.html
├── handy_math.html
└── drawings.html
/js/examples/dev/reflection.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kynd/p5sketches/HEAD/.DS_Store
--------------------------------------------------------------------------------
/js/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kynd/p5sketches/HEAD/js/.DS_Store
--------------------------------------------------------------------------------
/extra/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kynd/p5sketches/HEAD/extra/.DS_Store
--------------------------------------------------------------------------------
/css/example.css:
--------------------------------------------------------------------------------
1 | body { margin:0; padding: 0; background: #e4e4e4; overflow: none;}
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # p5sketches
2 |
3 | sketches in p5.js
4 |
5 | https://kynd.github.io/p5sketches/index.html
6 |
--------------------------------------------------------------------------------
/extra/wave_function/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kynd/p5sketches/HEAD/extra/wave_function/.DS_Store
--------------------------------------------------------------------------------
/extra/wave_function/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kynd/p5sketches/HEAD/extra/wave_function/screenshot.png
--------------------------------------------------------------------------------
/extra/wave_function/shaders/flat.vert:
--------------------------------------------------------------------------------
1 | attribute vec2 position;
2 | varying vec2 uv;
3 |
4 | void main() {
5 | gl_Position = vec4(position,0.0,1.0);
6 | uv = 0.5 * (position+1.0);
7 | }
8 |
--------------------------------------------------------------------------------
/vector2d.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 2D Vector
8 |
9 |
10 |
11 | Redirect
12 |
13 |
14 |
--------------------------------------------------------------------------------
/extra/wave_function/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Wave
7 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/extra/wave_function/shaders/render.frag:
--------------------------------------------------------------------------------
1 | precision mediump float;
2 | uniform sampler2D buffer;
3 | uniform int channelIndex;
4 | uniform vec2 dims;
5 | varying vec2 uv;
6 |
7 | void main() {
8 | vec4 samp0 = texture2D(buffer, uv + vec2(0.0, -1.0) / dims);
9 | vec4 samp1 = texture2D(buffer, uv + vec2(0.0, 1.0) / dims);
10 |
11 | vec4 color = vec4(0.88, 0.94, 0.95, 1.0);
12 | if (abs(uv.x - 0.5) < 0.3 && abs(uv.y - 0.5) < 0.02) {
13 | color = vec4(0.0, 0.0, 0.0, 1.0);
14 | }
15 | color.rgb -= smoothstep(0.026, 0.025, length(uv - vec2(0.5, 0.7)));
16 |
17 | float v = smoothstep(0.0, 0.1, samp0.r - samp1.r);
18 | color = vec4(color.rgb * (1.0 - v), 1.0);
19 | gl_FragColor = color;
20 | }
21 |
--------------------------------------------------------------------------------
/extra/wave_function/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wave_function",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "browserify": {
7 | "transform": [
8 | "glslify"
9 | ]
10 | },
11 | "scripts": {
12 | "start": "budo -H 127.0.0.1 -p 9000 --title wave index.js:bundle.js --open --live",
13 | "bundle": "browserify index.js -o bundle.js"
14 | },
15 | "devDependencies": {
16 | "browserify": "*",
17 | "budo": "*"
18 | },
19 | "author": "",
20 | "license": "ISC",
21 | "dependencies": {
22 | "a-big-triangle": "^1.0.3",
23 | "gl-clear": "^2.0.0",
24 | "gl-fbo": "^2.0.5",
25 | "gl-now": "^1.4.0",
26 | "gl-shader": "^4.2.1",
27 | "glslify": "^6.1.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/js/examples/p5setup.js:
--------------------------------------------------------------------------------
1 | let __ready = false;
2 | let __clicked = false;
3 |
4 |
5 | function windowResized() {
6 | resizeCanvas(windowWidth, windowHeight);
7 | }
8 |
9 | function start() {
10 | if (__ready) {
11 | loop();
12 | }
13 | }
14 |
15 | function stop() {
16 | if (__ready && !__clicked) {
17 | noLoop();
18 | if (stopAudio) {
19 | stopAudio();
20 | }
21 | }
22 | __clicked = false;
23 | }
24 |
25 | let __setup = setup;
26 |
27 | setup = function() {
28 | __setup();
29 |
30 | if (!__autorun) { noLoop(); }
31 | canvas.mouseClicked(function() {__clicked = true; __parent.focusExample(window)});
32 | canvas.touchStarted(function() {__clicked = true; __parent.focusExample(window)});
33 | __ready = true;
34 | }
35 |
--------------------------------------------------------------------------------
/js/examples/random/random_noise2.js:
--------------------------------------------------------------------------------
1 | let record = [], x = 0;
2 | let resolution = 150;
3 |
4 | function setup() {
5 | for (let i = 0; i < resolution * 10; i ++) {
6 | nextRandom();
7 | }
8 | canvas = createCanvas(windowWidth, windowHeight);
9 | }
10 |
11 | function draw() {
12 | clear();
13 | background(254, 253, 183);
14 |
15 | nextRandom();
16 |
17 | fill(0);stroke(0);
18 | for (let i = 0; i < record.length; i ++) {
19 | let w = width / resolution;
20 | let h = height * record[i];
21 | let x = w * i;
22 | let y = height - h;
23 | rect(x, y, w, h);
24 | }
25 | }
26 |
27 | function nextRandom() {
28 | let v = noise(x); x += 0.01;
29 | record.push(v);
30 | if (record.length > resolution) {
31 | record.shift();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/js/examples/physics/position.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | position = createVector(100, -100);
4 | }
5 |
6 | function draw() {
7 | clear();
8 | const hw = width / 2, hh = height / 2;
9 |
10 | background(117, 147, 208);
11 | push();
12 | translate(hw, hh);
13 |
14 | fill(0); stroke(0);
15 | strokeWeight(2);
16 | drawArrow(0, 0, position.x, position.y);
17 | drawLabel(position.x, position.y, `position (${position.x.toPrecision(4)}, ${position.y.toPrecision(4)})`, LEFT);
18 |
19 | strokeWeight(1)
20 | line(-hw, 0, hw, 0);
21 | line(0, -hh, 0, hh);
22 | drawLabel(0, -4, "Origin", LEFT);
23 |
24 | pop();
25 |
26 | position = createVector(mouseX - hw, mouseY - hh);
27 | }
28 |
29 | /** drawArrow **/
30 |
31 | /** drawLabel **/
32 |
--------------------------------------------------------------------------------
/dev.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dev
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/extra/wave_function/shaders/update.frag:
--------------------------------------------------------------------------------
1 |
2 | precision mediump float;
3 | uniform float frameCount;
4 | uniform sampler2D buffer;
5 | uniform vec2 dims;
6 | varying vec2 uv;
7 |
8 | void main() {
9 |
10 | vec4 color;
11 | if (length(uv - vec2(0.5, 0.7)) < 0.025) {
12 | // Source
13 | color = vec4(0.5 + sin(frameCount * 0.5) * 0.2 * (sin(frameCount * 0.05) + 1.0), 0.5, 0.5, 1.0);
14 | } else if (abs(uv.x - 0.5) < 0.3 && abs(uv.y - 0.5) < 0.02) {
15 | // Obstacle
16 | color = vec4(0.5, 0.5, 0.5, 1.0);
17 | } else {
18 | vec4 samp = texture2D(buffer, uv);
19 | float va = samp.r;
20 |
21 | vec2 d[4];
22 | d[0] = vec2(-1.0, -0.0);
23 | d[1] = vec2(0.0, -1.0);
24 | d[2] = vec2(1.0, 0.0);
25 | d[3] = vec2(-0.0, 1.0);
26 |
27 | float vb = 0.0;
28 | for (int i = 0; i < 4; i ++) {
29 | vb += texture2D(buffer, uv + d[i] / dims * 2.0).r;
30 | }
31 |
32 | float vc = samp.g;
33 | samp.b = va * 2.0 + 0.2 * (vb - va * 4.0) - vc;
34 | color = clamp(vec4(0.0), vec4(1.0), samp.brga);
35 | }
36 |
37 | gl_FragColor = color;
38 | }
39 |
--------------------------------------------------------------------------------
/js/examples/math/distance.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 |
4 | counter = 0;
5 | p = createVector(0, 0);
6 | q = createVector(0, 0);
7 | }
8 |
9 | function draw() {
10 | clear();
11 | const cx = width / 2, cy = height / 2;
12 | const t = frameCount - 1;
13 | const a0 = radians(t), a1 = radians(t * 2), a2 = radians(t * 3), a3 = radians(t * 4);
14 | p.x = cos(a0) * 150;
15 | p.y = sin(a3) * 100;
16 | q.x = -cos(a1) * 150;
17 | q.y = -sin(a2) * 100;
18 |
19 | // see also p5.Vector.dist()
20 | // https://p5js.org/reference/#/p5.Vector/dist
21 | const distance = sqrt((p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y));
22 |
23 | background(245, 177, 217);
24 |
25 | push();
26 | translate(cx, cy);
27 | fill(0); stroke(0);
28 | drawLineWithLabel(p.x, p.y, q.x, q.y, "distance:" + distance.toPrecision(4), CENTER);
29 | drawSquareMarker(p, 10);
30 | drawTriangleMarker(q, 12);
31 | pop();
32 |
33 | counter ++;
34 | }
35 |
36 | /** drawSquareMarker **/
37 |
38 | /** drawTriangleMarker **/
39 |
40 | /** drawLineWithLabel **/
41 |
42 | /** drawLabel **/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
--------------------------------------------------------------------------------
/js/examples/random/random.js:
--------------------------------------------------------------------------------
1 | let record, max;
2 | let resolution = 150;
3 |
4 | function setup() {
5 | initRecord();
6 | for (let i = 0; i < resolution * 10; i ++) {
7 | nextRandom();
8 | }
9 | canvas = createCanvas(windowWidth, windowHeight);
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(254, 253, 183);
15 |
16 | let v;
17 | for (let i = 0; i < resolution; i ++) {
18 | v = nextRandom();
19 | line(v * width, 0, v * width, height);
20 | }
21 |
22 | fill(0);stroke(0);
23 | for (let i = 0; i < resolution; i ++) {
24 | let w = width / resolution;
25 | let h = height / max * record[i];
26 | let x = w * i;
27 | let y = height - h;
28 | rect(x, y, w, h);
29 | }
30 |
31 | if (frameCount % 600 == 0) {
32 | initRecord();
33 | }
34 | }
35 |
36 | function initRecord() {
37 | max = 1;
38 | if (!record) {
39 | record = [];
40 | } else {
41 | record.length = 0;
42 | }
43 |
44 | for (let i = 0; i < resolution; i ++) {
45 | record.push(0);
46 | }
47 | }
48 |
49 | function nextRandom() {
50 | let v = random(1);
51 | if (++record[floor(v * resolution)] > max) {max ++};
52 | return v;
53 | }
54 |
--------------------------------------------------------------------------------
/js/examples/random/random_squared.js:
--------------------------------------------------------------------------------
1 | let record, max;
2 | let resolution = 150;
3 |
4 | function setup() {
5 | initRecord();
6 | for (let i = 0; i < resolution * 10; i ++) {
7 | nextRandom();
8 | }
9 | canvas = createCanvas(windowWidth, windowHeight);
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(254, 253, 183);
15 |
16 | let v;
17 | for (let i = 0; i < resolution; i ++) {
18 | v = nextRandom();
19 | line(v * width, 0, v * width, height);
20 | }
21 |
22 | fill(0);stroke(0);
23 | for (let i = 0; i < resolution; i ++) {
24 | let w = width / resolution;
25 | let h = height / max * record[i];
26 | let x = w * i;
27 | let y = height - h;
28 | rect(x, y, w, h);
29 | }
30 |
31 | if (frameCount % 600 == 0) {
32 | initRecord();
33 | }
34 | }
35 |
36 | function initRecord() {
37 | max = 1;
38 | if (!record) {
39 | record = [];
40 | } else {
41 | record.length = 0;
42 | }
43 |
44 | for (let i = 0; i < resolution; i ++) {
45 | record.push(0);
46 | }
47 | }
48 |
49 | function nextRandom() {
50 | let v = pow(random(1), 2);
51 | if (++record[floor(v * resolution)] > max) {max ++};
52 | return v;
53 | }
54 |
--------------------------------------------------------------------------------
/js/examples/random/random_noise.js:
--------------------------------------------------------------------------------
1 | let record, max, x = 0;
2 | let resolution = 150;
3 |
4 | function setup() {
5 | initRecord();
6 | for (let i = 0; i < resolution * 10; i ++) {
7 | nextRandom();
8 | }
9 | canvas = createCanvas(windowWidth, windowHeight);
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(254, 253, 183);
15 |
16 | let v;
17 | for (let i = 0; i < resolution; i ++) {
18 | v = nextRandom();
19 | line(v * width, 0, v * width, height);
20 | }
21 |
22 | fill(0);stroke(0);
23 | for (let i = 0; i < resolution; i ++) {
24 | let w = width / resolution;
25 | let h = height / max * record[i];
26 | let x = w * i;
27 | let y = height - h;
28 | rect(x, y, w, h);
29 | }
30 |
31 | if (frameCount % 600 == 0) {
32 | initRecord();
33 | }
34 | }
35 |
36 | function initRecord() {
37 | max = 1;
38 | if (!record) {
39 | record = [];
40 | } else {
41 | record.length = 0;
42 | }
43 |
44 | for (let i = 0; i < resolution; i ++) {
45 | record.push(0);
46 | }
47 | }
48 |
49 | function nextRandom() {
50 | let v = noise(x); x += 0.001;
51 | if (++record[floor(v * resolution)] > max) {max ++};
52 | return v;
53 | }
54 |
--------------------------------------------------------------------------------
/js/examples/random/random_average.js:
--------------------------------------------------------------------------------
1 | let record, max;
2 | let resolution = 150;
3 |
4 | function setup() {
5 | for (let i = 0; i < resolution * 10; i ++) {
6 | initRecord();
7 | nextRandom();
8 | }
9 | canvas = createCanvas(windowWidth, windowHeight);
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(254, 253, 183);
15 |
16 | let v;
17 | for (let i = 0; i < resolution; i ++) {
18 | v = nextRandom();
19 | line(v * width, 0, v * width, height);
20 | }
21 |
22 | fill(0);stroke(0);
23 | for (let i = 0; i < resolution; i ++) {
24 | let w = width / resolution;
25 | let h = height / max * record[i];
26 | let x = w * i;
27 | let y = height - h;
28 | rect(x, y, w, h);
29 | }
30 |
31 | if (frameCount % 600 == 0) {
32 | initRecord();
33 | }
34 | }
35 |
36 | function initRecord() {
37 | max = 1;
38 | if (!record) {
39 | record = [];
40 | } else {
41 | record.length = 0;
42 | }
43 |
44 | for (let i = 0; i < resolution; i ++) {
45 | record.push(0);
46 | }
47 | }
48 |
49 | function nextRandom() {
50 | let v = (random(1) + random(1)) / 2;
51 | if (++record[floor(v * resolution)] > max) {max ++};
52 | return v;
53 | }
54 |
--------------------------------------------------------------------------------
/js/examples/wave/wave_equation.js:
--------------------------------------------------------------------------------
1 | let u = [];
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | initValues();
6 | }
7 |
8 | function draw() {
9 | clear();
10 | background(224, 239, 243);
11 |
12 | let f = frameCount;
13 | let iN = (f + 1) % 3; // Next (t + 1)
14 | let iC = f % 3; // Current (t)
15 | let iP = (f + 2) % 3; // Previous (t - 1)
16 | let span = width / (u[0].length - 1);
17 |
18 | u[iC][0] += signedNoise(frameCount * 0.1) * 0.5;
19 |
20 | updateSimulation(iN, iC, iP)
21 |
22 | noFill(); stroke(1); strokeWeight(3);
23 | beginShape();
24 | for (let i = 0; i < u[0].length; i ++) {
25 | vertex(span * i, height / 2 + u[iN][i]);
26 | }
27 | endShape();
28 | }
29 |
30 | function updateSimulation(iN, iC, iP) {
31 | for (let i = 0; i < u[0].length; i ++) {
32 | let dhdx = 0;
33 | if (i != 0 && i != u[0].length - 1) {
34 | dhdx = u[iC][i - 1] + u[iC][i + 1] - 2 * u[iC][i]
35 | }
36 | let c2 = 0.1;
37 | let dampen = 0.995;
38 | u[iN][i] = 2 * u[iC][i] + c2 * dhdx - u[iP][i];
39 | u[iN][i] *= dampen;
40 | }
41 | }
42 |
43 | function initValues() {
44 | u = [];
45 | for (let i = 0; i < 3; i ++) {
46 | u.push(new Array(floor(width / 8) + 1).fill(0));
47 | }
48 | }
49 |
50 | /** signedNoise **/
51 |
--------------------------------------------------------------------------------
/js/examples/wave/sine_wave.js:
--------------------------------------------------------------------------------
1 | let prevInitFrame = 1;
2 | let radius = 100;
3 | let plotData = [];
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 | }
8 |
9 | function draw() {
10 | clear();
11 | background(224, 239, 243);
12 |
13 | let rad = radians(frameCount - 1) * 2;
14 | let sine = sin(rad);
15 | let cosine = cos(rad);
16 | let x = cosine * radius;
17 | let y = -sine * radius;
18 |
19 | push();
20 | translate(radius + 20, height / 2);
21 | fill(255); strokeWeight(1);
22 | ellipse(0, 0, radius * 2, radius * 2);
23 | line(-radius, 0, radius, 0);
24 | line(radius + 20, y, -radius - 20, y);
25 | strokeWeight(3);
26 | line(0,0,x, y);
27 | line(x, 0, x, y);
28 | line(0,0,x, 0);
29 | strokeWeight(1);
30 | drawCircleMarker(createVector(x, y), 4);
31 | pop();
32 |
33 | let graphW = width - (radius + 20) * 2;
34 | let graphX = (radius + 20) * 2;
35 |
36 | if (frameCount > prevInitFrame + graphW) {
37 | plotData = [];
38 | prevInitFrame += graphW;
39 | }
40 | plotData.push({x:frameCount - prevInitFrame, y: -y});
41 |
42 | plotGraph(plotData, graphX, height / 2, graphW, height - 64, 0, graphW, -height / 2 + 32, height / 2 - 32, "time", "y");
43 | }
44 |
45 | /** plotGraph **/
46 |
47 | /** drawLabel **/
48 |
49 | /** drawCircleMarker **/
50 |
--------------------------------------------------------------------------------
/js/examples/math/rotate2d.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 |
4 | degA = degB = degC = 0;
5 | pA = createVector(0, -80);
6 | pB = createVector(100, 0);
7 | pC = createVector(-100, 100);
8 | }
9 |
10 | function draw() {
11 | clear();
12 | let cx = width / 2, cy = height / 2;
13 |
14 | let radA = radians(degA); // PI * deg / 180;
15 | let radB = radians(degB); // PI * deg / 180;
16 | let radC = radians(degC); // PI * deg / 180;
17 | let npA = rotate2d(pA, radA);
18 | let npB = rotate2d(pB, radB);
19 | let npC = rotate2d(pC, radC);
20 |
21 | background(15, 157, 88);
22 |
23 | push();
24 | translate(cx, cy);
25 | fill(0); stroke(0);
26 | line(0, 0, pA.x, pA.y);
27 | line(0, 0, pB.x, pB.y);
28 | line(0, 0, pC.x, pC.y);
29 | drawTriangleMarker(pA, 12);
30 | drawCircleMarker(pB, 12);
31 | drawSquareMarker(pC, 10);
32 |
33 | fill(255); stroke(255);
34 | ellipse(0, 0, 8, 8);
35 | line(0, 0, npA.x, npA.y)
36 | line(0, 0, npB.x, npB.y)
37 | line(0, 0, npC.x, npC.y)
38 | drawTriangleMarker(npA, 12);
39 | drawCircleMarker(npB, 12);
40 | drawSquareMarker(npC, 10);
41 |
42 | pop();
43 |
44 | degA += 1;
45 | degB += 2;
46 | degC += 4;
47 | }
48 |
49 | /** rotate2d **/
50 |
51 | /** drawCircleMarker **/
52 |
53 | /** drawSquareMarker **/
54 |
55 | /** drawTriangleMarker **/
56 |
--------------------------------------------------------------------------------
/js/examples/random/random_norm.js:
--------------------------------------------------------------------------------
1 | let record, max;
2 | let resolution = 150;
3 |
4 | function setup() {
5 | initRecord();
6 | for (let i = 0; i < resolution * 10; i ++) {
7 | nextRandom();
8 | }
9 | canvas = createCanvas(windowWidth, windowHeight);
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(254, 253, 183);
15 |
16 | let v;
17 | for (let i = 0; i < resolution; i ++) {
18 | v = nextRandom();
19 | line(v * width, 0, v * width, height);
20 | }
21 |
22 | fill(0);stroke(0);
23 | for (let i = 0; i < resolution; i ++) {
24 | let w = width / resolution;
25 | let h = height / max * record[i];
26 | let x = w * i;
27 | let y = height - h;
28 | rect(x, y, w, h);
29 | }
30 |
31 | if (frameCount % 600 == 0) {
32 | initRecord();
33 | }
34 | }
35 |
36 | function initRecord() {
37 | max = 1;
38 | if (!record) {
39 | record = [];
40 | } else {
41 | record.length = 0;
42 | }
43 |
44 | for (let i = 0; i < resolution; i ++) {
45 | record.push(0);
46 | }
47 | }
48 |
49 | function nextRandom() {
50 | // Box-Muller Transform
51 | // avoiding log(0) by using (1 - Math.random())
52 | let mean = 0.5, variance = 0.1;
53 | let v = sqrt(-2 * log(1 - random(1))) * cos(2 * PI * random(1)) * variance + mean;
54 | if (++record[floor(v * resolution)] > max) {max ++};
55 | return v;
56 | }
57 |
--------------------------------------------------------------------------------
/js/examples/machines/crank.js:
--------------------------------------------------------------------------------
1 | let log = [];
2 | let center, pivot, radius, armLength;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | center = createVector(width * 0.25, height * 0.5);
7 | pivot = createVector(width * 0.5, height * 0.5);
8 | armLength = width * 0.5;
9 | radius = min(height * 0.2, center.dist(pivot) * 0.5);
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(69, 157, 193);
15 |
16 | let a = radians((frameCount - 1) * 2) + PI * 0.5;
17 | let p = createVector(cos(a) * radius, sin(a) * radius).add(center);
18 | let arm = new LineSegment().fromTwoPointsAndLength(p, pivot, armLength);
19 | if (frameCount % 2 == 0) { log.push(arm.p1) };
20 | if (log.length > 90) { log.shift(); }
21 |
22 | fill(253, 219, 192); stroke(0);
23 | ellipse(center.x, center.y, radius * 2, radius * 2);
24 |
25 | noFill();stroke(0);
26 | line(center.x, center.y, p.x, p.y);
27 |
28 | strokeWeight(3);
29 | beginShape();
30 | for (let i = 0; i < log.length; i ++) {
31 | vertex(log[i].x, log[i].y);
32 | }
33 | endShape();
34 | arm.draw();
35 |
36 | fill(255); strokeWeight(1);
37 | drawCircleMarker(center, 4);
38 | drawCircleMarker(p, 4);
39 | drawCircleMarker(arm.p1, 4);
40 | drawCircleMarker(pivot, 4);
41 | }
42 |
43 | /** LineSegment **/
44 |
45 | /** drawLabel **/
46 |
47 | /** drawCircleMarker **/
48 |
--------------------------------------------------------------------------------
/js/examples/physics/velocity.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 |
4 | counter = 0;
5 | position = createVector(100, -100);
6 | velocity = createVector(48, -48);
7 | fps = 60; // naively assuming 60 fps
8 | }
9 |
10 | function draw() {
11 | clear();
12 | const hw = width / 2, hh = height / 2;
13 | const vx = position.x + velocity.x;
14 | const vy = position.y + velocity.y;
15 |
16 | background(117, 147, 208);
17 | push();
18 | translate(hw, hh);
19 |
20 | fill(0); stroke(0);
21 | strokeWeight(2);
22 | drawArrow(position.x, position.y, vx, vy);
23 | drawCircleMarker(position, 4);
24 |
25 | drawLabel(position.x, position.y, `position (${position.x.toPrecision(4)}, ${position.y.toPrecision(4)})`, LEFT);
26 | drawLabel(vx, vy, `velocity (${velocity.x.toPrecision(4)}, ${velocity.y.toPrecision(4)})`, LEFT);
27 |
28 | strokeWeight(1)
29 | line(-hw, 0, hw, 0);
30 | line(0, -hh, 0, hh);
31 | drawLabel(0, -4, "Origin", LEFT);
32 |
33 | pop();
34 |
35 | const pDelta = velocity.copy().div(fps);
36 | position.add(pDelta);
37 | if (position.x > hw || position.x < -hw) {velocity.x = -velocity.x;}
38 | if (position.y > hh || position.y < -hh) {velocity.y = -velocity.y;}
39 | }
40 |
41 |
42 | /** drawCircleMarker **/
43 |
44 | /** drawArrow **/
45 |
46 | /** drawLabel **/
47 |
--------------------------------------------------------------------------------
/js/examples/drawings/line.js:
--------------------------------------------------------------------------------
1 | let lines = [];
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 |
6 | lines.push(new Line(0, 1, 0)); // X-axis: a = 0, b != 0, c = 0
7 | lines.push(new Line(1, 0, 0)); // Y-axis: a != 0, b = 0, c = 0
8 | lines.push(new Line());
9 | lines.push(new Line());
10 | lines.push(new Line());
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(255, 235, 59);
16 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
17 |
18 | for (let i = 2; i < lines.length; i ++) {
19 | let f = frameCount;
20 | let t0 = i + f * 0.00123, t1 = i + f * 0.00234, t2 = i + f * 0.00345, t3 = i + f * 0.00456;
21 | lines[i].fromTwoPoints({ x:signedNoise(t0) * 640, y: signedNoise(t1) * 640 }, { x:signedNoise(t2) * 640, y: signedNoise(t3) * 640 });
22 | }
23 |
24 | translate(width / 2, height / 2);
25 |
26 | fill(255); stroke(0);
27 | for (let i = 0; i < lines.length; i ++) {
28 | lines[i].draw(boundary);
29 | }
30 |
31 | for (let i = 0; i < lines.length; i ++) {
32 | for (let j = i + 1; j < lines.length; j ++) {
33 | let p = lines[i].getIntersectionPoint(lines[j]);
34 | if (p) {
35 | drawCircleMarker(p, 3);
36 | }
37 | }
38 | }
39 | }
40 |
41 | /** signedNoise **/
42 |
43 | /** Line **/
44 |
45 | /** LineSegment **/
46 |
47 | /** drawCircleMarker **/
48 |
--------------------------------------------------------------------------------
/js/examples/math/manhattan_distance.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 |
4 | counter = 0;
5 | p = createVector(0, 0);
6 | q = createVector(0, 0);
7 | r = createVector(0, 0);
8 | }
9 |
10 | function draw() {
11 | clear();
12 | const cx = width / 2, cy = height / 2;
13 | const t = frameCount + 30;
14 | const a0 = radians(t), a1 = radians(t * 2), a2 = radians(t * 3), a3 = radians(t * 4);
15 | p.x = cos(a0) * 150;
16 | p.y = sin(a3) * 100;
17 | q.x = -cos(a1) * 150;
18 | q.y = -sin(a2) * 100;
19 | r.x = p.x;
20 | r.y = q.y;
21 |
22 | const dx = Math.abs(p.x - q.x);
23 | const dy = Math.abs(p.y - q.y);
24 | const distance = dx + dy;
25 |
26 | background(245, 177, 217);
27 |
28 | push();
29 | translate(cx, cy);
30 | fill(0); stroke(0);
31 | drawLineWithLabel(p.x, p.y, r.x, r.y, "dx: " + dx.toPrecision(4), LEFT);
32 | drawLineWithLabel(q.x, q.y, r.x, r.y, "dy: " + dy.toPrecision(4), CENTER, 0, -4);
33 | drawLabel(0, cy - 16, "distance = dx + dy = " + distance.toPrecision(4), CENTER);
34 | drawSquareMarker(p, 10);
35 | drawTriangleMarker(q, 12);
36 | drawCircleMarker(r, 4);
37 | pop();
38 |
39 | counter ++;
40 | }
41 |
42 | /** drawCircleMarker **/
43 |
44 | /** drawSquareMarker **/
45 |
46 | /** drawTriangleMarker **/
47 |
48 | /** drawLineWithLabel **/
49 |
50 | /** drawLabel **/
--------------------------------------------------------------------------------
/js/examples/random/random_power.js:
--------------------------------------------------------------------------------
1 | let n = 0.2;
2 | let record, max;
3 | let resolution = 150;
4 |
5 | function setup() {
6 | initRecord();
7 | for (let i = 0; i < resolution * 10; i ++) {
8 | nextRandom();
9 | }
10 | canvas = createCanvas(windowWidth, windowHeight);
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(254, 253, 183);
16 |
17 | let v;
18 | for (let i = 0; i < resolution; i ++) {
19 | v = nextRandom();
20 | line(v * width, 0, v * width, height);
21 | }
22 |
23 | fill(0);stroke(0);
24 | for (let i = 0; i < resolution; i ++) {
25 | let w = width / resolution;
26 | let h = height / max * record[i];
27 | let x = w * i;
28 | let y = height - h;
29 | rect(x, y, w, h);
30 | }
31 |
32 | fill(254, 253, 183);
33 | drawLabel((n < 1) ? width -16 : 16, height - 16, "n = " + n.toPrecision(2), (n < 1) ? RIGHT : LEFT);
34 |
35 | n = (floor(frameCount / 60) % 10 + 1) * 0.2;
36 | if (frameCount % 60 == 0) {
37 | initRecord();
38 | }
39 | }
40 |
41 | function initRecord() {
42 | max = 1;
43 | if (!record) {
44 | record = [];
45 | } else {
46 | record.length = 0;
47 | }
48 |
49 | for (let i = 0; i < resolution; i ++) {
50 | record.push(0);
51 | }
52 | }
53 |
54 | function nextRandom() {
55 | let v = pow(random(1), n);
56 | if (++record[floor(v * resolution)] > max) {max ++};
57 | return v;
58 | }
59 |
60 | /** drawLabel **/
61 |
--------------------------------------------------------------------------------
/js/examples/random/random_average2.js:
--------------------------------------------------------------------------------
1 | let n = 10;
2 | let record, max;
3 | let resolution = 150;
4 |
5 | function setup() {
6 | initRecord();
7 | for (let i = 0; i < resolution * 10; i ++) {
8 | nextRandom();
9 | }
10 | canvas = createCanvas(windowWidth, windowHeight);
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(254, 253, 183);
16 |
17 | let v;
18 | for (let i = 0; i < resolution; i ++) {
19 | v = nextRandom();
20 | line(v * width, 0, v * width, height);
21 | }
22 |
23 | fill(0);stroke(0);
24 | for (let i = 0; i < resolution; i ++) {
25 | let w = width / resolution;
26 | let h = height / max * record[i];
27 | let x = w * i;
28 | let y = height - h;
29 | rect(x, y, w, h);
30 | }
31 |
32 | fill(254, 253, 183);
33 | drawLabel(width / 2, height - 16, "n = " + n, CENTER);
34 |
35 | n = floor(frameCount / 60) % 9 + 2;
36 | if (frameCount % 60 == 0) {
37 | initRecord();
38 | }
39 | }
40 |
41 | function initRecord() {
42 | max = 1;
43 | if (!record) {
44 | record = [];
45 | } else {
46 | record.length = 0;
47 | }
48 |
49 | for (let i = 0; i < resolution; i ++) {
50 | record.push(0);
51 | }
52 | }
53 |
54 | function nextRandom() {
55 | let v = 0;
56 | for (let i = 0; i < n; i ++) {
57 | v += random(1);
58 | }
59 | v /= n;
60 | if (++record[floor(v * resolution)] > max) {max ++};
61 | return v;
62 | }
63 |
64 | /** drawLabel **/
65 |
--------------------------------------------------------------------------------
/js/examples/easing/colliding.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevNow = 0;
2 | let tween, tweens;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | tween = new Tween();
7 | tweens = [
8 | (t)=>{return tween.powerInOut(t, 2)},
9 | (t)=>{return tween.powerOut(t, 2)},
10 | (t)=>{return tween.powerOut(t, 3)}
11 | ]
12 | }
13 |
14 | function draw() {
15 | clear();
16 | background(73, 5, 255);
17 |
18 | let duration = 500, baseSize = 72;
19 | let t = (msec % (duration)) / duration;
20 | let i = Math.floor(msec / duration);
21 | let phase = i % 4;
22 | let reverse = i % 2;
23 |
24 |
25 | fill(255); stroke(0);
26 | push();
27 | translate(width / 2, height / 2);
28 | for (let i = 0; i < 3; i ++) {
29 | let xr0 = 0, xr1 = 0, y = (i - 1) * baseSize * 1.3;
30 | let d = width * 0.4;
31 | switch(phase) {
32 | case 0:
33 | xr0 = tweens[i](t);
34 | break;
35 | case 1:
36 | xr0 = tweens[i](1 - t);
37 | break;
38 | case 2:
39 | xr1 = tweens[i](t);
40 | break;
41 | case 3:
42 | xr1 = tweens[i](1 - t);
43 | break;
44 | }
45 |
46 | ellipse(d * -xr0 - baseSize / 2, y, baseSize);
47 | ellipse(d * xr1 + baseSize / 2, y, baseSize);
48 | }
49 | pop();
50 |
51 | ellapseTime();
52 | }
53 |
54 | function ellapseTime() {
55 | msec += min(100, window.performance.now() - prevNow);
56 | prevNow = window.performance.now();
57 | }
58 |
59 | /** Tween **/
60 |
--------------------------------------------------------------------------------
/js/examples/drawings/circle.js:
--------------------------------------------------------------------------------
1 |
2 | let lines = [];
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | lines.push(new Line(0, 1, 0)); // X-axis: a = 0, b != 0, c = 0
7 | lines.push(new Line(1, 0, 0)); // Y-axis: a != 0, b = 0, c = 0
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(255, 235, 59);
13 |
14 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height}
15 |
16 | let points = [];
17 | for (let i = 0; i < 3; i ++) {
18 | let f = frameCount + 100;
19 | let t0 = i + f * 0.00123, t1 = i + f * 0.00234;
20 | points.push(createVector(signedNoise(t0) * 320,signedNoise(t1) * 320));
21 | }
22 | let circle = new Circle().fromThreePoints(points[0], points[1], points[2]);
23 |
24 | translate(width / 2, height / 2);
25 |
26 | noFill(); stroke(0);
27 | for (let i = 0; i < lines.length; i ++) {
28 | lines[i].draw(boundary);
29 | }
30 |
31 | circle.draw();
32 |
33 | fill(255);
34 | for (let i = 0; i < points.length; i ++) {
35 | drawCircleMarker(points[i], 3);
36 | }
37 | drawCircleMarker(circle.center, 3);
38 |
39 |
40 | fill(0); noStroke();
41 | for (let i = 0; i < lines.length; i ++) {
42 | let intersections = circle.getIntersectionPoints(lines[i]);
43 | for (let j = 0; j < intersections.length; j++) {
44 | drawCircleMarker(intersections[j], 3);
45 | }
46 | }
47 | }
48 |
49 | /** signedNoise **/
50 |
51 | /** Line **/
52 |
53 | /** Circle **/
54 |
55 | /** drawCircleMarker **/
56 |
--------------------------------------------------------------------------------
/js/examples/collision/collision_line_circle.js:
--------------------------------------------------------------------------------
1 | let A, B, P;
2 | let radius = 60;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | A = createVector();
7 | B = createVector();
8 | P = createVector();
9 | }
10 |
11 | function draw() {
12 | clear();
13 | background(249, 246, 236);
14 | let t = radians(frameCount);
15 | P.x = cos(t) * 120;
16 | P.y = sin(t * 1.5) * 120;
17 | A.x = 60;
18 | A.y = -height / 2;
19 | B.x = -60;
20 | B.y = height / 2;
21 |
22 | // test
23 | let ap = P.copy().sub(A);
24 | let ab = B.copy().sub(A);
25 | let d = (ap.x * ab.y - ab.x * ap.y) / ab.mag();
26 |
27 | let result = abs(d) <= radius;
28 |
29 | // rendering
30 |
31 | push();
32 | translate(width / 2, height / 2);
33 |
34 | noStroke();
35 | if (result) {
36 | fill(225, 81, 106);
37 | } else {
38 | fill(255);
39 | }
40 | ellipse(P.x, P.y, radius * 2);
41 |
42 | noFill(); stroke(0); strokeWeight(1);
43 | ellipse(P.x, P.y, radius * 2);
44 | line(A.x, A.y, B.x, B.y);
45 |
46 | let l = new Line().fromTwoPoints(A, B);
47 | let q = l.getNearestPoint(P);
48 | if (result) {
49 | strokeWeight(3);
50 | stroke(0, 0, 0, 255);
51 | }
52 | line(q.x, q.y, P.x, P.y);
53 |
54 | stroke(0, 0, 0, 32); strokeWeight(1);
55 |
56 | line(A.x, A.y, P.x, P.y);
57 |
58 | fill(0);
59 | drawLabel(P.x + 8, P.y, "P", "RIGHT");
60 | drawLabel(A.x + 8, A.y + 16, "A", "RIGHT");
61 | drawLabel(B.x + 8, B.y - 8, "B", "RIGHT");
62 |
63 | pop();
64 | }
65 |
66 | /** Line **/
67 |
68 | /** drawLabel **/
69 |
--------------------------------------------------------------------------------
/js/examples/verlet/verlet_points.js:
--------------------------------------------------------------------------------
1 |
2 | let points = [];
3 | let accelIndex, accel;
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 | for (let i = 0; i < 10; i ++) {
8 | points.push(new VerletPoint( createVector(random(width), random(height))) );
9 | points[i].position.add(random2D().mult(random(2) + 1));
10 | }
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(100, 150, 180);
16 | points.forEach((p)=>{
17 | p.update();
18 | if (p.position.x < 0) { p.position.x += 2; }
19 | if (p.position.x > width) { p.position.x -= 2; }
20 | if (p.position.y < 0) { p.position.y += 2; }
21 | if (p.position.y > height) { p.position.y -= 2; }
22 | if (p.getVelocity().mag() > 3) {
23 | p.setVelocity(p.getVelocity().normalize().mult(3)); // limit the speed
24 | }
25 | });
26 |
27 | let f = (frameCount - 1) % 60;
28 | if (f == 0) {
29 | accelIndex = floor(random(points.length));
30 | accel = random2D().mult((random(0.5) + 0.5));
31 | }
32 |
33 |
34 | fill(255); stroke(0); strokeWeight(3);
35 | if (f < 30) {
36 | points[accelIndex].position.add(accel);
37 | let p0 = points[accelIndex].position;
38 | let p1 = points[accelIndex].position.copy().add(accel.copy().mult(100));
39 | drawArrow(p0.x, p0.y, p1.x, p1.y);
40 | }
41 | strokeWeight(1);
42 | points.forEach((p)=>{p.draw();});
43 | }
44 |
45 | function random2D() {
46 | return createVector(random(-1, 1), random(-1, 1)).normalize();
47 | }
48 |
49 | /** random2D **/
50 |
51 | /** drawArrow **/
52 |
53 | /** VerletPoint **/
54 |
--------------------------------------------------------------------------------
/js/examples/drawings/line_segments.js:
--------------------------------------------------------------------------------
1 |
2 | let lines = [];
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 |
7 | lines.push(new Line(0, 1, 0)); // X-axis: a = 0, b != 0, c = 0
8 | lines.push(new Line(1, 0, 0)); // Y-axis: a != 0, b = 0, c = 0
9 | lines.push(new LineSegment());
10 | lines.push(new LineSegment());
11 | lines.push(new LineSegment());
12 | }
13 |
14 | function draw() {
15 | clear();
16 | background(255, 235, 59);
17 |
18 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height}
19 |
20 | for (let i = 2; i < lines.length; i ++) {
21 | let f = frameCount + 100;
22 | let t0 = i + f * 0.00123, t1 = i + f * 0.00234, t2 = i + f * 0.00345, t3 = i + f * 0.00456;
23 | lines[i].fromTwoPoints(createVector(signedNoise(t0) * 320,signedNoise(t1) * 320), createVector(signedNoise(t2) * 320, signedNoise(t3) * 320));
24 | }
25 |
26 | translate(width / 2, height / 2);
27 |
28 | fill(255); stroke(0);
29 | for (let i = 0; i < lines.length; i ++) {
30 | lines[i].draw(boundary);
31 | }
32 |
33 | for (let i = 0; i < lines.length; i ++) {
34 | if (lines[i] instanceof LineSegment) {
35 | drawCircleMarker(lines[i].p0, 3);
36 | drawCircleMarker(lines[i].p1, 3);
37 | }
38 | for (let j = i + 1; j < lines.length; j ++) {
39 | let p = lines[i].getIntersectionPoint(lines[j]);
40 | if (p) {
41 | drawCircleMarker(p, 3);
42 | }
43 | }
44 | }
45 | }
46 |
47 | /** signedNoise **/
48 |
49 | /** Line **/
50 |
51 | /** LineSegment **/
52 |
53 | /** drawCircleMarker **/
54 |
--------------------------------------------------------------------------------
/js/examples/math/dot_product.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 |
4 | deg = 240;
5 | }
6 |
7 | function draw() {
8 | clear();
9 | let m = 60; // magnifier
10 | let v1 = createVector(1, -1).normalize();
11 | let rad = radians(deg);
12 | let v2 = createVector(cos(rad), sin(rad)).mult(3);
13 | let dotProduct = v2.dot(v1.copy().normalize());
14 | let p = v1.copy().normalize().mult(dotProduct);
15 |
16 | background(15, 157, 88);
17 |
18 | push();
19 | translate(width / 2, height / 2);
20 |
21 | fill(255); stroke(0); strokeWeight(1);
22 | let hh = height / 2;
23 | //line(-hh, -hh, hh, hh);
24 | line(-hh, hh, hh, -hh);
25 | line(v2.x * m, v2.y * m, p.x * m, p.y * m);
26 |
27 | fill(0); stroke(0); strokeWeight(3);
28 | drawArrow(0, 0, v1.x * m, v1.y * m);
29 | drawArrow(0, 0, v2.x * m, v2.y * m);
30 |
31 | strokeWeight(1);
32 | line(0, 0, 72, 72);
33 | line(p.x * m, p.y * m, p.x * m + 72, p.y * m + 72);
34 | drawLineWithLabel(64, 64, p.x * m + 64, p.y * m + 64, " dot product = " + dotProduct.toPrecision(3), LEFT);
35 |
36 | fill(255); stroke(0); strokeWeight(1);
37 | drawCircleMarker(p.copy().mult(m), 4);
38 | drawCircleMarker(v2.copy().mult(m), 4);
39 | drawCircleMarker(createVector(0, 0), 4);
40 |
41 | fill(0); noStroke()
42 | drawLabel(v1.x * m + 4, v1.y * m, "v1(magnitude = 1)", LEFT);
43 | drawLabel(v2.x * m + 4, v2.y * m, "v2(magnitude = 3)", LEFT);
44 | deg ++;
45 | }
46 |
47 | /** drawLineWithLabel **/
48 |
49 | /** drawLabel **/
50 |
51 | /** drawArrow **/
52 |
53 | /** drawCircleMarker **/
54 |
--------------------------------------------------------------------------------
/js/examples/math/raycasting.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | deg = 45;
4 | }
5 |
6 | function draw() {
7 | clear();
8 |
9 | let hypotenuse = 100;
10 | let rad = radians(deg); // PI * deg / 180;
11 |
12 | let sine = sin(rad);
13 | let cosine = cos(rad);
14 | let opposite = sine * hypotenuse;
15 | let adjacent = cosine * hypotenuse;
16 | let tangent = sine / cosine;
17 |
18 | background(135, 108, 209);
19 |
20 | push();
21 | translate(width / 2, height / 2);
22 | fill(255);
23 | stroke(0); strokeWeight(1);
24 | ellipse(0, 0, hypotenuse * 2, hypotenuse * 2);
25 | line(-hypotenuse, 0, hypotenuse, 0);
26 |
27 | fill(0); stroke(0); strokeWeight(3);
28 | line(0, 0, adjacent, 0);
29 | drawLineWithLabel(0, 0, adjacent, -opposite, "hypotenuse:" + hypotenuse.toPrecision(3), (adjacent > 0) ? RIGHT : LEFT);
30 | drawLineWithLabel(adjacent, 0, adjacent, -opposite, "opposite:" + opposite.toPrecision(3), (adjacent > 0) ? LEFT : RIGHT);
31 | drawLabel(adjacent / 2, 16, "adjacent:" + adjacent.toPrecision(3), LEFT);
32 | pop();
33 |
34 | drawLabel(16, windowHeight - 120, "angle(degrees):" + deg.toPrecision(3), LEFT);
35 | drawLabel(16, windowHeight - 96, "angle(radians):" + rad.toPrecision(3), LEFT);
36 | drawLabel(16, windowHeight - 72, "sine:" + sine.toPrecision(3), LEFT);
37 | drawLabel(16, windowHeight - 48, "cosine:" + cosine.toPrecision(3), LEFT);
38 | drawLabel(16, windowHeight - 24, "tangent:" + tangent.toPrecision(3), LEFT);
39 |
40 | deg ++;
41 | }
42 |
43 | /** drawLineWithLabel **/
44 |
45 | /** drawLabel **/
46 |
--------------------------------------------------------------------------------
/js/examples/math/sine_cosine.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | deg = 45;
4 | }
5 |
6 | function draw() {
7 | clear();
8 |
9 | let hypotenuse = 100;
10 | let rad = radians(deg); // PI * deg / 180;
11 |
12 | let sine = sin(rad);
13 | let cosine = cos(rad);
14 | let opposite = sine * hypotenuse;
15 | let adjacent = cosine * hypotenuse;
16 | let tangent = sine / cosine;
17 |
18 | background(135, 108, 209);
19 |
20 | push();
21 | translate(width / 2, height / 2);
22 | fill(255);
23 | stroke(0); strokeWeight(1);
24 | ellipse(0, 0, hypotenuse * 2, hypotenuse * 2);
25 | line(-hypotenuse, 0, hypotenuse, 0);
26 |
27 | fill(0); stroke(0); strokeWeight(3);
28 | line(0, 0, adjacent, 0);
29 | drawLineWithLabel(0, 0, adjacent, -opposite, "hypotenuse:" + hypotenuse.toPrecision(3), (adjacent > 0) ? RIGHT : LEFT);
30 | drawLineWithLabel(adjacent, 0, adjacent, -opposite, "opposite:" + opposite.toPrecision(3), (adjacent > 0) ? LEFT : RIGHT);
31 | drawLabel(adjacent / 2, 16, "adjacent:" + adjacent.toPrecision(3), LEFT);
32 | pop();
33 |
34 | drawLabel(16, windowHeight - 120, "angle(degrees):" + deg.toPrecision(3), LEFT);
35 | drawLabel(16, windowHeight - 96, "angle(radians):" + rad.toPrecision(3), LEFT);
36 | drawLabel(16, windowHeight - 72, "sine:" + sine.toPrecision(3), LEFT);
37 | drawLabel(16, windowHeight - 48, "cosine:" + cosine.toPrecision(3), LEFT);
38 | drawLabel(16, windowHeight - 24, "tangent:" + tangent.toPrecision(3), LEFT);
39 |
40 | deg ++;
41 | }
42 |
43 | /** drawLineWithLabel **/
44 |
45 | /** drawLabel **/
46 |
--------------------------------------------------------------------------------
/js/examples/machines/piston.js:
--------------------------------------------------------------------------------
1 | let center, centerLine, armLength, radius;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | center = createVector(width * 0.5, height * 0.75);
6 | centerLine = new Line().fromTwoPoints(createVector(width * 0.5, 0), createVector(width * 0.5, height));
7 | armLength = height * 0.3;
8 | radius = height * 0.14;
9 | }
10 |
11 | function draw() {
12 | clear();
13 | background(0, 171, 107);
14 |
15 | let a = radians((frameCount - 1) * 4);
16 | let p = createVector(cos(a) * radius, sin(a) * radius).add(center);
17 | let circle = new Circle().fromCenterAndRadius(p, armLength);
18 | let intersections = circle.getIntersectionPoints(centerLine);
19 | let pistonBottom = intersections[0];
20 |
21 | if (intersections.length > 1 && intersections[1].y < intersections[0].y) {
22 | pistonBottom = intersections[1];
23 | }
24 | let arm = new LineSegment().fromTwoPoints(p, pistonBottom);
25 |
26 | fill(171, 232, 199); stroke(0);
27 | ellipse(center.x, center.y, radius * 2, radius * 2);
28 | fill(12, 228, 113);
29 | rect(center.x - 60, -1, 120, pistonBottom.y + 1);
30 |
31 | noFill();stroke(0);
32 | line(center.x, center.y, p.x, p.y);
33 | centerLine.draw();
34 |
35 | strokeWeight(3);
36 | arm.draw();
37 |
38 | fill(255); strokeWeight(1);
39 | drawCircleMarker(center, 4);
40 | drawCircleMarker(p, 4);
41 | drawCircleMarker(arm.p1, 4);
42 | drawCircleMarker(pistonBottom, 4);
43 | }
44 |
45 | /** Line **/
46 |
47 | /** LineSegment **/
48 |
49 | /** Circle **/
50 |
51 | /** drawLabel **/
52 |
53 | /** drawCircleMarker **/
54 |
--------------------------------------------------------------------------------
/js/examples/machines/crank2.js:
--------------------------------------------------------------------------------
1 | let log = [];
2 | let centerA, centerB, radiusA, radiusB, armLength;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | centerA = createVector(width * 0.25, height * 0.5);
7 | centerB = createVector(width * 0.5, height * 0.5);
8 | armLength = width * 0.5;
9 | radiusA = min(height * 0.2, centerA.dist(centerB) * 0.5);
10 | radiusB = radiusA * 0.5;
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(69, 157, 193);
16 |
17 | let aA = radians((frameCount - 1) * 2) + PI * 0.5;
18 | let aB = radians((frameCount - 1) * 5) - PI * 0.5;
19 | let pA = createVector(cos(aA) * radiusA, sin(aA) * radiusA).add(centerA);
20 | let pB = createVector(cos(aB) * radiusB, sin(aB) * radiusB).add(centerB);
21 | let arm = new LineSegment().fromTwoPointsAndLength(pA, pB, armLength);
22 | noFill();stroke(0);
23 |
24 | log.push(arm.p1);
25 | if (log.length > 120) { log.shift(); }
26 |
27 | fill(253, 219, 192); stroke(0);
28 | ellipse(centerA.x, centerA.y, radiusA * 2, radiusA * 2);
29 | ellipse(centerB.x, centerB.y, radiusB * 2, radiusB * 2);
30 | noFill();
31 | line(centerA.x, centerA.y, pA.x, pA.y);
32 | line(centerB.x, centerB.y, pB.x, pB.y);
33 |
34 |
35 | strokeWeight(3);
36 | beginShape();
37 | for (let i = 0; i < log.length; i ++) {
38 | vertex(log[i].x, log[i].y);
39 | }
40 | endShape();
41 |
42 | arm.draw();
43 |
44 | fill(255); strokeWeight(1);
45 | drawCircleMarker(centerA, 4);
46 | drawCircleMarker(centerB, 4);
47 | drawCircleMarker(pA, 4);
48 | drawCircleMarker(pB, 4);
49 | drawCircleMarker(arm.p1, 4);
50 | }
51 |
52 | /** LineSegment **/
53 |
54 | /** drawLabel **/
55 |
56 | /** drawCircleMarker **/
57 |
--------------------------------------------------------------------------------
/js/examples/distance/circle.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | stepLength = 16;
4 | x = 0;
5 | y = 0;
6 | dx = 0;
7 | dy = -1;
8 | steps = 0;
9 | next = 1;
10 | phase = 0;
11 |
12 | count = 0;
13 | background(20, 80, 130);
14 | }
15 |
16 | function distance(p, center, radius) {
17 | return Math.sqrt(Math.pow(p.x - center.x, 2) + Math.pow(p.y - center.y, 2)) - radius; // or use p5.Vector.dist()
18 | }
19 |
20 | function draw() {
21 | const hw = width / 2;
22 | const hh = height / 2;
23 |
24 | const p = createVector(x * stepLength, y * stepLength);
25 | const dist = distance(p, createVector(0, 0), 128);
26 | const size = Math.max(0.25, 1 - (128 - Math.abs(dist)) / 128) * 4;
27 | push();
28 | translate(hw, hh);
29 | if (dist >= 0) {
30 | fill(0); noStroke();
31 | } else {
32 | fill(255); noStroke();
33 | }
34 |
35 | drawCircleMarker(p, size);
36 | pop();
37 |
38 | x += dx;
39 | y += dy;
40 | steps ++;
41 |
42 | if (steps >= next) {
43 | steps = 0;
44 | if (dx == 1) {
45 | dx = 0; dy = 1;
46 | } else if (dx == -1) {
47 | dx = 0; dy = -1;
48 | } else if (dy == 1) {
49 | dx = -1; dy = 0;
50 | } else if (dy == -1) {
51 | dx = 1; dy = 0;
52 | }
53 | if (phase == 1) {
54 | next ++;
55 | }
56 | phase = (phase + 1) % 2;
57 |
58 | if (next * stepLength >= height) {
59 | background(20, 80, 130);
60 | x = 0; y = 0; dx = 0; dy = -1; steps = 0; next = 1; phase = 0;
61 | }
62 | }
63 | }
64 |
65 | /** drawCircleMarker **/
66 |
--------------------------------------------------------------------------------
/js/examples/wave/square_wave.js:
--------------------------------------------------------------------------------
1 | let prevInitFrame = 1;
2 | let n = 1;
3 | let baseRadius = 100;
4 | let plotData = [];
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(224, 239, 243);
13 |
14 | let x = 0, y = 0;
15 |
16 | push();
17 | translate(baseRadius + 20, height / 2);
18 | fill(255); stroke(0); strokeWeight(1);
19 | ellipse(x, y, baseRadius * 2, baseRadius * 2);
20 |
21 | let m = 4 / PI;
22 | for (let i = 0; i < n; i ++) {
23 | let d = 1 + i * 2;
24 | let rad = radians(frameCount - 1) * 2 * d;
25 | let radius = baseRadius / d * m;
26 | let sine = sin(rad);
27 | let cosine = cos(rad);
28 | let nx = x + cosine * radius;
29 | let ny = y - sine * radius;
30 |
31 | line(x, y, nx, ny);
32 | drawCircleMarker(createVector(nx, ny), 2);
33 | x = nx;
34 | y = ny;
35 | }
36 |
37 | drawCircleMarker(createVector(0, 0), 2);
38 | line(baseRadius + 20, y, -baseRadius - 20, y);
39 | drawCircleMarker(createVector(x, y), 4);
40 | pop();
41 |
42 | let graphW = width - (baseRadius + 20) * 2;
43 | let graphX = (baseRadius + 20) * 2;
44 |
45 | if (frameCount > prevInitFrame + graphW) {
46 | plotData = [];
47 | prevInitFrame += graphW;
48 | }
49 | plotData.push({x:frameCount - prevInitFrame, y: -y});
50 |
51 | if (frameCount % 90 == 0) {
52 | n ++;
53 | if (n > 40) {
54 | n = 1;
55 | }
56 | }
57 |
58 | plotGraph(plotData, graphX, height / 2, graphW, height - 64, 0, graphW, -height / 2 + 32, height / 2 - 32, "time", "y");
59 |
60 | drawLabel(8, height - 32, "n = " + n, LEFT);
61 | }
62 |
63 | /** plotGraph **/
64 |
65 | /** drawLabel **/
66 |
67 | /** drawCircleMarker **/
68 |
--------------------------------------------------------------------------------
/js/examples/distance/rectangle.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | stepLength = 16;
4 | x = 0;
5 | y = 0;
6 | dx = 0;
7 | dy = -1;
8 | steps = 0;
9 | next = 1;
10 | phase = 0;
11 |
12 | count = 0;
13 | background(20, 80, 130);
14 | }
15 |
16 | function distance(p, size, center, radius) {
17 | const diff = p.copy().sub(center);
18 | return Math.max(Math.abs(diff.x) - size.x, Math.abs(diff.y) - size.y);
19 | }
20 |
21 | function draw() {
22 | const hw = width / 2;
23 | const hh = height / 2;
24 |
25 | const p = createVector(x * stepLength, y * stepLength);
26 | const dist = distance(p, createVector(128, 64), createVector(0, 0), 128);
27 | const size = Math.max(0.25, 1 - (128 - Math.abs(dist)) / 128) * 4;
28 | push();
29 | translate(hw, hh);
30 | if (dist >= 0) {
31 | fill(0); noStroke();
32 | } else {
33 | fill(255); noStroke();
34 | }
35 |
36 | drawCircleMarker(p, size);
37 | pop();
38 |
39 | x += dx;
40 | y += dy;
41 | steps ++;
42 |
43 | if (steps >= next) {
44 | steps = 0;
45 | if (dx == 1) {
46 | dx = 0; dy = 1;
47 | } else if (dx == -1) {
48 | dx = 0; dy = -1;
49 | } else if (dy == 1) {
50 | dx = -1; dy = 0;
51 | } else if (dy == -1) {
52 | dx = 1; dy = 0;
53 | }
54 | if (phase == 1) {
55 | next ++;
56 | }
57 | phase = (phase + 1) % 2;
58 |
59 | if (next * stepLength >= height) {
60 | background(20, 80, 130);
61 | x = 0; y = 0; dx = 0; dy = -1; steps = 0; next = 1; phase = 0;
62 | }
63 | }
64 | }
65 |
66 | /** drawCircleMarker **/
67 |
--------------------------------------------------------------------------------
/js/examples/wave/triangle_wave.js:
--------------------------------------------------------------------------------
1 | let prevInitFrame = 1;
2 | let n = 1;
3 | let baseRadius = 100;
4 | let plotData = [];
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(224, 239, 243);
13 |
14 | let x = 0, y = 0;
15 |
16 | push();
17 | translate(baseRadius + 20, height / 2);
18 | fill(255); stroke(0); strokeWeight(1);
19 | ellipse(x, y, baseRadius * 2, baseRadius * 2);
20 |
21 | let m = 8 / PI / PI;
22 | for (let i = 0; i < n; i ++) {
23 | let d = 1 + i * 2;
24 | let rad = radians(frameCount - 1) * 2 * d;
25 | let radius = baseRadius / pow(d, 2) * (i % 2 == 0 ? 1 : -1) * m;
26 | let sine = sin(rad);
27 | let cosine = cos(rad);
28 | let nx = x + cosine * radius;
29 | let ny = y - sine * radius;
30 |
31 | line(x, y, nx, ny);
32 | drawCircleMarker(createVector(nx, ny), 2);
33 | x = nx;
34 | y = ny;
35 | }
36 |
37 | drawCircleMarker(createVector(0, 0), 2);
38 | line(baseRadius + 20, y, -baseRadius - 20, y);
39 | drawCircleMarker(createVector(x, y), 4);
40 | pop();
41 |
42 |
43 | let graphW = width - (baseRadius + 20) * 2;
44 | let graphX = (baseRadius + 20) * 2;
45 |
46 | if (frameCount > prevInitFrame + graphW) {
47 | plotData = [];
48 | prevInitFrame += graphW;
49 | }
50 | plotData.push({x:frameCount - prevInitFrame, y: -y});
51 |
52 | if (frameCount % 90 == 0) {
53 | n ++;
54 | if (n > 40) {
55 | n = 1;
56 | }
57 | }
58 |
59 | plotGraph(plotData, graphX, height / 2, graphW, height - 64, 0, graphW, -height / 2 + 32, height / 2 - 32, "time", "y");
60 | drawLabel(8, height - 32, "n = " + n, LEFT);
61 | }
62 |
63 | /** plotGraph **/
64 |
65 | /** drawLabel **/
66 |
67 | /** drawCircleMarker **/
68 |
--------------------------------------------------------------------------------
/js/examples/collision/collision_circles.js:
--------------------------------------------------------------------------------
1 | let A, B;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 |
6 | A = {center: createVector(), radius: 80};
7 | B = {center: createVector(), radius: 60};
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(249, 246, 236);
13 | let t = radians(frameCount) / 2;
14 | A.center.x = cos(t) * 120;
15 | A.center.y = sin((t + 1) * 2) * 120;
16 | B.center.x = -cos((t + 2) * 3) * 100;
17 | B.center.y = -sin((t + 3) * 4) * 100;
18 |
19 | // test
20 |
21 | let result = A.center.dist(B.center) - A.radius - B.radius <= 0;
22 |
23 | // rendering
24 |
25 | push();
26 | translate(width / 2, height / 2);
27 |
28 | noStroke();
29 | if (result) {
30 | fill(225, 81, 106);
31 | } else {
32 | fill(255);
33 | }
34 | ellipse(A.center.x, A.center.y, A.radius * 2);
35 | ellipse(B.center.x, B.center.y, B.radius * 2);
36 |
37 | noFill(); stroke(0); strokeWeight(1);
38 | ellipse(A.center.x, A.center.y, A.radius * 2);
39 | ellipse(B.center.x, B.center.y, B.radius * 2);
40 |
41 | let pA = A.center.copy().add(B.center.copy().sub(A.center).normalize().mult(A.radius));
42 | let pB = B.center.copy().add(A.center.copy().sub(B.center).normalize().mult(B.radius));
43 |
44 | strokeWeight(1);
45 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
46 | let l = new Line().fromTwoPoints(A.center, B.center);
47 | let perpA = l.getPerpendicular(pA);
48 | let perpB = l.getPerpendicular(pB);
49 | l.draw(boundary);
50 |
51 | stroke(0, 0, 0, 128);
52 | perpA.draw(boundary);
53 | perpB.draw(boundary);
54 |
55 | if (result) {
56 | strokeWeight(3);
57 | stroke(0, 0, 0, 255);
58 | line(pA.x, pA.y, pB.x, pB.y);
59 | }
60 |
61 | pop();
62 | }
63 |
64 | /** Line **/
65 |
--------------------------------------------------------------------------------
/js/examples/wave/saw_wave.js:
--------------------------------------------------------------------------------
1 | let prevInitFrame = 1;
2 | let n = 1;
3 | let baseRadius = 100;
4 | let plotData = [];
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(224, 239, 243);
13 |
14 | let x = 0, y = 0;
15 |
16 | push();
17 | translate(baseRadius + 20, height / 2);
18 | fill(255); stroke(0); strokeWeight(1);
19 | ellipse(x, y, baseRadius * 2, baseRadius * 2);
20 |
21 | let m = 2 / PI;
22 | for (let i = 1; i <= n; i ++) {
23 | let rad = radians(frameCount - 1) * 2 * i;
24 | let radius = baseRadius / i * (i % 2 == 0 ? -1 : 1) * m;
25 | let sine = sin(rad);
26 | let cosine = cos(rad);
27 | let nx = x + cosine * radius;
28 | let ny = y - sine * radius;
29 | if (i == 0) {
30 | ellipse(x, y, radius * 2, radius * 2);
31 | }
32 |
33 | line(x, y, nx, ny);
34 | drawCircleMarker(createVector(nx, ny), 2);
35 | x = nx;
36 | y = ny;
37 | }
38 |
39 | drawCircleMarker(createVector(0, 0), 2);
40 | line(baseRadius + 20, y, -baseRadius - 20, y);
41 | drawCircleMarker(createVector(x, y), 4);
42 | pop();
43 |
44 |
45 | let graphW = width - (baseRadius + 20) * 2;
46 | let graphX = (baseRadius + 20) * 2;
47 |
48 | if (frameCount > prevInitFrame + graphW) {
49 | plotData = [];
50 | prevInitFrame += graphW;
51 | }
52 | plotData.push({x:frameCount - prevInitFrame, y: -y});
53 |
54 | if (frameCount % 90 == 0) {
55 | n ++;
56 | if (n > 40) {
57 | n = 1;
58 | }
59 | }
60 |
61 | plotGraph(plotData, graphX, height / 2, graphW, height - 64, 0, graphW, -height / 2 + 32, height / 2 - 32, "time", "y");
62 | drawLabel(8, height - 32, "n = " + n, LEFT);
63 |
64 | }
65 |
66 | /** plotGraph **/
67 |
68 | /** drawLabel **/
69 |
70 | /** drawCircleMarker **/
71 |
--------------------------------------------------------------------------------
/js/examples/distance/rotated_rectangle.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | stepLength = 16;
4 | x = 0;
5 | y = 0;
6 | dx = 0;
7 | dy = -1;
8 | steps = 0;
9 | next = 1;
10 | phase = 0;
11 |
12 | count = 0;
13 | background(20, 80, 130);
14 | }
15 |
16 | function distance(p, size, center, radius) {
17 | let diff = p.copy().sub(center);
18 | diff = rotate2d(diff, Math.PI * 0.25);
19 | return Math.max(Math.abs(diff.x) - size.x, Math.abs(diff.y) - size.y);
20 | }
21 |
22 | function draw() {
23 | const hw = width / 2;
24 | const hh = height / 2;
25 |
26 | const p = createVector(x * stepLength, y * stepLength);
27 | const dist = distance(p, createVector(128, 64), createVector(0, 0), 128);
28 | const size = Math.max(0.25, 1 - (128 - Math.abs(dist)) / 128) * 4;
29 | push();
30 | translate(hw, hh);
31 | if (dist >= 0) {
32 | fill(0); noStroke();
33 | } else {
34 | fill(255); noStroke();
35 | }
36 |
37 | drawCircleMarker(p, size);
38 | pop();
39 |
40 | x += dx;
41 | y += dy;
42 | steps ++;
43 |
44 | if (steps >= next) {
45 | steps = 0;
46 | if (dx == 1) {
47 | dx = 0; dy = 1;
48 | } else if (dx == -1) {
49 | dx = 0; dy = -1;
50 | } else if (dy == 1) {
51 | dx = -1; dy = 0;
52 | } else if (dy == -1) {
53 | dx = 1; dy = 0;
54 | }
55 | if (phase == 1) {
56 | next ++;
57 | }
58 | phase = (phase + 1) % 2;
59 |
60 | if (next * stepLength >= height) {
61 | background(20, 80, 130);
62 | x = 0; y = 0; dx = 0; dy = -1; steps = 0; next = 1; phase = 0;
63 | }
64 | }
65 | }
66 |
67 | /** rotate2d **/
68 |
69 | /** drawCircleMarker **/
70 |
--------------------------------------------------------------------------------
/js/examples/drawings/centroid.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | }
4 |
5 | function draw() {
6 | clear();
7 | background(62, 252, 100);
8 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
9 |
10 | let t = (frameCount % 720) / 720;
11 | let a0 = PI / 3 * cos(t * TWO_PI) + 0.01 + TWO_PI / 3 ;
12 | let a1 = PI / 3 * cos(t * TWO_PI * 3) + 0.02 + TWO_PI / 3 * 2;
13 | let a2 = PI / 3 * cos(t * TWO_PI * 5) + 0.03;
14 |
15 | let p0 = createVector(cos(a0), sin(a0)).mult(120);
16 | let p1 = createVector(cos(a1), sin(a1)).mult(140);
17 | let p2 = createVector(cos(a2), sin(a2)).mult(160);
18 |
19 | let s0 = new LineSegment().fromTwoPoints(p0, p1);
20 | let s1 = new LineSegment().fromTwoPoints(p1, p2);
21 | let s2 = new LineSegment().fromTwoPoints(p2, p0);
22 |
23 | let mp0 = s0.getMidPoint();
24 | let mp1 = s1.getMidPoint();
25 | let mp2 = s2.getMidPoint();
26 |
27 | let l0 = new Line().fromTwoPoints(p0, mp1);
28 | let l1 = new Line().fromTwoPoints(p1, mp2);
29 | let l2 = new Line().fromTwoPoints(p2, mp0);
30 | let centroid = l0.getIntersectionPoint(l1);
31 |
32 | push();
33 | translate(width / 2, height / 2);
34 | noFill(); stroke(0); strokeWeight(1);
35 | fill(0); strokeWeight(3);
36 | s0.draw();
37 | s1.draw();
38 | s2.draw();
39 | strokeWeight(1);
40 |
41 | l0.draw(boundary);
42 | l1.draw(boundary);
43 | l2.draw(boundary);
44 | drawCircleMarker(mp0, 3);
45 | drawCircleMarker(mp1, 3);
46 | drawCircleMarker(mp2, 3);
47 |
48 | fill(255);
49 | drawCircleMarker(p0, 3);
50 | drawCircleMarker(p1, 3);
51 | drawCircleMarker(p2, 3);
52 | if (centroid) {
53 | drawCircleMarker(centroid, 4);
54 | }
55 | pop();
56 | }
57 |
58 | /** Line **/
59 |
60 | /** LineSegment **/
61 |
62 | /** Circle **/
63 |
64 | /** drawCircleMarker **/
65 |
--------------------------------------------------------------------------------
/js/examples/easing/composite01.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | let msec = 0, prevNow = 0;
4 | const duration = 1000;
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | plotData = [];
9 | tween = new Tween();
10 | tweens = [
11 | (t)=>{return tween.powerInOut(t, 2)},
12 | (t)=>{return tween.powerInOut(t, 4)},
13 | (t)=>{return tween.linear(t)}
14 | ]
15 | }
16 |
17 | function draw() {
18 | clear();
19 | background(240, 240, 30);
20 |
21 | const t = msec / duration;
22 |
23 | const hw = width / 2;
24 | const hh = height / 2;
25 | const p0 = createVector(-160, -160);
26 | const p1 = createVector(80, -80);
27 | const p2 = createVector(160, 160);
28 | let p0_1 = p0.copy().lerp(p1, tweens[0](t));
29 | let p1_2 = p1.copy().lerp(p2, tweens[1](t));
30 | let p = p0_1.copy().lerp(p1_2, tweens[2](t));
31 | plotData.push(p);
32 |
33 | push();
34 | translate(hw, hh);
35 | noFill(); stroke(0);
36 | line(p0.x, p0.y, p1.x, p1.y);
37 | line(p1.x, p1.y, p2.x, p2.y);
38 | line(p0_1.x, p0_1.y, p1_2.x, p1_2.y);
39 |
40 | for (let i = 1; i < plotData.length; i ++) {
41 | line(plotData[i - 1].x, plotData[i - 1].y, plotData[i].x, plotData[i].y);
42 | }
43 |
44 | fill(0); noStroke();
45 | drawCircleMarker(p0, 4);
46 | drawCircleMarker(p1, 4);
47 | drawCircleMarker(p2, 4);
48 | fill(255); stroke(0);
49 | drawCircleMarker(p0_1, 4);
50 | drawCircleMarker(p1_2, 4);
51 | drawCircleMarker(p, 4);
52 |
53 |
54 | pop();
55 | ellapseTime();
56 | }
57 |
58 | function ellapseTime() {
59 | if (msec > duration) {
60 | msec = 0;
61 | plotData = [];
62 | } else {
63 | msec += min(100, window.performance.now() - prevNow);
64 | }
65 | prevNow = window.performance.now();
66 | }
67 |
68 | /** drawCircleMarker **/
69 |
70 | /** Tween **/
71 |
--------------------------------------------------------------------------------
/js/examples/collision/collision_rectangles.js:
--------------------------------------------------------------------------------
1 | let A, B;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 |
6 | A = {x: 0, y: 0, w: 160, h: 90};
7 | B = {x: 0, y: 0, w: 90, h: 160};
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(249, 246, 236);
13 | let t = radians(frameCount) / 2;
14 | A.x = cos(t) * 120 - A.w / 2;
15 | A.y = sin(t * 2) * 120 - A.h / 2;
16 | B.x = -cos(t * 3) * 120 - B.w / 2;
17 | B.y = -sin(t * 4) * 120 - B.h / 2;
18 |
19 | // test
20 |
21 | let xResult = A.x <= B.x + B.w && A.x + A.w >= B.x;
22 | let yResult = A.y <= B.y + B.h && A.h + A.y >= B.y;
23 | let result = xResult && yResult;
24 |
25 | // rendering
26 |
27 | push();
28 | translate(width / 2, height / 2);
29 |
30 | noStroke();
31 | if (result) {
32 | fill(225, 81, 106);
33 | } else {
34 | fill(255);
35 | }
36 | rect(A.x, A.y, A.w, A.h);
37 | rect(B.x, B.y, B.w, B.h);
38 |
39 | noFill(); stroke(0); strokeWeight(1);
40 | rect(A.x, A.y, A.w, A.h);
41 | rect(B.x, B.y, B.w, B.h);
42 |
43 | fill(0); strokeWeight(1);
44 | let l0 = -width / 2, l1 = l0 + 16;
45 | let b0 = height / 2, b1 = b0 - 16;
46 |
47 | line(-width / 2, b1, width / 2, b1);
48 | line(l1, -height / 2, l1, height / 2);
49 |
50 | stroke(0, 0, 0, 32);
51 | line(A.x, A.y, A.x, b0);
52 | line(A.x + A.w, A.y, A.x + A.w, b0);
53 | line(A.x, A.y, l0, A.y);
54 | line(A.x, A.y + A.h, l0, A.y + A.h);
55 |
56 | line(B.x, B.y, l0, B.y);
57 | line(B.x, B.y + B.h, l0, B.y + B.h);
58 | line(B.x, B.y, B.x, b0);
59 | line(B.x + B.w, B.y, B.x + B.w, b0);
60 |
61 | stroke(0);
62 | strokeWeight(3);
63 | if (xResult) {
64 | let sorted = [A.x, B.x + B.w, A.x + A.w, B.x].sort((a,b)=>{return a > b ? 1: -1});
65 | line(sorted[1], b1, sorted[2], b1);
66 | }
67 |
68 | if (yResult) {
69 | let sorted = [A.y, B.y + B.h, A.y + A.h, B.y].sort((a,b)=>{return a > b ? 1: -1});
70 | line(l1, sorted[1], l1, sorted[2]);
71 | }
72 |
73 | pop();
74 | }
75 |
--------------------------------------------------------------------------------
/machines.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Mechanical Movement
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Geometric Machines
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Crank Slider(1)
19 |
20 |
21 |
Crank Slider(2)
22 |
23 |
24 |
Piston
25 |
26 |
27 |
index
28 |
kynd 2019 | Please suggest edits and/or better code at Github
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/js/examples/verlet/verlet_sticks.js:
--------------------------------------------------------------------------------
1 |
2 | let points = [], sticks = [];
3 | let accelIndex, accel;
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 | for (let i = 0; i < 10; i ++) {
8 | points.push(new VerletPoint( createVector(random(width), random(height))) );
9 | points[i].position.add(random2D().mult(random(2) + 1));
10 | }
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(100, 150, 180);
16 | points.forEach((p)=>{
17 | p.update();
18 | if (p.position.x < 0) { p.position.x += 2; }
19 | if (p.position.x > width) { p.position.x -= 2; }
20 | if (p.position.y < 0) { p.position.y += 2; }
21 | if (p.position.y > height) { p.position.y -= 2; }
22 | if (p.getVelocity().mag() > 3) {
23 | p.setVelocity(p.getVelocity().normalize().mult(3)); // limit the speed
24 | }
25 | });
26 |
27 | sticks.forEach((s)=>{
28 | s.update();
29 | });
30 |
31 | let f = (frameCount - 1) % 60;
32 | if (f == 0) {
33 | accelIndex = floor(random(points.length));
34 | accel = random2D().mult((random(0.5) + 0.5));
35 | let idx0, idx1;
36 | do {
37 | idx0 = floor(random(points.length));
38 | idx1 = floor(random(points.length));
39 | } while (idx0 == idx1);
40 |
41 | sticks.push(new VerletStick(points[idx0], points[idx1]));
42 | if (sticks.length > 5) {
43 | sticks.shift();
44 | }
45 | }
46 |
47 | fill(255); stroke(0); strokeWeight(3);
48 | if (f < 30) {
49 | points[accelIndex].position.add(accel);
50 | let p0 = points[accelIndex].position;
51 | let p1 = points[accelIndex].position.copy().add(accel.copy().mult(100));
52 | drawArrow(p0.x, p0.y, p1.x, p1.y);
53 | }
54 |
55 | strokeWeight(1);
56 | sticks.forEach((s)=>{s.draw();});
57 | points.forEach((p)=>{p.draw();});
58 | }
59 |
60 | function random2D() {
61 | return createVector(random(-1, 1), random(-1, 1)).normalize();
62 | }
63 |
64 | /** random2D **/
65 |
66 | /** drawArrow **/
67 |
68 | /** VerletPoint **/
69 |
70 | /** VerletStick **/
71 |
--------------------------------------------------------------------------------
/js/examples/drawings/spinner.js:
--------------------------------------------------------------------------------
1 | let lines = [[],[],[],[],[]];
2 | let sqrt2 = Math.sqrt(2);
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | }
7 |
8 | function draw() {
9 | clear();
10 | background(72, 140, 255);
11 |
12 | let f = frameCount - 1;
13 |
14 | if (f % 180 >= 90) {
15 | for (let i = 0; i < lines.length; i ++) {
16 | lines[i].shift(); lines[i].shift();
17 | }
18 | }
19 |
20 | let theta = (f / 90 - 0.25) * TWO_PI;
21 | let u = min(width, height) / 8;
22 | let c0 = createVector(0, -u * 2);
23 | let c1 = createVector(0, u * 2);
24 | let m = createVector(cos(theta) * u * 3, sin(theta) * u * 3);
25 | let cp0 = (m.copy().sub(c0)).normalize().mult(u).add(c0);
26 | let cp1 = (m.copy().sub(c1)).normalize().mult(u).add(c1);
27 | let mp = createVector(0, constrain(m.y, c0.y, c1.y));
28 |
29 | let sp;
30 | if (m.y < c0.y) {
31 | sp = cp0.copy();
32 | } else if (m.y > c1.y) {
33 | sp = cp1.copy();
34 | } else {
35 | if (m.x < 0) {
36 | sp = createVector(-u, mp.y);
37 | } else {
38 | sp = createVector(u, mp.y);
39 | }
40 | }
41 |
42 | lines[0].push(m);
43 | lines[1].push(cp0);
44 | lines[2].push(cp1);
45 | lines[3].push(mp);
46 | lines[4].push(sp);
47 |
48 | push();
49 | translate(width / 2, height / 2);
50 | rotate((f / 180 - 0.125) * TWO_PI);
51 | noFill(); stroke(0);
52 | for (let i = 0; i < lines.length; i++) {
53 | drawLine(lines[i]);
54 | }
55 | line(m.x, m.y, c0.x, c0.y);
56 | line(m.x, m.y, c1.x, c1.y);
57 | line(m.x, m.y, mp.x, mp.y);
58 | fill(255);
59 | drawCircleMarker(m, 4);
60 | drawCircleMarker(cp0, 4);
61 | drawCircleMarker(cp1, 4);
62 | drawCircleMarker(c0, 4);
63 | drawCircleMarker(c1, 4);
64 | drawCircleMarker(mp, 4);
65 | drawCircleMarker(sp, 4);
66 | pop();
67 | }
68 |
69 | function drawLine(line) {
70 | beginShape();
71 | for (let i = 0; i < line.length; i ++) {
72 | vertex(line[i].x, line[i].y);
73 | }
74 | endShape();
75 | }
76 |
77 | /** drawCircleMarker **/
78 |
--------------------------------------------------------------------------------
/js/examples/math/cross_product.js:
--------------------------------------------------------------------------------
1 | let project = getProjectionFunc(2, 3);
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | }
6 |
7 | function draw() {
8 | clear();
9 | let t = frameCount * 0.005;
10 |
11 | let m = 320; // Magnifier
12 | let x1 = signedNoise(t + 123);
13 | let y1 = signedNoise(t + 234);
14 | let z1 = signedNoise(t + 456);
15 | let x2 = signedNoise(t + 789);
16 | let y2 = signedNoise(t + 890);
17 | let z2 = signedNoise(t + 901);
18 |
19 | let v1 = createVector(x1, y1, z1).normalize();
20 | let v2 = createVector(x2, y2, z2).normalize();
21 | let v3 = v1.cross(v2);
22 | let v4 = v1.cross(v3);
23 |
24 | let p1 = project(v1).mult(m);
25 | let p2 = project(v2).mult(m);
26 | let p3 = project(v3).mult(m);
27 |
28 | let sp0 = project(v1.copy().sub(v4)).mult(m * 1.2);
29 | let sp1 = project(v1.copy().add(v4)).mult(m * 1.2);
30 | let sp2 = project(v1.copy().mult(-1).sub(v4)).mult(m * 1.2);
31 | let sp3 = project(v1.copy().mult(-1).add(v4)).mult(m * 1.2);
32 |
33 | background(245, 177, 217);
34 |
35 | push();
36 | translate(width / 2, height / 2);
37 |
38 | noFill(); stroke(0); strokeWeight(1);
39 | line(sp0.x, sp0.y, sp1.x, sp1.y);
40 | line(sp1.x, sp1.y, sp3.x, sp3.y);
41 | line(sp0.x, sp0.y, sp2.x, sp2.y);
42 | line(sp2.x, sp2.y, sp3.x, sp3.y);
43 | strokeWeight(2);
44 | drawArrow(0, 0, p1.x, p1.y);
45 | drawArrow(0, 0, p2.x, p2.y);
46 | strokeWeight(3);
47 | drawArrow(0, 0, p3.x, p3.y);
48 |
49 |
50 | fill(0); noStroke()
51 | drawLabel(p1.x, p1.y, "v1 [" + v1.x.toPrecision(2) + ", " + v1.y.toPrecision(2) + ", " + v1.z.toPrecision(2) + "]", LEFT);
52 | drawLabel(p2.x, p2.y, "v2 [" + v2.x.toPrecision(2) + ", " + v2.y.toPrecision(2) + ", " + v2.z.toPrecision(2) + "]", LEFT);
53 | drawLabel(p3.x, p3.y, "Cross Product [" + v3.x.toPrecision(2) + ", " + v3.y.toPrecision(2) + ", " + v3.z.toPrecision(2) + "]", LEFT);
54 | pop();
55 | }
56 |
57 | /** signedNoise **/
58 |
59 | /** getProjectionFunc **/
60 |
61 | /** drawArrow **/
62 |
63 | /** drawLabel **/
64 |
--------------------------------------------------------------------------------
/js/examples/physics/acceleration.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 |
4 | counter = 0;
5 | position = createVector(100, -100);
6 | velocity = createVector(48, -48);
7 | acceleration = createVector(30, 30);
8 | fps = 60; // naively assuming 60 fps
9 | maxSpeed = 256;
10 | }
11 |
12 | function draw() {
13 | clear();
14 | const hw = width / 2, hh = height / 2;
15 | const vx = position.x + velocity.x;
16 | const vy = position.y + velocity.y;
17 | const ax = position.x + acceleration.x;
18 | const ay = position.y + acceleration.y;
19 |
20 | background(117, 147, 208);
21 | push();
22 | translate(hw, hh);
23 |
24 | fill(0); stroke(0);
25 | strokeWeight(1);
26 | drawArrow(position.x, position.y, vx, vy);
27 | drawCircleMarker(position, 4);
28 |
29 | strokeWeight(2);
30 | drawArrow(position.x, position.y, ax, ay);
31 |
32 | drawLabel(position.x, position.y, `position (${position.x.toPrecision(4)}, ${position.y.toPrecision(4)})`, LEFT);
33 | drawLabel(vx, vy, `velocity (${velocity.x.toPrecision(4)}, ${velocity.y.toPrecision(4)})`, LEFT);
34 | drawLabel(ax, ay, `acceleration (${acceleration.x.toPrecision(4)}, ${acceleration.y.toPrecision(4)})`, LEFT);
35 |
36 | strokeWeight(1)
37 | line(-hw, 0, hw, 0);
38 | line(0, -hh, 0, hh);
39 | drawLabel(0, -4, "Origin", LEFT);
40 |
41 | pop();
42 |
43 | acceleration = createVector(mouseX - position.x - hw, mouseY - position.y - hh).div(2);
44 | const vDelta = acceleration.copy().div(fps);
45 | velocity.add(vDelta);
46 | if (velocity.mag() > maxSpeed) {
47 | velocity.setMag(maxSpeed)
48 | }
49 | const pDelta = velocity.copy().div(fps);
50 | position.add(pDelta);
51 | if (position.x > hw || position.x < -hw) {velocity.x = -velocity.x;}
52 | if (position.y > hh || position.y < -hh) {velocity.y = -velocity.y;}
53 | }
54 |
55 |
56 | /** drawCircleMarker **/
57 |
58 | /** drawArrow **/
59 |
60 | /** drawLabel **/
61 |
--------------------------------------------------------------------------------
/js/examples/drawings/incenter.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | }
4 |
5 | function draw() {
6 | clear();
7 | background(62, 252, 100);
8 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
9 |
10 | let t = (frameCount % 720) / 720;
11 | let a0 = PI / 3 * cos(t * TWO_PI) + 0.01 + TWO_PI / 3 ;
12 | let a1 = PI / 3 * cos(t * TWO_PI * 3) + 0.02 + TWO_PI / 3 * 2;
13 | let a2 = PI / 3 * cos(t * TWO_PI * 5) + 0.03;
14 |
15 | let p0 = createVector(cos(a0), sin(a0)).mult(120);
16 | let p1 = createVector(cos(a1), sin(a1)).mult(140);
17 | let p2 = createVector(cos(a2), sin(a2)).mult(160);
18 |
19 | let s0 = new LineSegment().fromTwoPoints(p0, p1);
20 | let s1 = new LineSegment().fromTwoPoints(p1, p2);
21 | let s2 = new LineSegment().fromTwoPoints(p2, p0);
22 | let bs0 = getAngleBisection(p0, p1, p2);
23 | let bs1 = getAngleBisection(p1, p2, p0);
24 | let bs2 = getAngleBisection(p2, p0, p1);
25 |
26 | let incenter = bs0.getIntersectionPoint(bs1);
27 | let radius = incenter.dist(s0.getIntersectionPoint(s0.getPerpendicular(incenter)));
28 | let incircle = new Circle().fromCenterAndRadius(incenter, radius);
29 |
30 | push();
31 | translate(width / 2, height / 2);
32 | noFill(); stroke(0); strokeWeight(1);
33 | fill(0); strokeWeight(3);
34 | s0.draw();
35 | s1.draw();
36 | s2.draw();
37 | strokeWeight(1);
38 |
39 | bs0.draw(boundary);
40 | bs1.draw(boundary);
41 | bs2.draw(boundary);
42 |
43 | fill(255);
44 | drawCircleMarker(p0, 3);
45 | drawCircleMarker(p1, 3);
46 | drawCircleMarker(p2, 3);
47 |
48 | if (incenter) {
49 | noFill(); stroke(0); strokeWeight(1);
50 | incircle.draw();
51 | fill(255);
52 | drawCircleMarker(incenter, 4);
53 | }
54 |
55 | pop();
56 | }
57 |
58 | function getAngleBisection(o, p0, p1) {
59 | let a0 = atan2((p0.y - o.y), (p0.x - o.x));
60 | let a1 = atan2((p1.y - o.y), (p1.x - o.x));
61 | return new Line().fromPointAndAngle(o, (a0 + a1) / 2);
62 | }
63 |
64 | /** Line **/
65 |
66 | /** LineSegment **/
67 |
68 | /** Circle **/
69 |
70 | /** drawCircleMarker **/
71 |
--------------------------------------------------------------------------------
/js/examples/drawings/orthocenter.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | }
4 |
5 | function draw() {
6 | clear();
7 | background(62, 252, 100);
8 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
9 |
10 | let t = (frameCount % 720) / 720;
11 | let a0 = PI / 3 * cos(t * TWO_PI) + 0.01 + TWO_PI / 3 ;
12 | let a1 = PI / 3 * cos(t * TWO_PI * 3) + 0.02 + TWO_PI / 3 * 2;
13 | let a2 = PI / 3 * cos(t * TWO_PI * 5) + 0.03;
14 |
15 | let p0 = createVector(cos(a0), sin(a0)).mult(120);
16 | let p1 = createVector(cos(a1), sin(a1)).mult(140);
17 | let p2 = createVector(cos(a2), sin(a2)).mult(160);
18 |
19 | let s0 = new LineSegment().fromTwoPoints(p0, p1);
20 | let s1 = new LineSegment().fromTwoPoints(p1, p2);
21 | let s2 = new LineSegment().fromTwoPoints(p2, p0);
22 |
23 | let pl0 = s0.getPerpendicular(p2);
24 | let pl1 = s1.getPerpendicular(p0);
25 | let pl2 = s2.getPerpendicular(p1);
26 | let l0 = s0.toLine();
27 | let l1 = s1.toLine();
28 | let l2 = s2.toLine();
29 |
30 | let orthocenter = pl0.getIntersectionPoint(pl1);
31 |
32 | push();
33 | translate(width / 2, height / 2);
34 | fill(0); stroke(0); strokeWeight(3);
35 | s0.draw();
36 | s1.draw();
37 | s2.draw();
38 |
39 | strokeWeight(1);
40 | pl0.draw(boundary);
41 | pl1.draw(boundary);
42 | pl2.draw(boundary);
43 |
44 | stroke(0, 0, 0, 30);
45 | l0.draw(boundary);
46 | l1.draw(boundary);
47 | l2.draw(boundary);
48 |
49 | stroke(0); noFill();
50 | drawSquareMark(l0, pl0);
51 | drawSquareMark(l1, pl1);
52 | drawSquareMark(l2, pl2);
53 |
54 | fill(255);
55 | drawCircleMarker(p0, 3);
56 | drawCircleMarker(p1, 3);
57 | drawCircleMarker(p2, 3);
58 | if (orthocenter) {
59 | drawCircleMarker(orthocenter, 4);
60 | }
61 |
62 | pop();
63 | }
64 |
65 | function drawSquareMark(l0, l1) {
66 | let p = l0.getIntersectionPoint(l1);
67 | push();
68 | translate(p.x, p.y);
69 | rotate(l0.getAngle());
70 | rect(0,0,8,8);
71 | pop();
72 | }
73 |
74 | /** Line **/
75 |
76 | /** LineSegment **/
77 |
78 | /** Circle **/
79 |
80 | /** drawCircleMarker **/
81 |
--------------------------------------------------------------------------------
/js/examples/verlet/pendulum.js:
--------------------------------------------------------------------------------
1 |
2 | let points = [], sticks = [];
3 | let accelIndex, accel;
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 | for (let i = 0; i < 10; i ++) {
8 | points.push(new VerletPoint( createVector(i * 16, i * 16)) );
9 | if (i != 0) {
10 | sticks.push(new VerletStick(points[i - 1], points[i]));
11 | }
12 | }
13 | let p0 = points[points.length - 1];
14 | let p1 = new VerletPoint( p0.position.copy().add(createVector(32, 0)) );
15 | let p2 = new VerletPoint( p0.position.copy().add(createVector(32, 32)) );
16 | let p3 = new VerletPoint( p0.position.copy().add(createVector(0, 32)) );
17 | sticks.push(new VerletStick(p0, p1));
18 | sticks.push(new VerletStick(p1, p2));
19 | sticks.push(new VerletStick(p2, p3));
20 | sticks.push(new VerletStick(p3, p0));
21 | sticks.push(new VerletStick(p0, p2));
22 | sticks.push(new VerletStick(p1, p3));
23 | points.push(p1);
24 | points.push(p2);
25 | points.push(p3);
26 | }
27 |
28 | function draw() {
29 | clear();
30 | background(254, 131, 49);
31 | points.forEach((p, i)=>{
32 | p.update();
33 | if (i != 0) {
34 | p.position.y += 1;
35 | }
36 | });
37 |
38 | for (let i = 0; i < 3; i ++) {
39 | sticks.forEach((s)=>{
40 | s.update();
41 | });
42 | points[0].position.x = points[0].position.y = 0;
43 | }
44 |
45 | let f = (frameCount - 1) % 120;
46 | if (f == 0) {
47 | accelIndex = points.length - 2;
48 | accel = createVector((random() < 0.5) ? -random(1,3) : random(1,3), -random(0,3));
49 | }
50 |
51 | push();
52 | translate(width / 2, 0);
53 | fill(255); stroke(0); strokeWeight(3);
54 | if (f > 90) {
55 | points[accelIndex].position.add(accel);
56 | let p0 = points[accelIndex].position;
57 | let p1 = points[accelIndex].position.copy().add(accel.copy().mult(40));
58 | drawArrow(p0.x, p0.y, p1.x, p1.y);
59 | }
60 | strokeWeight(1);
61 | sticks.forEach((s)=>{s.draw();});
62 | //points.forEach((p)=>{p.draw();});
63 | pop();
64 | }
65 |
66 | /** random2D **/
67 |
68 | /** drawArrow **/
69 |
70 | /** VerletPoint **/
71 |
72 | /** VerletStick **/
73 |
--------------------------------------------------------------------------------
/js/examples/drawings/reuleaux.js:
--------------------------------------------------------------------------------
1 | let cLog = [], vLog = [[],[],[]];
2 | function setup() {
3 | canvas = createCanvas(windowWidth, windowHeight);
4 | }
5 |
6 | function draw() {
7 | clear();
8 | background(72, 140, 255);
9 | let t = ((frameCount - 1) % 180) / 180;
10 | if (t == 0) {
11 | cLog = [];
12 | vLog[0] = [];
13 | vLog[1] = [];
14 | vLog[2] = [];
15 | }
16 |
17 | let s = height * 0.8;
18 | let lb = -s / 2;
19 | let rb = s / 2;
20 | let tb = -s / 2;
21 | let bb = s / 2;
22 |
23 | let cos120 = cos(PI / 3 * 2);
24 | let r = sqrt(s * s / (2 * (1 - cos120)));
25 |
26 | let rot = t * TWO_PI / 3 * 4;
27 | let p = [];
28 | let adjX = 0, adjY = 0;
29 | for (let i = 0; i < 3; i ++) {
30 | let a = rot + TWO_PI / 3 * i;
31 | p[i] = createVector(cos(a) * r, sin(a) * r);
32 | if (p[i].x + adjX < lb) {
33 | adjX = lb - p[i].x;
34 | }
35 | if (p[i].x + adjX > rb) {
36 | adjX = rb - p[i].x;
37 | }
38 | if (p[i].y + adjY < tb) {
39 | adjY = tb - p[i].y;
40 | }
41 | if (p[i].y + adjY > bb) {
42 | adjY = bb - p[i].y;
43 | }
44 | }
45 | for (let i = 0; i < 3; i ++) {
46 | p[i].x += adjX;
47 | p[i].y += adjY;
48 | vLog[i].push(p[i]);
49 | }
50 |
51 | push();
52 | translate(width / 2, height / 2);
53 |
54 | noFill(); stroke(0); strokeWeight(1);
55 | rect(lb, tb, s, s);
56 |
57 | fill(255);
58 | let t0 = constrain(t * 8 - 1, 0, 1);
59 | for (let i = 0; i < 3; i ++) {
60 | let i1 = (i + 2) % 3;
61 | let pt = p[i].copy().lerp(p[i1], t0);
62 | line(p[i].x, p[i].y, pt.x, pt.y);
63 | drawCircleMarker(p[i], 4);
64 | }
65 |
66 | noFill();
67 | strokeWeight(3);
68 | let ph = constrain(t * 8 - 2 , 0, 1);
69 | if (ph > 0) {
70 | let a = ph * PI / 3;
71 | drawArc(p[0], p[2], a);
72 | drawArc(p[1], p[0], a);
73 | drawArc(p[2], p[1], a);
74 | }
75 | pop();
76 | }
77 |
78 | function drawArc(p0, p1, a) {
79 | let diameter = p0.dist(p1) * 2;
80 | let angle = atan2(p1.y - p0.y, p1.x - p0.x);
81 | arc(p0.x, p0.y, diameter, diameter, angle - a, angle);
82 | }
83 |
84 | /** drawCircleMarker **/
85 |
--------------------------------------------------------------------------------
/js/examples/physics/gravity.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevInitMsec = 0, prevNow = 0;
2 | let plotMode = -1, plotLabels = ["position(y)", "velocity(y)", "acceleration(y)"], plotStartMsec = 0, plotData = [];
3 | let gravity = 9.8 * 2; // 2px ~= 1m
4 | let apple;
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | apple = new Body(1);
9 | }
10 |
11 | function draw() {
12 | clear();
13 | background(247, 227, 218);
14 |
15 | ellapseTime();
16 |
17 | let minWH = min(width, height);
18 | push();
19 | translate(min((width - minWH) / 2 + 32, width / 4) , 32);
20 | fill(250, 170, 165); stroke(0);
21 | ellipse(0, apple.position.y, 24, 24);
22 | line(0, apple.position.y - 8, 0, apple.position.y - 16);
23 | pop();
24 |
25 | let graphW = minWH - 64;
26 | plotGraph(plotData, (width - graphW) / 2 + 32, 32, graphW, height - 64, 0, 8000, -(height - 64), 0, "time", plotLabels[plotMode]);
27 | }
28 |
29 | function ellapseTime() {
30 | let ellapsedMsec = min(100, window.performance.now() - prevNow);
31 | msec += ellapsedMsec;
32 | let secondsRemaining = ellapsedMsec / 1000;
33 | let maxStepSize = 1 / 60;
34 | while (secondsRemaining > 0) {
35 | let stepSize = secondsRemaining > maxStepSize ? maxStepSize : secondsRemaining;
36 | updateSimulation(stepSize);
37 | secondsRemaining -= maxStepSize;
38 | }
39 |
40 | if (msec > prevInitMsec + 8000) {
41 | apple = new Body(1);
42 | plotData = [];
43 | prevInitMsec += 8000;
44 | }
45 |
46 | if (plotData.length == 0) {
47 | plotStartMsec = msec;
48 | plotMode = (plotMode + 1) % 3;
49 | }
50 |
51 | let protMsec = msec - plotStartMsec;
52 | switch(plotMode) {
53 | case 0: plotData.push({x:protMsec, y: -apple.position.y}); break;
54 | case 1: plotData.push({x:protMsec, y: -apple.velocity.y}); break;
55 | case 2: plotData.push({x:protMsec, y: -getForce(apple).y}); break;
56 | }
57 | }
58 |
59 | function updateSimulation(t) {
60 | apple.applyForce(getForce(apple), t);
61 | apple.update(t);
62 | }
63 |
64 | function getForce(o) {
65 | return createVector(0, gravity).mult(o.mass)
66 | }
67 |
68 | /** plotGraph **/
69 |
70 | /** Body **/
71 |
72 | /** drawCircleMarker **/
73 |
74 | /** drawLabel **/
75 |
--------------------------------------------------------------------------------
/extra/wave_function/index.js:
--------------------------------------------------------------------------------
1 | // -----------------------------------------------------------
2 | let glShader = require('gl-shader');
3 | let glFBO = require("gl-fbo");
4 | let clear = require('gl-clear')({color: [0.5, 0.5, 0.5, 1.0]});
5 | let glslify = require('glslify');
6 | let fillScreen = require("a-big-triangle");
7 | let now = require("gl-now");
8 | // -----------------------------------------------------------
9 |
10 | class glRenderer {
11 | constructor() {
12 | this.shell = now();
13 | this.shell.on("gl-init", this.init.bind(this));
14 | }
15 |
16 | init() {
17 | let gl = this.shell.gl;
18 | //this.shell.on("tick", this.update.bind(this));
19 | this.shell.on("gl-render", this.draw.bind(this));
20 |
21 | this.updateShader = glShader( gl, glslify( './shaders/flat.vert' ), glslify( './shaders/update.frag' ) );
22 | this.renderShader = glShader( gl, glslify( './shaders/flat.vert' ), glslify( './shaders/render.frag' ) );
23 |
24 | let w = 640, h = 640;
25 | this.fbos = [ glFBO(gl, [w,h]), glFBO(gl, [w,h]) ];
26 | this.pingpongIndex = 0;
27 | this.frameCount = 0;
28 |
29 | this.fbos[0].bind();
30 | clear(gl);
31 | this.fbos[1].bind();
32 | clear(gl);
33 | }
34 |
35 | update() {
36 | // NULL
37 | }
38 |
39 | draw() {
40 | // OFF SCREEEN
41 | if (!this.updateShader) return;
42 | let gl = this.shell.gl;
43 |
44 | let prevFbo = this.fbos[this.pingpongIndex];
45 | let currentFbo = this.fbos[this.pingpongIndex ^= 1];
46 |
47 | currentFbo.bind();
48 | this.updateShader.bind();
49 | this.updateShader.uniforms.buffer = prevFbo.color[0].bind(0);
50 | this.updateShader.uniforms.frameCount = this.frameCount;
51 | this.updateShader.uniforms.dims = prevFbo.shape;
52 | fillScreen(gl);
53 | this.frameCount ++;
54 |
55 | // ON SCREEN
56 |
57 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
58 | if (!this.renderShader) return;
59 |
60 | this.renderShader.bind()
61 | this.renderShader.uniforms.buffer =this.fbos[this.pingpongIndex].color[0].bind(0);
62 | this.renderShader.uniforms.dims = [gl.drawingBufferWidth, gl.drawingBufferHeight];
63 | fillScreen(gl);
64 | }
65 | }
66 |
67 | let renderer = new glRenderer();
68 |
--------------------------------------------------------------------------------
/js/examples/drawings/bezier.js:
--------------------------------------------------------------------------------
1 | let log = [];
2 | let pDef = [[-1, 1], [-0.5, -1], [0.5, 1], [1, -1]] ;
3 | let p = [];
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 |
8 | for (let i = 0; i < pDef.length; i ++) {
9 | p.push(createVector(pDef[i][0], pDef[i][1]));
10 | }
11 | }
12 |
13 | function draw() {
14 | clear();
15 | background(15, 243, 208);
16 |
17 | let interval = 30;
18 | let duration = 120;
19 | let len = interval + duration;
20 | let f = frameCount - 1;
21 | if (f % len == 0) { log = []; }
22 | let t = constrain((f % len - interval / 2) / duration, 0, 1);
23 |
24 | fill(0); stroke(0);
25 | let s = createVector(width * 0.3, height * 0.2);
26 |
27 | push();
28 | translate(width / 2, height / 2);
29 |
30 | for (let i = 0; i < p.length; i ++) {
31 | drawCircleMarker(createVector(p[i].x * s.x, p[i].y * s.y), 3);
32 | drawLabel(p[i].x * s.x, p[i].y * s.y + 24, "P" + i);
33 | if (i > 0) {
34 | line(p[i - 1].x * s.x, p[i - 1].y * s.y, p[i].x * s.x, p[i].y * s.y);
35 | }
36 | }
37 |
38 | tp = [];
39 | tp.push(p[0].copy().lerp(p[1], t));
40 | tp.push(p[1].copy().lerp(p[2], t));
41 | tp.push(p[2].copy().lerp(p[3], t));
42 | tp.push(tp[0].copy().lerp(tp[1], t));
43 | tp.push(tp[1].copy().lerp(tp[2], t));
44 | tp.push(tp[3].copy().lerp(tp[4], t));
45 | log.push(tp[5]);
46 |
47 | for (let i = 0; i < tp.length; i ++) {
48 | drawCircleMarker(createVector(tp[i].x * s.x, tp[i].y * s.y), 3);
49 | }
50 |
51 | line(tp[0].x * s.x, tp[0].y * s.y, tp[1].x * s.x, tp[1].y * s.y);
52 | line(tp[1].x * s.x, tp[1].y * s.y, tp[2].x * s.x, tp[2].y * s.y);
53 | line(tp[3].x * s.x, tp[3].y * s.y, tp[4].x * s.x, tp[4].y * s.y);
54 |
55 |
56 | let pt = p[0].copy().mult((1 - t) * (1 - t) * (1 - t))
57 | .add(p[1].copy().mult(3 * (1 - t) * (1 - t) * t))
58 | .add(p[2].copy().mult(3 * (1 - t) * t * t))
59 | .add(p[3].copy().mult(t * t * t));
60 |
61 | noFill();
62 | drawCircleMarker(createVector(pt.x * s.x, pt.y * s.y), 8);
63 |
64 | strokeWeight(2);
65 | beginShape();
66 | for (let i = 0; i < log.length; i ++) {
67 | vertex(log[i].x * s.x, log[i].y * s.y);
68 | }
69 | endShape();
70 |
71 | pop();
72 | }
73 |
74 | /** drawLabel **/
75 |
76 | /** drawCircleMarker **/
77 |
--------------------------------------------------------------------------------
/js/examples/wave/simple_harmonic.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevInitMsec = 0, prevNow = 0;
2 | let plotData = [];
3 | let tention = 1, friction = 0.0;
4 | let ball;
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | ball = new Body(1);
9 | ball.position.y = 100;
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(224, 239, 243);
15 |
16 | ellapseTime();
17 |
18 | push();
19 | translate(32, height / 2);
20 | fill(250, 170, 165); stroke(0);
21 | ellipse(0, ball.position.y, 24, 24);
22 |
23 | noFill(); stroke(0);
24 |
25 | let springEndY = -height / 2;
26 | let len = height / 2 + ball.position.y - 12;
27 | beginShape();
28 | for (let i = 0; i <= 72; i ++) {
29 | let angle = i / 2 * PI;
30 | let x = sin(angle) * 6;
31 | let y = springEndY + len / 72 * i;
32 | vertex(x, y);
33 | }
34 | endShape();
35 | pop();
36 |
37 | let graphW = width - 64;
38 | let graphX = 64;
39 | plotGraph(plotData, graphX, height / 2, graphW, height - 64, 0, 20 * graphW, -height / 2 + 32, height / 2 - 32, "time", "y");
40 | }
41 |
42 | function ellapseTime() {
43 | let ellapsedMsec = min(100, window.performance.now() - prevNow);
44 | msec += ellapsedMsec;
45 | let secondsRemaining = ellapsedMsec / 1000;
46 | let maxStepSize = 1 / 60;
47 | while (secondsRemaining > 0) {
48 | let stepSize = secondsRemaining > maxStepSize ? maxStepSize : secondsRemaining;
49 | updateSimulation(stepSize);
50 | secondsRemaining -= maxStepSize;
51 | }
52 |
53 | if (msec > prevInitMsec + 20 * (width - 64)) {
54 | ball = new Body(1);
55 | ball.position.y = 100;
56 | plotData = [];
57 | prevInitMsec += 20 * (width - 64);
58 | }
59 |
60 | if (plotData.length == 0) {
61 | plotStartMsec = msec;
62 | }
63 |
64 | let plotMsec = (msec - plotStartMsec);
65 | plotData.push({x:plotMsec, y: -ball.position.y});
66 | }
67 |
68 | function updateSimulation(t) {
69 | ball.applyForce(getForce(ball), t);
70 | ball.update(t);
71 | }
72 |
73 | function getForce(o) {
74 | let springForce = o.position.copy().mult(-tention);
75 | let frictionForce = o.velocity.copy().mult(-friction);
76 | return springForce.add(frictionForce);
77 | }
78 |
79 | /** plotGraph **/
80 |
81 | /** Body **/
82 |
83 | /** drawCircleMarker **/
84 |
85 | /** drawLabel **/
86 |
--------------------------------------------------------------------------------
/js/examples/easing/composite02.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | let msec = 0, prevNow = 0;
4 | const duration0 = 900, duration1 = 1200, duration2 = 3000;
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | plotData = [];
9 | tween = new Tween();
10 | console.log(tween.sinInOut)
11 | tweens = [
12 | (t)=>{return recprocate(t, tween.sineInOut)},
13 | (t)=>{return recprocate(t, tween.sineInOut)},
14 | (t)=>{return recprocate(t, tween.sineInOut)}
15 | ]
16 | }
17 |
18 | function draw() {
19 | clear();
20 | background(240, 240, 30);
21 |
22 | const t0 = (msec % duration0) / duration0;
23 | const t1 = (msec % duration1) / duration1;
24 | const t2 = (msec % duration2) / duration2;
25 |
26 | const hw = width / 2;
27 | const hh = height / 2;
28 | const p0 = createVector(-160, -160);
29 | const p1 = createVector(160, -160);
30 | const p2 = createVector(-160, 160);
31 | const p3 = createVector(160, 160);
32 | let p0_1 = p0.copy().lerp(p1, tweens[0](t0));
33 | let p2_3 = p2.copy().lerp(p3, tweens[1](t1));
34 | let p = p0_1.copy().lerp(p2_3, tweens[2](t2));
35 | plotData.push(p);
36 | if (plotData.length > 40) {
37 | plotData.shift();
38 | }
39 |
40 | push();
41 | translate(hw, hh);
42 | noFill(); stroke(0);
43 | line(p0.x, p0.y, p1.x, p1.y);
44 | line(p2.x, p2.y, p3.x, p3.y);
45 | line(p0_1.x, p0_1.y, p2_3.x, p2_3.y);
46 |
47 | for (let i = 1; i < plotData.length; i ++) {
48 | line(plotData[i - 1].x, plotData[i - 1].y, plotData[i].x, plotData[i].y);
49 | }
50 |
51 | fill(0); noStroke();
52 | drawCircleMarker(p0, 4);
53 | drawCircleMarker(p1, 4);
54 | drawCircleMarker(p2, 4);
55 | drawCircleMarker(p3, 4);
56 | fill(255); stroke(0);
57 | drawCircleMarker(p0_1, 4);
58 | drawCircleMarker(p2_3, 4);
59 | drawCircleMarker(p, 4);
60 |
61 | pop();
62 | ellapseTime();
63 | }
64 |
65 |
66 | function recprocate(t, f) {
67 | if (t < 0.5) {
68 | return f(t * 2);
69 | } else {
70 | return 1 - f((t - 0.5) * 2);
71 | }
72 | }
73 |
74 | function ellapseTime() {
75 | msec += min(100, window.performance.now() - prevNow);
76 | prevNow = window.performance.now();
77 | }
78 |
79 | /** drawCircleMarker **/
80 |
81 | /** Tween **/
82 |
--------------------------------------------------------------------------------
/js/examples/drawings/circumcenter.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | }
4 |
5 | function draw() {
6 | clear();
7 | background(62, 252, 100);
8 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
9 |
10 | let t = (frameCount % 720) / 720;
11 | let a0 = PI / 3 * cos(t * TWO_PI) + 0.01 + TWO_PI / 3 ;
12 | let a1 = PI / 3 * cos(t * TWO_PI * 3) + 0.02 + TWO_PI / 3 * 2;
13 | let a2 = PI / 3 * cos(t * TWO_PI * 5) + 0.03;
14 |
15 | let p0 = createVector(cos(a0), sin(a0)).mult(120);
16 | let p1 = createVector(cos(a1), sin(a1)).mult(140);
17 | let p2 = createVector(cos(a2), sin(a2)).mult(160);
18 |
19 | let s0 = new LineSegment().fromTwoPoints(p0, p1);
20 | let s1 = new LineSegment().fromTwoPoints(p1, p2);
21 | let s2 = new LineSegment().fromTwoPoints(p2, p0);
22 |
23 | let mp0 = s0.getMidPoint();
24 | let mp1 = s1.getMidPoint();
25 | let mp2 = s2.getMidPoint();
26 |
27 | let bs0 = s0.getBisection();
28 | let bs1 = s1.getBisection();
29 | let bs2 = s2.getBisection();
30 |
31 | let circumcenter = bs0.getIntersectionPoint(bs1);
32 | let circumcircle = new Circle().fromCenterAndPoint(circumcenter, p0);
33 |
34 | push();
35 | translate(width / 2, height / 2);
36 | fill(0); stroke(0); strokeWeight(3);
37 | s0.draw();
38 | s1.draw();
39 | s2.draw();
40 | strokeWeight(1);
41 |
42 | bs0.draw(boundary);
43 | bs1.draw(boundary);
44 | bs2.draw(boundary);
45 |
46 | noFill();
47 | drawSquareMark(s0.toLine(), bs0);
48 | drawSquareMark(s1.toLine(), bs1);
49 | drawSquareMark(s2.toLine(), bs2);
50 |
51 | fill(255);
52 | drawCircleMarker(mp0, 3);
53 | drawCircleMarker(mp1, 3);
54 | drawCircleMarker(mp2, 3);
55 |
56 | if (circumcenter) {
57 | noFill(); stroke(0); strokeWeight(1);
58 | circumcircle.draw();
59 | fill(255);
60 | drawCircleMarker(circumcenter, 4);
61 | }
62 |
63 | fill(255);
64 | drawCircleMarker(p0, 3);
65 | drawCircleMarker(p1, 3);
66 | drawCircleMarker(p2, 3);
67 |
68 | pop();
69 | }
70 |
71 | function drawSquareMark(l0, l1) {
72 | let p = l0.getIntersectionPoint(l1);
73 | push();
74 | translate(p.x, p.y);
75 | rotate(l0.getAngle());
76 | rect(0,0,8,8);
77 | pop();
78 | }
79 |
80 | /** Line **/
81 |
82 | /** LineSegment **/
83 |
84 | /** Circle **/
85 |
86 | /** drawCircleMarker **/
87 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sketching with Math and Quasi Physics
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Sketching with Math and Quasi Physics
16 |
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Index
19 |
20 | Handy Math
21 | Taming Randomness
22 | Hello Isaac
23 | Distance and Shape
24 | Geometric Drawings
25 | Mechanical Movement
26 | Wave Anatomy
27 | Pitch and Frequency
28 | Easing
29 | Detecting Collision
30 | Path of Light
31 | Building Ragdolls
32 |
33 |
kynd 2019 | Please suggest edits and/or better code at Github
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/js/examples/light_path/reflection.js:
--------------------------------------------------------------------------------
1 | let mirror;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | mirror = new Line();
6 | }
7 |
8 | function reflect(i, n) {
9 | return i.copy().add(n.copy().mult(i.copy().mult(2).dot(n) / pow(n.mag(), 2) * -1));
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(255, 235, 200);
15 | const boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
16 |
17 | const mx = cos(frameCount / 120 * PI + PI * 0.251);
18 | const my = 1;
19 | mirror.fromTwoPoints({x:0, y: 0}, {x: mx, y: my});
20 |
21 | const ty = sin(frameCount / 90 * PI) * height / 4;
22 | const ray = new Line().fromTwoPoints({x: -width / 2, y:0}, {x: 0, y: ty});
23 | const rayVec = createVector(width / 2, ty).normalize();
24 |
25 | const intersection = mirror.getIntersectionPoint(ray);
26 | const normal = createVector(-my, mx);
27 | if (normal.dot(rayVec) > 0) { normal.mult(-1);}
28 | const reflectionVec = reflect(rayVec, normal);
29 |
30 | const rayHead = intersection.copy().add(rayVec.copy().mult(-32));
31 | const rayTail = intersection.copy().add(rayVec.copy().mult(-56));
32 | const normalHead = intersection.copy().add(normal.copy().mult(24));
33 | const reflectionHead = intersection.copy().add(reflectionVec.copy().mult(56));
34 | const reflectionTail = intersection.copy().add(reflectionVec.copy().mult(32));
35 | const reflectionLineEnd = intersection.copy().add(reflectionVec.copy().mult(width));
36 |
37 | push();
38 |
39 | fill(255); stroke(0); strokeWeight(1);
40 | translate(width / 2, height / 2);
41 | line(-width / 2, 0, intersection.x, intersection.y);
42 | line(intersection.x, intersection.y, reflectionLineEnd.x, reflectionLineEnd.y);
43 |
44 | strokeWeight(2);
45 | mirror.draw(boundary);
46 | drawArrow(intersection.x, intersection.y, normalHead.x, normalHead.y);
47 | strokeWeight(4);
48 | drawArrow(rayTail.x, rayTail.y, rayHead.x, rayHead.y);
49 | drawArrow(reflectionTail.x, reflectionTail.y, reflectionHead.x, reflectionHead.y);
50 |
51 | fill(0); noStroke(0);
52 | drawLabel(rayHead.x + rayVec.x * 16, rayHead.y + rayVec. y * 16, "i");
53 | drawLabel(reflectionHead.x + reflectionVec.x * 16, reflectionHead.y + reflectionVec.y * 16, "r");
54 | drawLabel(normalHead.x + normal.x * 16, normalHead.y + normal.y * 16, "n");
55 |
56 | pop();
57 | }
58 |
59 | /** Line **/
60 |
61 | /** drawArrow **/
62 |
63 | /** drawLabel **/
64 |
65 |
--------------------------------------------------------------------------------
/js/examples/sound/equal_temperament.js:
--------------------------------------------------------------------------------
1 | let audioCtx;
2 | let prevClickFrame = -999;
3 | let buffer_size = 16384;
4 | let baseFreq = 440.0;
5 | let pitch = 0;
6 | let gain = 0.1;
7 | let phase = 0;
8 | let labels = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A(Octave)"];
9 |
10 | function setup() {
11 | canvas = createCanvas(windowWidth, windowHeight);
12 | canvas.mousePressed(function() { toggleAudio(); });
13 | canvas.touchStarted(function() { toggleAudio(); });
14 | }
15 |
16 | function draw() {
17 | clear();
18 | background(0, 222, 201);
19 | let freq = Math.pow(2.0, pitch / 12.0) * baseFreq;
20 |
21 | if (frameCount % 100 == 0) {
22 | pitch = (pitch + 1) % 13;
23 | }
24 |
25 | push();
26 | translate(0, height / 2);
27 | noFill(); stroke(0);
28 | beginShape();
29 | for (let i = 0; i <= width; i ++) {
30 | let ph = i / width * freq / 100;
31 | vertex(i, f(ph) * height * 0.3);
32 | }
33 | endShape();
34 | pop();
35 |
36 | stroke(0, 0, 0, 64);
37 | for (let i = 0; i < 10; i ++) {
38 | let x = i * width / 10;
39 | if (i != 0) { line(x, 0, x, height); }
40 | drawLabel(x, height - 16, i + "ms", LEFT);
41 | }
42 |
43 | drawLabel(8, 32, labels[pitch] + " = " + freq.toPrecision(4) + "Hz", LEFT);
44 | drawLabel(width - 8, 32, "Click to turn on/off the sound", RIGHT);
45 | }
46 |
47 | function f(phase) {
48 | return Math.sin(phase * 3.141592 * 2);
49 | }
50 |
51 | function audiohandler(event) {
52 | let outL = event.outputBuffer.getChannelData(0);
53 | let outR = event.outputBuffer.getChannelData(1);
54 | let acc = Math.pow(2.0, pitch / 12.0) * baseFreq / audioCtx.sampleRate;
55 | for(let i = 0 ; i < outL.length; i++) {
56 | phase += acc;
57 | let out = f(phase);
58 | outL[i] = outR[i] = out * gain;
59 | }
60 | }
61 |
62 | function toggleAudio() {
63 | if (prevClickFrame + 10 >= frameCount) {
64 | return;
65 | }
66 | prevClickFrame = frameCount;
67 |
68 | if (audioCtx) {
69 | stopAudio();
70 | } else {
71 | initAudio();
72 | }
73 | }
74 |
75 | function initAudio() {
76 | if (!audioCtx) {
77 | audioCtx = new (window.webkitAudioContext || window.AudioContext);
78 | let scriptproc = audioCtx.createScriptProcessor(buffer_size);
79 | scriptproc.connect(audioCtx.destination);
80 | scriptproc.onaudioprocess = audiohandler;
81 | }
82 | }
83 |
84 | function stopAudio() {
85 | if (audioCtx) {
86 | audioCtx.close();
87 | audioCtx = null;
88 | }
89 | }
90 |
91 | /** drawLabel **/
92 |
--------------------------------------------------------------------------------
/js/examples/easing/tweens.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevNow = 0;
2 | let tween, tweens;
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | tween = new Tween();
6 | tweens = [
7 | {func:tween.linear , label: "linear"},
8 | {func:(t)=>{return tween.powerIn(t,2);} , label: "powerIn(2)"},
9 | {func:(t)=>{return tween.powerOut(t,2);} , label: "powerOut(2)"},
10 | {func:(t)=>{return tween.powerInOut(t,2);} , label: "powerInOut(2)"},
11 | {func:(t)=>{return tween.powerIn(t,3);} , label: "powerIn(3)"},
12 | {func:(t)=>{return tween.powerOut(t,3);} , label: "powerOut(3)"},
13 | {func:(t)=>{return tween.powerInOut(t,3);} , label: "powerInOut(3)"},
14 | {func:tween.sineIn , label: "sineIn"},
15 | {func:tween.sineOut , label: "sineOut"},
16 | {func:tween.circularIn , label: "circularIn"},
17 | {func:tween.circularOut , label: "circularOut"},
18 | {func:tween.circularInOut , label: "circularInOut"},
19 | {func:tween.createCubicBezier({x:0.4, y: 0.0}, {x:0.2, y: 1}), label:"bezier([0.2,0.8],[0.6,0.4])"}
20 | ];
21 |
22 | }
23 |
24 | function draw() {
25 | clear();
26 | background(29, 223, 182);
27 | ellapseTime();
28 |
29 | let duration = 1000, interval = 500;
30 | let t = (msec % (duration + interval) - interval / 2) / duration;
31 | let i = Math.floor(msec / (duration + interval)) % tweens.length;
32 | t = Math.min(1, Math.max(0, t));
33 |
34 | push();
35 | translate(width / 2, height / 2);
36 | plot(0, 0, tweens[i].func, tweens[i].label, t);
37 | pop();
38 | }
39 |
40 | function ellapseTime() {
41 | msec += min(100, window.performance.now() - prevNow);
42 | prevNow = window.performance.now();
43 | }
44 |
45 | function plot(cx, cy, func, label, t) {
46 | let w = height * 0.8, h = height * 0.8;
47 | let ox = -w / 2, oy = h / 2;
48 | let resolution = w / 2;
49 | noFill(); stroke(0);
50 |
51 | beginShape();
52 | for (let i = 0; i <= resolution; i ++) {
53 | let x = i / resolution;
54 | vertex(ox + w * x, oy - h * func(x));
55 | }
56 | endShape();
57 |
58 | let x = ox + w * t, y = oy - h * func(t);
59 | rect(ox, oy - h, w, h);
60 | line(ox, y, ox + w, y);
61 | line(x, oy, x, oy - h);
62 | fill(255); stroke(0);
63 |
64 | drawCircleMarker(createVector(x, y), 4);
65 | fill(0); noStroke(0);
66 | drawLabel(ox, oy + 20, label, LEFT);
67 | drawLabel(ox + w, oy + 20, "t", RIGHT);
68 | drawLabel(ox , oy - h + 16, "f(t)", RIGHT);
69 | }
70 |
71 | /** Tween **/
72 |
73 | /** drawCircleMarker **/
74 |
75 | /** drawLabel **/
76 |
--------------------------------------------------------------------------------
/js/examples/sound/just_intonation.js:
--------------------------------------------------------------------------------
1 | let audioCtx;
2 | let prevClickFrame = -999;
3 | let buffer_size = 16384;
4 | let baseFreq = 440.0;
5 | let note = 0;
6 | let gain = 0.1;
7 | let phase = 0;
8 | let ratios = [1, 9/8, 5/4, 4/3, 3/2, 5/3, 15/8, 2];
9 | let labels = ["A", "B(M2 9/8)", "C#(M3 5/4)", "D(P4 4/3)", "E(P5 3/2)", "F#(M6 5/3)", "G#(M7 15/8)", "A(Octave 2/1)"];
10 |
11 | function setup() {
12 | canvas = createCanvas(windowWidth, windowHeight);
13 | canvas.mousePressed(function() { toggleAudio(); });
14 | canvas.touchStarted(function() { toggleAudio(); });
15 | }
16 |
17 | function draw() {
18 | clear();
19 | background(0, 222, 201);
20 | let freq = ratios[note] * baseFreq;
21 |
22 | if (frameCount % 100 == 0) {
23 | note = (note + 1) % 8;
24 | }
25 |
26 | push();
27 | translate(0, height / 2);
28 | noFill(); stroke(0);
29 | beginShape();
30 | for (let i = 0; i <= width; i ++) {
31 | let ph = i / width * freq / 100;
32 | vertex(i, f(ph) * height * 0.3);
33 | }
34 | endShape();
35 | pop();
36 |
37 | stroke(0, 0, 0, 64);
38 | for (let i = 0; i < 10; i ++) {
39 | let x = i * width / 10;
40 | if (i != 0) { line(x, 0, x, height); }
41 | drawLabel(x, height - 16, i + "ms", LEFT);
42 | }
43 |
44 | drawLabel(8, 32, labels[note] + " = " + freq.toPrecision(4) + "Hz", LEFT);
45 | drawLabel(width - 8, 32, "Click to turn on/off the sound", RIGHT);
46 | }
47 |
48 | function f(phase) {
49 | return Math.sin(phase * 3.141592 * 2);
50 | }
51 |
52 | function audiohandler(event) {
53 | let outL = event.outputBuffer.getChannelData(0);
54 | let outR = event.outputBuffer.getChannelData(1);
55 | let acc = ratios[note] * baseFreq / audioCtx.sampleRate;
56 | for(let i = 0 ; i < outL.length; i++) {
57 | phase += acc;
58 | let out = f(phase);
59 | outL[i] = outR[i] = out * gain;
60 | }
61 | }
62 |
63 | function toggleAudio() {
64 | if (prevClickFrame + 10 >= frameCount) {
65 | return;
66 | }
67 | prevClickFrame = frameCount;
68 |
69 | if (audioCtx) {
70 | stopAudio();
71 | } else {
72 | initAudio();
73 | }
74 | }
75 |
76 | function initAudio() {
77 | if (!audioCtx) {
78 | audioCtx = new (window.webkitAudioContext || window.AudioContext);
79 | let scriptproc = audioCtx.createScriptProcessor(buffer_size);
80 | scriptproc.connect(audioCtx.destination);
81 | scriptproc.onaudioprocess = audiohandler;
82 | }
83 | }
84 |
85 | function stopAudio() {
86 | if (audioCtx) {
87 | audioCtx.close();
88 | audioCtx = null;
89 | }
90 | }
91 |
92 | /** drawLabel **/
93 |
--------------------------------------------------------------------------------
/js/examples/random/random_walk.js:
--------------------------------------------------------------------------------
1 | let walkers = [];
2 |
3 | class RandomWalker {
4 | constructor(x, y, randomFunc, renderFunc, label) {
5 | this.x = x;
6 | this.y = y;
7 | this.label = label;
8 | this.random = randomFunc;
9 | this.render = renderFunc;
10 | this.log = [];
11 | }
12 |
13 | update() {
14 | this.x = constrain(this.x + this.random() * 2, 0, width);
15 | this.y = constrain(this.y + this.random() * 2, 0, height);
16 | this.log.push(createVector(this.x, this.y));
17 | if (this.log.length > 100) {
18 | this.log.shift();
19 | }
20 | }
21 |
22 | draw() {
23 | push();
24 | fill(0); noStroke();
25 | this.render(createVector(this.x, this.y), 8);
26 | drawLabel(this.x + ((this.x < width / 2) ? 8 : -8), this.y + 16,
27 | this.label, (this.x < width / 2) ? LEFT : RIGHT);
28 | noFill(); stroke(0);
29 | beginShape();
30 | for (let i = 0; i < this.log.length; i ++) {
31 | vertex(this.log[i].x, this.log[i].y);
32 | }
33 | endShape();
34 | stroke(0);
35 | line(this.x, 0, this.x, height);
36 | line(0, this.y, width, this.y);
37 | pop();
38 | }
39 | }
40 |
41 | function setup() {
42 | canvas = createCanvas(windowWidth, windowHeight);
43 | walkers.push(new RandomWalker(random(0, width), random(0, height), uniform(), drawCircleMarker, "uniform"));
44 | walkers.push(new RandomWalker(random(0, width), random(0, height), perlin(), drawTriangleMarker, "perlin"));
45 | walkers.push(new RandomWalker(random(0, width), random(0, height), gaussian(), drawSquareMarker, "gaussian"));
46 | walkers.push(new RandomWalker(random(0, width), random(0, height), gaussian_perlin(), drawStarMarker, "gaussian + perlin"));
47 | }
48 |
49 | function draw() {
50 | clear();
51 | background(254, 253, 183);
52 |
53 | let v;
54 | for (let i = 0; i < walkers.length; i ++) {
55 | walkers[i].update();
56 | }
57 |
58 | for (let i = 0; i < walkers.length; i ++) {
59 | walkers[i].draw();
60 | }
61 | }
62 |
63 | function uniform() {
64 | return ()=>{return random(-1, 1);}
65 | }
66 |
67 | function perlin() {
68 | let i = 0, n = random(100);
69 | return ()=>{
70 | n += 0.01;
71 | i = (i + 1) % 2;
72 | return (noise(i + n) - 0.5) * 2;
73 | }
74 | }
75 |
76 | function gaussian() {
77 | return ()=>{return randomGaussian(0,1);}
78 | }
79 |
80 | function gaussian_perlin() {
81 | let g = gaussian();
82 | let p = perlin();
83 | return ()=>{return (g() * 0.2 + p() * 0.8);}
84 | }
85 |
86 | /** drawLabel **/
87 |
88 | /** drawCircleMarker **/
89 |
90 | /** drawSquareMarker **/
91 |
92 | /** drawTriangleMarker **/
93 |
94 | /** drawStarMarker **/
95 |
--------------------------------------------------------------------------------
/easing.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Easing
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Easing
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Tween functions(1)
19 |
20 |
21 |
Tween functions(2)
22 |
23 |
24 |
Learn more
25 |
Robert Penner's Easing Functions
26 |
27 |
Colliding
28 |
29 |
30 |
Bouncing
31 |
32 |
33 |
Composite motion(1)
34 |
35 |
See also
36 |
Bézier Curve
37 |
38 |
Composite motion(2)
39 |
40 |
41 |
Sequenced Actors
42 |
43 |
44 |
index
45 |
kynd 2019 | Please suggest edits and/or better code at Github
46 |
47 |
48 |
49 |
50 |
51 |
52 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/physics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Hello Isaac
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Hello Isaac
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
19 |
Position
20 |
21 |
22 |
Velocity
23 |
24 |
25 |
Acceleration
26 |
27 |
28 |
29 |
Gravity (Force, Acceleration, Velocity, Position)
30 |
31 |
32 |
Orbit
33 |
34 |
35 |
Spring (Tension, Friction)
36 |
37 |
38 |
39 |
Learn more
40 |
41 | The Nature of code - Chapter 1. Vectors
42 |
43 | The Nature of code - Chapter 2. Forces
44 |
index
45 |
kynd 2019 | Please suggest edits and/or better code at Github
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/js/examples/light_path/parabola.js:
--------------------------------------------------------------------------------
1 | let points = [], focusPoint;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | for (let y = -height / 1.8; y < height / 1.8; y += height / 40) {
6 | points.push(createVector(f(y), y));
7 | }
8 | }
9 |
10 | function f(y) {
11 | return -pow(y * 0.1, 2);
12 | }
13 |
14 | function n(y) {
15 | return -2 * y * 0.01;
16 | }
17 |
18 | function reflect(i, n) {
19 | return i.copy().add(n.copy().mult(i.copy().mult(2).dot(n) / pow(n.mag(), 2) * -1));
20 | }
21 |
22 | function draw() {
23 | clear();
24 | background(255, 235, 200);
25 |
26 | const left = - width / 4 * 3;
27 | const boundary = {x: left, y: -height / 2, w: width, h: height};
28 |
29 | const y = ((frameCount % 120) / 120 - 0.5) * height;
30 | const x = f(y);
31 |
32 | const intersection = createVector(x, y);
33 |
34 | const normal = createVector(-1, n(y)).normalize();
35 | const rayVec = createVector(1, 0);
36 | const reflectionVec = reflect(rayVec, normal);
37 |
38 |
39 |
40 |
41 | const rayHead = intersection.copy().add(rayVec.copy().mult(-32));
42 | const rayTail = intersection.copy().add(rayVec.copy().mult(-56));
43 | const normalHead = intersection.copy().add(normal.copy().mult(24));
44 | const reflectionHead = intersection.copy().add(reflectionVec.copy().mult(56));
45 | const reflectionTail = intersection.copy().add(reflectionVec.copy().mult(32));
46 | const reflectionLineEnd = intersection.copy().add(reflectionVec.copy().mult(width));
47 |
48 | const centerLine = new Line().fromTwoPoints({x:0, y:0}, {x:1, y:0});
49 | const reflectionLine = new Line().fromTwoPoints(intersection, intersection.copy().add(reflectionVec));
50 | const focus = centerLine.getIntersectionPoint(reflectionLine);
51 | if (focus) {
52 | focusPoint = focus;
53 | }
54 |
55 | fill(255); stroke(0); strokeWeight(1);
56 | push();
57 | translate(-left, height / 2);
58 | for (let i = 1; i < points.length; i ++) {
59 | line(points[i].x, points[i].y, points[i - 1].x, points[i - 1].y);
60 | }
61 | line(left, y, x, y);
62 | centerLine.draw(boundary);
63 | centerLine.draw(reflectionLine);
64 | line(intersection.x, intersection.y, reflectionLineEnd.x, reflectionLineEnd.y);
65 |
66 | strokeWeight(2);
67 | drawArrow(intersection.x, intersection.y, normalHead.x, normalHead.y);
68 | strokeWeight(4);
69 | drawArrow(rayTail.x, rayTail.y, rayHead.x, rayHead.y);
70 | drawArrow(reflectionTail.x, reflectionTail.y, reflectionHead.x, reflectionHead.y);
71 |
72 | fill(0); noStroke(0);
73 | drawCircleMarker(focusPoint, 4);
74 | pop();
75 | }
76 |
77 | /** Line **/
78 |
79 | /** drawCircleMarker **/
80 |
81 | /** drawArrow **/
82 |
83 | /** drawLabel **/
--------------------------------------------------------------------------------
/js/examples/light_path/refraction.js:
--------------------------------------------------------------------------------
1 | let IOR = 1;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 | }
6 |
7 | function refract(i, n, ior) {
8 | const cosi = -i.copy().dot(n);
9 | const eta = 1 / ior;
10 | const k = 1 - eta * eta * (1 - cosi * cosi);
11 | return t = i.copy().mult(eta).add(
12 | n.copy().mult(eta * cosi - sqrt(k))
13 | );
14 | }
15 |
16 |
17 | function draw() {
18 | clear();
19 | background(255, 235, 200);
20 |
21 | if (frameCount % 60 == 0) {
22 | IOR = 1 + (frameCount % 600) / 600;
23 | }
24 |
25 | const boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
26 |
27 | const mx = cos(frameCount / 120 * PI + PI * 0.251);
28 | const my = 1;
29 | const border = new Line().fromTwoPoints({x:0, y: 0}, {x: mx, y: my});
30 |
31 | const ty = sin(frameCount / 90 * PI) * height / 4;
32 | const ray = new Line().fromTwoPoints({x: -width / 2, y:0}, {x: 0, y: ty});
33 | const rayVec = createVector(width / 2, ty).normalize();
34 |
35 | const intersection = border.getIntersectionPoint(ray);
36 | const normal = createVector(-my, mx).normalize();
37 | if (normal.dot(rayVec) > 0) { normal.mult(-1);}
38 | const refractionVec = refract(rayVec, normal, IOR);
39 |
40 | const rayHead = intersection.copy().add(rayVec.copy().mult(-32));
41 | const rayTail = intersection.copy().add(rayVec.copy().mult(-56));
42 | const normalHead = intersection.copy().add(normal.copy().mult(24));
43 | const refractionHead = intersection.copy().add(refractionVec.copy().mult(56));
44 | const refractionTail = intersection.copy().add(refractionVec.copy().mult(32));
45 | const refractionLineEnd = intersection.copy().add(refractionVec.copy().mult(width));
46 |
47 | push();
48 |
49 | fill(255); stroke(0); strokeWeight(1);
50 | translate(width / 2, height / 2);
51 | line(-width / 2, 0, intersection.x, intersection.y);
52 | line(intersection.x, intersection.y, refractionLineEnd.x, refractionLineEnd.y);
53 |
54 | strokeWeight(2);
55 | border.draw(boundary);
56 | drawArrow(intersection.x, intersection.y, normalHead.x, normalHead.y);
57 | strokeWeight(4);
58 | drawArrow(rayTail.x, rayTail.y, rayHead.x, rayHead.y);
59 | drawArrow(refractionTail.x, refractionTail.y, refractionHead.x, refractionHead.y);
60 |
61 | fill(0); noStroke(0);
62 | drawLabel(rayHead.x + rayVec.x * 16, rayHead.y + rayVec. y * 16, "i");
63 | drawLabel(refractionHead.x + refractionVec.x * 16, refractionHead.y + refractionVec.y * 16, "r");
64 | drawLabel(normalHead.x + normal.x * 16, normalHead.y + normal.y * 16, "n");
65 |
66 | pop();
67 | drawLabel(8, 32, "IOR = " + IOR, LEFT);
68 | }
69 |
70 | /** Line **/
71 |
72 | /** drawArrow **/
73 |
74 | /** drawLabel **/
75 |
76 |
--------------------------------------------------------------------------------
/js/examples/drawings/excenter.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | }
4 |
5 | function draw() {
6 | clear();
7 | background(62, 252, 100);
8 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
9 |
10 | let t = (frameCount % 720) / 720;
11 | let a0 = PI / 3 * cos(t * TWO_PI) + 0.01 + TWO_PI / 3 ;
12 | let a1 = PI / 3 * cos(t * TWO_PI * 3) + 0.02 + TWO_PI / 3 * 2;
13 | let a2 = PI / 3 * cos(t * TWO_PI * 5) + 0.03;
14 |
15 | let p0 = createVector(cos(a0), sin(a0)).mult(60);
16 | let p1 = createVector(cos(a1), sin(a1)).mult(70);
17 | let p2 = createVector(cos(a2), sin(a2)).mult(80);
18 |
19 | let s0 = new LineSegment().fromTwoPoints(p0, p1);
20 | let s1 = new LineSegment().fromTwoPoints(p1, p2);
21 | let s2 = new LineSegment().fromTwoPoints(p2, p0);
22 |
23 | let l0 = s0.toLine();
24 | let l1 = s1.toLine();
25 | let l2 = s2.toLine();
26 |
27 | let bs0 = getExternalAngleBisctor(p0, p1, p2);
28 | let bs1 = getExternalAngleBisctor(p1, p2, p0);
29 | let bs2 = getExternalAngleBisctor(p2, p0, p1);
30 |
31 | let excenters = [];
32 | excenters.push(bs0.getIntersectionPoint(bs1));
33 | excenters.push(bs1.getIntersectionPoint(bs2));
34 | excenters.push(bs2.getIntersectionPoint(bs0));
35 |
36 | let excircles = [];
37 | if (excenters[0]) { excircles.push(getExcircle(excenters[0], l2)); }
38 | if (excenters[1]) { excircles.push(getExcircle(excenters[1], l0)); }
39 | if (excenters[2]) { excircles.push(getExcircle(excenters[2], l1)); }
40 |
41 | push();
42 | translate(width / 2, height / 2);
43 | noFill(); stroke(0); strokeWeight(1);
44 | fill(0); strokeWeight(3);
45 | s0.draw();
46 | s1.draw();
47 | s2.draw();
48 |
49 | strokeWeight(1);
50 | l0.draw(boundary);
51 | l1.draw(boundary);
52 | l2.draw(boundary);
53 |
54 | stroke(0, 0, 0, 30);
55 | bs0.draw(boundary);
56 | bs1.draw(boundary);
57 | bs2.draw(boundary);
58 |
59 | fill(255); stroke(0);
60 | drawCircleMarker(p0, 3);
61 | drawCircleMarker(p1, 3);
62 | drawCircleMarker(p2, 3);
63 |
64 | for (let i = 0; i < 3; i ++) {
65 | if (excenters[i]) {
66 | noFill(); stroke(0); strokeWeight(1);
67 | excircles[i].draw();
68 | fill(255);
69 | drawCircleMarker(excenters[i], 4);
70 | }
71 | }
72 |
73 | pop();
74 | }
75 |
76 | function getExternalAngleBisctor(o, p0, p1) {
77 | let a0 = atan2((o.y - p0.y), (o.x - p0.x));
78 | let a1 = atan2((p1.y - o.y), (p1.x - o.x));
79 | return new Line().fromPointAndAngle(o, (a0 + a1) / 2);
80 | }
81 |
82 | function getExcircle(p, l) {
83 | let radius = p.dist(l.getIntersectionPoint(l.getPerpendicular(p)));
84 | return new Circle().fromCenterAndRadius(p, radius);
85 | }
86 |
87 | /** Line **/
88 |
89 | /** LineSegment **/
90 |
91 | /** Circle **/
92 |
93 | /** drawCircleMarker **/
94 |
--------------------------------------------------------------------------------
/js/examples/physics/orbit.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevInitMsec = 0, prevNow = 0;
2 | let bodies = [];
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | initBodies();
7 | }
8 |
9 | function draw() {
10 | clear();
11 | background(247, 227, 218);
12 |
13 | ellapseTime();
14 |
15 | push();
16 | translate(width / 2, height / 2);
17 | stroke(0);
18 | bodies.forEach((b, i)=>{
19 | noFill();
20 | let step = 4;
21 | for (let i = step; i < b.tail.length; i += step) {
22 | line(b.tail[i].x, b.tail[i].y, b.tail[i - 1].x, b.tail[i - 1].y);
23 | }
24 | });
25 | bodies.forEach((b, i)=>{
26 | if (i == 0) {
27 | fill(250, 170, 165);
28 | } else {
29 | fill(117, 147, 208);
30 | }
31 | let s = pow(b.mass, 1 / 3) * 4;
32 | ellipse(b.position.x, b.position.y, s, s);
33 | });
34 | pop();
35 | }
36 |
37 | function ellapseTime() {
38 | let ellapsedMsec = min(100, window.performance.now() - prevNow);
39 | msec += ellapsedMsec;
40 | let secondsRemaining = ellapsedMsec / 1000;
41 | let maxStepSize = 1 / 60;
42 | while (secondsRemaining > 0) {
43 | let stepSize = secondsRemaining > maxStepSize ? maxStepSize : secondsRemaining;
44 | updateSimulation(stepSize);
45 | secondsRemaining -= maxStepSize;
46 | }
47 |
48 | if (msec > prevInitMsec + 20000) {
49 | initBodies();
50 | prevInitMsec += 20000;
51 | }
52 |
53 | }
54 |
55 | function updateSimulation(t) {
56 | for (let i = 0; i < bodies.length - 1; i ++) {
57 | for (let j = i + 1; j < bodies.length; j ++) {
58 | gravitate(bodies[i], bodies[j], t);
59 | }
60 | }
61 | for (let i = 0; i < bodies.length; i ++) {
62 | bodies[i].update(t);
63 | if (bodies[i].prevPosition.dist(bodies[i].position) > 4) {
64 | bodies[i].tail.push(bodies[i].position.copy());
65 | bodies[i].prevPosition = bodies[i].position.copy();
66 | }
67 | }
68 | }
69 |
70 | function gravitate(o0, o1, t) {
71 | let distance = max(1, o0.position.dist(o1.position) / 10);
72 | let force = o1.position.copy().sub(o0.position).normalize().mult(o0.mass * o1.mass / distance / distance);
73 | o0.applyForce(force, t);
74 | o1.applyForce(force.mult(-1), t);
75 | }
76 |
77 | function initBodies() {
78 | bodies = [];
79 | for (let i = 0; i < 8; i ++) {
80 | let body;
81 | if (i == 0) {
82 | body = new Body(500);
83 | } else {
84 | let angle = random(PI * 2);
85 | let distance = random(100, 200);
86 | let speed = random(10, 30);
87 | body = new Body(random(2,30));
88 | body.position = createVector(cos(angle), sin(angle)).mult(distance);
89 | body.velocity = createVector(-sin(angle), cos(angle)).mult(speed);
90 | }
91 | body.tail = [];
92 | body.prevPosition = body.position.copy();
93 | bodies.push(body);
94 | }
95 | }
96 |
97 | /** Body **/
98 |
--------------------------------------------------------------------------------
/js/examples/easing/bouncing.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevNow = 0;
2 | let tween, bezier, quad;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | tween = new Tween();
7 | bezier = tween.createCubicBezier({x:0.4, y: 0.0}, {x:0.2, y: 1});
8 | quad = (t)=>{return tween.powerOut(t, 2)};
9 | }
10 |
11 | function draw() {
12 | clear();
13 | background(73, 5, 255);
14 | let groundY = height - 24;
15 | let baseSize = 72;
16 | let mt = msec % 1900;
17 |
18 | for (let i = 0; i < 2; i++) {
19 | let x = width / 2 + baseSize * (i * 2 - 1), y = 0, w = baseSize, h = baseSize;
20 | if (mt < 500) {
21 | let t = map(mt, 0, 500, 0, 1);
22 | if (i == 1) {
23 | let r = 1 - tween.powerInOut(t, 2) * 0.2;
24 | w = baseSize / r;
25 | h = baseSize * r;
26 | x += randomGaussian(0, t * 2);
27 | }
28 | y = groundY - h / 2;
29 | } else if (mt < 1000) {
30 | let t = map(mt, 500, 1000, 0, 1);
31 | if (i == 1) {
32 | let r = 1.2 - tween.powerOut(t, 2) * 0.2;
33 | w = baseSize / r;
34 | h = baseSize * r;
35 | }
36 | y = groundY - h / 2 - tween.powerOut(t, 2) * height * 2;
37 | } else if (mt < 1500) {
38 | let t = map(mt, 1000, 1500, 0, 1);
39 | y = groundY - h / 2 - tween.powerOut(1 - t, 2) * height * 2;
40 | } else {
41 | if (i == 0) {
42 | y = groundY - h / 2;
43 | } else if (mt < 1600) {
44 | let t = map(mt, 1500, 1600, 0, 1);
45 | let r = 1 - tween.powerOut(t, 2) * 0.3;
46 | w = baseSize / r;
47 | h = baseSize * r;
48 | y = groundY - h / 2;
49 | } else if (mt < 1750) {
50 | let t = map(mt, 1600, 1750, 0, 1);
51 | let t2 = map(mt, 1600, 1650, 0, 1);
52 | let r = 0.7 + tween.powerOut(t2, 2) * 0.3;
53 | w = baseSize / r;
54 | h = baseSize * r;
55 | y = groundY - h / 2 - tween.powerOut(t, 2) * baseSize;
56 | } else if (mt < 1900) {
57 | let t = map(mt, 1750, 1900, 0, 1);
58 | y = groundY - h / 2 - tween.powerOut(1 - t, 2) * baseSize;
59 | }
60 | }
61 |
62 | fill(255); stroke(0);
63 | ellipse(x, y, w, h);
64 | }
65 |
66 |
67 | noFill(); stroke(0);
68 | drawGround(groundY);
69 | ellapseTime();
70 | }
71 |
72 | function drawGround(groundY) {
73 | let n = Math.ceil(width / 32);
74 | beginShape();
75 | curveVertex(-8, groundY);
76 | for (let i = 0; i <= n; i ++) {
77 | let x = width / n * i;
78 | curveVertex(x, groundY + randomGaussian(0, 1));
79 |
80 | }
81 | curveVertex(width + 8, groundY);
82 | endShape();
83 | }
84 |
85 | function ellapseTime() {
86 | msec += min(100, window.performance.now() - prevNow);
87 | prevNow = window.performance.now();
88 | }
89 |
90 | function drawBox(x, y, size) {
91 | rect(x - size / 2, y - size / 2, size, size);
92 | }
93 |
94 | /** Tween **/
95 |
--------------------------------------------------------------------------------
/light_path.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Light Path
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Path of Light
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Reflection
19 |
$${r=i-\frac{2i\cdot n}{\left\|n\right\|^2}n}$$
20 |
$${i}$$ : vector of the ray to the surface, $${n}$$ : normal of the surface, $${r}$$ : vector of the reflected ray
21 |
22 |
23 |
Parabola
24 |
Parallel rays coming into a parabolic mirror converge at a single focal point
25 |
26 |
27 |
Refraction
28 |
29 |
Learn more
30 |
Scratchapixel 2.0
31 |
32 |
Random Mirrors
33 |
34 |
Learn more
35 |
Scratchapixel 2.0
36 |
37 |
index
38 |
kynd 2019 | Please suggest edits and/or better code at Github
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/js/examples/verlet/ragdoll.js:
--------------------------------------------------------------------------------
1 | let points = [], sticks = [];
2 | let headTarget;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | let u = height / 16;
7 | points.push(new VerletPoint( createVector(0, u * 2)) ); // 0
8 | points.push(new VerletPoint( createVector(-u * 2, u * 3)) ); // 1
9 | points.push(new VerletPoint( createVector(u * 2, u * 3)) ); // 2
10 | points.push(new VerletPoint( createVector(-u * 1.5, u * 8)) ); // 3
11 | points.push(new VerletPoint( createVector(u * 1.5, u * 8)) ); // 4
12 | points.push(new VerletPoint( createVector(-u * 5, u * 3)) ); // 5
13 | points.push(new VerletPoint( createVector(-u * 8, u * 3)) ); // 6
14 | points.push(new VerletPoint( createVector(u * 5, u * 3)) ); // 7
15 | points.push(new VerletPoint( createVector(u * 8, u * 3)) ); // 8
16 | points.push(new VerletPoint( createVector(-u * 1.5, u * 12)) ); // 9
17 | points.push(new VerletPoint( createVector(-u * 1.5, u * 16)) ); // 10
18 | points.push(new VerletPoint( createVector(u * 1.5, u * 12)) ); // 11
19 | points.push(new VerletPoint( createVector(u * 1.5, u * 16)) ); // 12
20 |
21 | sticks.push(new VerletStick(points[0], points[1]));
22 | sticks.push(new VerletStick(points[0], points[2]));
23 | sticks.push(new VerletStick(points[1], points[2]));
24 | sticks.push(new VerletStick(points[1], points[3]));
25 | sticks.push(new VerletStick(points[2], points[4]));
26 | sticks.push(new VerletStick(points[3], points[4]));
27 | sticks.push(new VerletStick(points[1], points[4]));
28 |
29 | sticks.push(new VerletStick(points[1], points[5]));
30 | sticks.push(new VerletStick(points[5], points[6]));
31 | sticks.push(new VerletStick(points[2], points[7]));
32 | sticks.push(new VerletStick(points[7], points[8]));
33 |
34 | sticks.push(new VerletStick(points[3], points[9]));
35 | sticks.push(new VerletStick(points[9], points[10]));
36 | sticks.push(new VerletStick(points[4], points[11]));
37 | sticks.push(new VerletStick(points[11], points[12]));
38 |
39 | }
40 |
41 | function draw() {
42 | clear();
43 | background(254, 131, 49);
44 | points.forEach((p, i)=>{
45 | p.update();
46 | p.position.y += 0.1;
47 | p.position.y = min(p.position.y, height);
48 | });
49 |
50 | for (let i = 0; i < 5; i ++) {
51 | sticks.forEach((s)=>{
52 | s.update();
53 | });
54 | }
55 |
56 | let f = (frameCount - 1) % 60;
57 | if (f == 0) {
58 | let u = height / 16;
59 | headTarget = createVector(random(-u * 4, u * 4), random(u * 2) + u);
60 | }
61 |
62 | if (f < 30) {
63 | points[0].position.add(headTarget.sub(points[0].position).normalize().mult(3));
64 | }
65 |
66 | push();
67 | translate(width / 2, 0);
68 | fill(255); stroke(0); strokeWeight(3);
69 |
70 | strokeWeight(1);
71 | sticks.forEach((s)=>{s.draw();});
72 | //points.forEach((p)=>{p.draw();});
73 | pop();
74 |
75 | var fps = frameRate();
76 | fill(255);
77 | stroke(0);
78 | }
79 |
80 |
81 | /** VerletPoint **/
82 |
83 | /** VerletStick **/
--------------------------------------------------------------------------------
/distance.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Distance and Shape
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Distance and Shape
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Distance function
19 |
A shape can be defined by a function that takes the coordinate of a point and returns the distance to the closest boudary of the shape. This function is called distance function and used as a modeling technique in computer graphics.
20 |
Learn more
21 |
Ray Marching and Signed Distance Functions by Jamie Wong
22 |
The book of shaders - Shaping function by Patricio Gonzalez Vivo & Jen Lowe
23 |
Distance functions by Inigo Quilez
24 |
25 |
Circle
26 |
The size of dots indicate the distance from the boundary of the shape (the smaller the closer). White dots are inside the shape. Black dots are outside.
27 |
28 |
29 |
Rectangle
30 |
31 |
32 |
Rotated rectangle
33 |
34 |
See also
35 |
Rotating 2D points
36 |
37 |
index
38 |
kynd 2019 | Please suggest edits and/or better code at Github
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/js/examples/easing/tweens2.js:
--------------------------------------------------------------------------------
1 | let graphData = [{y:0, msec: -5000}];
2 | let resolution = 80;
3 | let duration = 1000, interval = 500;
4 | let msec = 0, prevNow = 0, prevUpdateMsec = 0;
5 | let tween, tweens;
6 |
7 | function setup() {
8 | canvas = createCanvas(windowWidth, windowHeight);
9 | tween = new Tween();
10 | tweens = [
11 | {func:tween.linear , label: "linear"},
12 | {func:(t)=>{return tween.powerIn(t,2);} , label: "powerIn(2)"},
13 | {func:(t)=>{return tween.powerOut(t,2);} , label: "powerOut(2)"},
14 | {func:(t)=>{return tween.powerInOut(t,2);} , label: "powerInOut(2)"},
15 | {func:(t)=>{return tween.powerIn(t,3);} , label: "powerIn(3)"},
16 | {func:(t)=>{return tween.powerOut(t,3);} , label: "powerOut(3)"},
17 | {func:(t)=>{return tween.powerInOut(t,3);} , label: "powerInOut(3)"},
18 | {func:tween.sineIn , label: "sineIn"},
19 | {func:tween.sineOut , label: "sineOut"},
20 | {func:tween.circularIn , label: "circularIn"},
21 | {func:tween.circularOut , label: "circularOut"},
22 | {func:tween.circularInOut , label: "circularInOut"},
23 | {func:tween.createCubicBezier({x:0.4, y: 0.0}, {x:0.2, y: 1}), label:"bezier([0.2,0.8],[0.6,0.4])"}
24 | ];
25 | }
26 |
27 | function draw() {
28 | clear();
29 | background(29, 223, 182);
30 |
31 | while (msec + duration + interval >= prevUpdateMsec) {
32 | updateGraphData();
33 | }
34 | ellapseTime();
35 |
36 | let s = height * 0.8;
37 | let x = (width + s) / 2, oy = (height + s) / 2;
38 | let y = oy - s * msecToValue(msec);
39 |
40 | noFill(); stroke(0);
41 |
42 | beginShape();
43 | for (let i = 0; i < graphData.length; i ++) {
44 | let vx = x - s * (msec - graphData[i].msec) / duration;
45 | vertex(vx, oy - graphData[i].y * s);
46 | }
47 | endShape();
48 |
49 | fill(255); stroke(0);
50 | drawCircleMarker(createVector(x, y), 4);
51 |
52 | fill(0); noStroke();
53 | drawLabel(width / 2, height / 2, msecToLabel(msec));
54 | }
55 |
56 | function ellapseTime() {
57 | msec += min(100, window.performance.now() - prevNow);
58 | prevNow = window.performance.now();
59 | }
60 |
61 | function msecToValue(msec) {
62 | let t = (msec % (duration + interval)) / duration;
63 | t = Math.min(1, Math.max(0, t));
64 | let i = Math.floor(msec / (duration + interval));
65 | let reverse = i % 2 == 0;
66 | let idx = Math.floor(i / 2) % tweens.length;
67 | return reverse ? tweens[idx].func(t) : (1 - tweens[idx].func(t));
68 | }
69 |
70 | function msecToLabel(msec) {
71 | let idx = Math.floor(Math.floor(msec / (duration + interval)) / 2) % tweens.length;
72 | return tweens[idx].label;
73 | }
74 |
75 | function updateGraphData() {
76 | for (let i = 0; i <= resolution; i ++) {
77 | let dataMsec = prevUpdateMsec + i / resolution * duration;
78 | let y = msecToValue(dataMsec);
79 | graphData.push({msec: dataMsec, y: y});
80 | }
81 | if (graphData.length > resolution * 4) {
82 | graphData = graphData.slice(resolution);
83 | }
84 |
85 | prevUpdateMsec += (duration + interval);
86 | }
87 |
88 | /** Tween **/
89 |
90 | /** drawCircleMarker **/
91 |
92 | /** drawLabel **/
93 |
--------------------------------------------------------------------------------
/js/examples/light_path/mirrors.js:
--------------------------------------------------------------------------------
1 | const maxReflection = 32;
2 | let mirrors;
3 |
4 | function setup() {
5 | canvas = createCanvas(windowWidth, windowHeight);
6 | updateMirrors();
7 | }
8 |
9 | function updateMirrors() {
10 | mirrors = [];
11 | const w = min(width, height);
12 | for (let i = 0; i < 4; i ++) {
13 | p0 = createVector(-w * 0.5 + random() * w, -w * 0.5 + random() * w);
14 | p1 = createVector(-w * 0.5 + random() * w, -w * 0.5 + random() * w);
15 | mirrors.push(new LineSegment().fromTwoPoints(p0, p1));
16 | }
17 | }
18 |
19 | function hitTest(o, d, lineSegments, ignore) {
20 | let intersection, hitObject, minDistance = Infinity;
21 | const ray = new Line().fromPointAndVector(o, d);
22 | lineSegments.forEach((ls)=>{
23 | if (ls != ignore && ls.intersects(ray)) {
24 | const temp = ls.getIntersectionPoint(ray);
25 | const dot = d.dot(temp.copy().sub(o));
26 | const dist = o.dist(temp);
27 | if (dot >= 0 && dist < minDistance) {
28 | intersection = temp;
29 | minDistance = dist;
30 | hitObject = ls;
31 | }
32 | }
33 | });
34 |
35 | return intersection ? {point: intersection, object: hitObject} : null;
36 | }
37 |
38 | function reflect(i, n) {
39 | return i.copy().add(n.copy().mult(i.copy().mult(2).dot(n) / pow(n.mag(), 2) * -1));
40 | }
41 |
42 | function draw() {
43 | clear();
44 | background(255, 235, 200);
45 |
46 | const l = max(width, height);
47 | const angle = frameCount / 60 * PI;
48 | if (frameCount % 120 == 0) { updateMirrors();}
49 |
50 | let origin = createVector(cos(angle), sin(angle)).mult(l);
51 | let dir = origin.copy().mult(-1).normalize();
52 |
53 | const points = [origin];
54 | let currentMirror = null;
55 | for (let i = 0; i < maxReflection; i ++) {
56 | const hitResult = hitTest(origin, dir, mirrors, currentMirror);
57 |
58 | if (hitResult) {
59 | points.push(hitResult.point);
60 | currentMirror = hitResult.object;
61 |
62 | const p0 = hitResult.object.p0;
63 | const p1 = hitResult.object.p1;
64 | normal = createVector(
65 | -(p0.y - p1.y),
66 | p0.x - p1.x
67 | ).normalize();
68 |
69 | normal = (normal.dot(dir) > 0) ? normal.mult(-1) : normal;
70 | origin = hitResult.point;
71 | dir = reflect(dir, normal);
72 | } else {
73 | points.push(origin.copy().add(dir.copy().mult(l * 2)));
74 | break;
75 | }
76 | }
77 |
78 | push();
79 |
80 | translate(width / 2, height / 2);
81 | fill(255); stroke(0); strokeWeight(1);
82 | for (let i = 1; i < points.length; i++) {
83 | line(points[i - 1].x, points[i - 1].y, points[i].x, points[i].y);
84 | }
85 | strokeWeight(3);
86 | mirrors.forEach((m)=>{m.draw();});
87 | fill(0); noStroke(0);
88 | points.forEach((p)=>{drawCircleMarker(p, 4);})
89 | pop();
90 | }
91 |
92 | /** Line **/
93 |
94 | /** LineSegment **/
95 |
96 | /** drawCircleMarker **/
97 |
--------------------------------------------------------------------------------
/js/examples/math/perspective.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | canvas = createCanvas(windowWidth, windowHeight);
3 | }
4 |
5 | function draw() {
6 | clear();
7 | let cx = width / 4 * 3, cy = height / 2;
8 | let cameraZ = -width / 8 * 5;
9 | let planeZ = cameraZ / 2;
10 | let radius = width / 8;
11 | let r0 = radians(frameCount + 45);
12 | let r1 = radians(frameCount + 135);
13 | let r2 = radians(frameCount + 225);
14 | let r3 = radians(frameCount + 315);
15 | let p0 = createVector(0, cos(r0), sin(r0)).mult(radius);
16 | let p1 = createVector(0, cos(r1), sin(r1)).mult(radius);
17 | let p2 = createVector(0, cos(r2), sin(r2)).mult(radius);
18 | let p3 = createVector(0, cos(r3), sin(r3)).mult(radius);
19 |
20 | let pp0 = project(p0, planeZ, cameraZ)
21 | let pp1 = project(p1, planeZ, cameraZ)
22 | let pp2 = project(p2, planeZ, cameraZ)
23 | let pp3 = project(p3, planeZ, cameraZ)
24 |
25 | background(135, 108, 209);
26 |
27 | push();
28 |
29 | fill(0); stroke(0); strokeWeight(1);
30 | translate(cx, cy);
31 | line(p0.z, p0.y, cameraZ, 0);
32 | line(p1.z, p1.y, cameraZ, 0);
33 | line(p2.z, p2.y, cameraZ, 0);
34 | line(p3.z, p3.y, cameraZ, 0);
35 | line(-width / 4 * 3, 0, width / 4, 0);
36 | line(0, -height / 2, 0, height / 2);
37 | line(cameraZ, 0, cameraZ, -height / 3);
38 | line(cameraZ, -height / 4 + 16, planeZ, -height / 4 + 16);
39 | line(p1.z, p1.y, p1.z, -height / 3);
40 | line(cameraZ, -height / 3 + 16, p1.z, -height / 3 + 16);
41 |
42 | strokeWeight(2);
43 | line(p0.z, p0.y, p1.z, p1.y);
44 | line(p1.z, p1.y, p2.z, p2.y);
45 | line(p2.z, p2.y, p3.z, p3.y);
46 | line(p3.z, p3.y, p0.z, p0.y);
47 | line(planeZ, -height / 4, planeZ, height / 4);
48 |
49 | fill(255); stroke(0); strokeWeight(1);
50 | drawCircleMarker(createVector(p1.z, p1.y), 4);
51 | drawCircleMarker(createVector(planeZ, pp1.y), 4);
52 | drawSquareMarker(createVector(cameraZ, 0), 8);
53 |
54 | fill(0); stroke(0); strokeWeight(1);
55 | drawCircleMarker(createVector(p0.z, p0.y), 2);
56 | drawCircleMarker(createVector(p2.z, p2.y), 2);
57 | drawCircleMarker(createVector(p3.z, p3.y), 2);
58 |
59 | drawCircleMarker(createVector(planeZ, pp0.y), 2);
60 | drawCircleMarker(createVector(planeZ, pp2.y), 2);
61 | drawCircleMarker(createVector(planeZ, pp3.y), 2);
62 |
63 |
64 | noStroke(); fill(0);
65 | drawLabel(cameraZ, 24, "camera");
66 | drawLabel(planeZ, height / 4, "image plane", LEFT);
67 | drawLabel(-width / 4 * 3, -12, "z(+)", LEFT);
68 | drawLabel(width / 4, -12, "z(-)", RIGHT);
69 | drawLabel(4, -height / 2 + 16, "y(-)", LEFT);
70 | drawLabel(4, height / 2 - 8, "y(+)", LEFT);
71 | drawLabel(4, 16, "[0, 0]", LEFT);
72 | drawLabel((cameraZ + planeZ) / 2, -height / 4 + 8, "d1");
73 | drawLabel((cameraZ + p1.z) / 2, -height / 3 + 8, "d2");
74 | pop();
75 | }
76 |
77 | function project(v, nearClip, cameraZ) {
78 | let r = abs(cameraZ - nearClip) / abs(cameraZ - v.z);
79 | return createVector(v.x * r, v.y * r);
80 | // Look up for Projection Matrix for more proper 3D projection
81 | // e.g. http://www.songho.ca/opengl/gl_projectionmatrix.html
82 | }
83 |
84 | /** drawCircleMarker **/
85 |
86 | /** drawSquareMarker **/
87 |
88 | /** drawLabel **/
89 |
--------------------------------------------------------------------------------
/js/examples/physics/spring.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevInitMsec = 0, prevNow = 0;
2 | let plotMode = -1, plotLabels = ["position(y)", "velocity(y)", "acceralation(y)"], plotStartMsec = 0, plotData = [];
3 | let paramMode = -1, tention = 1, friction = 0.0;
4 | let ball;
5 |
6 | function setup() {
7 | canvas = createCanvas(windowWidth, windowHeight);
8 | ball = new Body(1);
9 | ball.position.y = 100;
10 | }
11 |
12 | function draw() {
13 | clear();
14 | background(180, 235, 190);
15 |
16 | ellapseTime();
17 |
18 | let minWH = min(width, height);
19 | push();
20 | translate(min((width - minWH) / 2 + 32, width / 4) , height / 2);
21 | fill(250, 170, 165); stroke(0);
22 | ellipse(0, ball.position.y, 24, 24);
23 |
24 | noFill(); stroke(0);
25 |
26 | let springEndY = -height / 2;
27 | let len = height / 2 + ball.position.y - 12;
28 | beginShape();
29 | for (let i = 0; i <= 72; i ++) {
30 | let angle = i / 2 * PI;
31 | let x = sin(angle) * 6;
32 | let y = springEndY + len / 72 * i;
33 | vertex(x, y);
34 | }
35 | endShape();
36 |
37 | pop();
38 |
39 | let graphW = minWH - 64;
40 | let graphX = (width - graphW) / 2 + 32;
41 |
42 | plotGraph(plotData, graphX, height / 2, graphW, height - 64, 0, 10000, -height / 2 + 32, height / 2 - 32, "time", plotLabels[plotMode]);
43 |
44 | drawLabel(graphX + graphW, 40, "tention: " + tention, RIGHT);
45 | drawLabel(graphX + graphW, 56, "friction: " + friction, RIGHT);
46 | }
47 |
48 | function ellapseTime() {
49 | let ellapsedMsec = min(100, window.performance.now() - prevNow);
50 | msec += ellapsedMsec;
51 | let secondsRemaining = ellapsedMsec / 1000;
52 | let maxStepSize = 1 / 60;
53 | while (secondsRemaining > 0) {
54 | let stepSize = secondsRemaining > maxStepSize ? maxStepSize : secondsRemaining;
55 | updateSimulation(stepSize);
56 | secondsRemaining -= maxStepSize;
57 | }
58 |
59 | if (msec > prevInitMsec + 10000) {
60 | ball = new Body(1);
61 | ball.position.y = 100;
62 | plotData = [];
63 | prevInitMsec += 10000;
64 | }
65 |
66 | if (plotData.length == 0) {
67 | plotStartMsec = msec;
68 | plotMode = (plotMode + 1) % 3;
69 |
70 | if (plotMode == 0) {
71 | paramMode = (paramMode + 1) % 3;
72 | switch(paramMode) {
73 | case 0: tention = 1; friction = 0; break;
74 | case 1: tention = 4; friction = 0.5; break;
75 | case 2: tention = 2; friction = 1.5; break;
76 | }
77 | }
78 | }
79 |
80 | let plotMsec = (msec - plotStartMsec);
81 | switch(plotMode) {
82 | case 0: plotData.push({x:plotMsec, y: -ball.position.y}); break;
83 | case 1: plotData.push({x:plotMsec, y: -ball.velocity.y}); break;
84 | case 2: plotData.push({x:plotMsec, y: -getForce(ball).y}); break;
85 | }
86 | }
87 |
88 | function updateSimulation(t) {
89 | ball.applyForce(getForce(ball), t);
90 | ball.update(t);
91 | }
92 |
93 | function getForce(o) {
94 | let springForce = o.position.copy().mult(-tention);
95 | let frictionForce = o.velocity.copy().mult(-friction);
96 | return springForce.add(frictionForce);
97 | }
98 |
99 | /** plotGraph **/
100 |
101 | /** Body **/
102 |
103 | /** drawCircleMarker **/
104 |
105 | /** drawLabel **/
106 |
--------------------------------------------------------------------------------
/verlet.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Building Ragdolls
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Building Ragdolls
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Verlet Points
19 |
Verlet integration is based on the assumption that, without force applied, an object will continue the uniform motion that it previously had. Instead of explcitly maintaining velocity as a variable belongs to the object, the change from the previous position to the current position is used as substitute for the velocity.
20 |
21 |
let v = (random(1) + random(1)) / 2;
22 | update() {
23 | let temp = this.position.copy();
24 | this.position.add(this.getVelocity());
25 | this.prevPosition = temp;
26 | }
27 |
28 | setVelocity(v) {
29 | this.prevPosition = this.position.copy().sub(v);
30 | }
31 |
32 | getVelocity() {
33 | return this.position.copy().sub(this.prevPosition);
34 | }
35 |
36 |
37 |
38 |
Learn more
39 |
Verlet integration
40 |
41 |
Verlet Sticks
42 |
The points can be connected by segments(sticks) that constrain the distances between them
43 |
update() {
44 | let dist = this.pa.position.dist(this.pb.position);
45 | let diff = this.length - dist;
46 | let offset = this.pa.position.copy().sub(this.pb.position).mult(diff / dist / 2);
47 | this.pa.position.add(offset);
48 | this.pb.position.sub(offset);
49 | }
50 |
51 |
52 |
53 |
Pendulum
54 |
55 |
56 |
Ragdoll
57 |
58 |
59 |
Ragdoll 3D
60 |
61 |
62 |
index
63 |
kynd 2019 | Please suggest edits and/or better code at Github
64 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/js/examples/drawings/bspline.js:
--------------------------------------------------------------------------------
1 | let log = [];
2 | let b = [];
3 | let resolution = 50;
4 | let n = 2;
5 | let knots = [0, 0, 0, 1, 2, 3, 3, 3];
6 | let pDef = [[-1, 1], [-0.5, -1], [0, 1], [0.5, -1], [1, 1]];
7 | let p = [];
8 | let tmin = 0;
9 | let tmax = 3;
10 |
11 | function setup() {
12 | canvas = createCanvas(windowWidth, windowHeight);
13 |
14 | for (let i = 0; i < pDef.length; i ++) {
15 | p.push(createVector(pDef[i][0], pDef[i][1]));
16 | }
17 |
18 | for (let i = 0; i < p.length; i ++) {
19 | b.push([]);
20 | for (let j = tmin; j <= tmax * resolution; j += 1) {
21 | let x = j / resolution;
22 | if (x >= tmax) { x = tmax - 0.00001; }
23 | b[i].push(bN(i, n, x));
24 | }
25 | }
26 | }
27 |
28 | function draw() {
29 | clear();
30 | background(15, 243, 208);
31 |
32 | let interval = 30;
33 | let len = b[0].length + interval;
34 | let f = frameCount - 1;
35 | if (f % len == 0) { log = []; }
36 | let idx = constrain(f % len - interval / 2, 0, b[0].length - 1);
37 |
38 | drawGraph(idx);
39 | drawCurve(idx);
40 | }
41 |
42 | function drawGraph(idx) {
43 | noFill(); stroke(0);
44 | let w = width * 0.6, h = height * 0.2;
45 | let x = (width - w) / 2, y = height - 32;
46 |
47 | push();
48 | translate(x, y);
49 | for (let i = 0; i < b.length; i ++) {
50 | beginShape();
51 | for (let j = 0; j < b[i].length; j ++) {
52 | let v = b[i][j];
53 | vertex(j / resolution * w / tmax, -v * h);
54 | }
55 | endShape();
56 | }
57 | line(idx / resolution * w / tmax, 0, idx / resolution * w / tmax, -h);
58 |
59 | fill(0);
60 | for (let i = 0; i < b.length; i ++) {
61 | let v = b[i][idx];
62 | drawCircleMarker(createVector(idx / resolution * w / tmax, -v * h), 2);
63 | }
64 |
65 | for (let i = 0; i <= tmax; i ++) {
66 | drawCircleMarker(createVector(i * w / tmax, 0), 2);
67 |
68 | drawLabel(i * w / tmax, 16, "x = " + i);
69 | }
70 |
71 | drawLabel(0, -h - 8, "B i,n(x)");
72 | pop();
73 | }
74 |
75 |
76 | function drawCurve(idx) {
77 | fill(0); stroke(0);
78 | let s = createVector(width * 0.4, height * 0.2); // scale
79 |
80 | push();
81 | translate(width / 2, height / 3 * 1);
82 |
83 | for (let i = 0; i < p.length; i ++) {
84 | drawCircleMarker(createVector(p[i].x * s.x, p[i].y * s.y), 3);
85 | drawLabel(p[i].x * s.x, p[i].y * s.y + 24, "P" + i);
86 | if (i > 0) {
87 | line(p[i - 1].x * s.x, p[i - 1].y * s.y, p[i].x * s.x, p[i].y * s.y);
88 | }
89 | }
90 |
91 | let pt = createVector();
92 | let v = [];
93 | for (let i = 0; i < p.length; i ++) {
94 | v.push(b[i][idx]);
95 | pt.add(p[i].copy().mult(v[i]))
96 | }
97 |
98 | drawCircleMarker(createVector(pt.x * s.x, pt.y * s.y), 4);
99 | log.push(pt);
100 | for (let i = 0; i < p.length; i ++) {
101 | stroke(0, 0, 0, v[i] * 255);
102 | line(pt.x * s.x, pt.y * s.y, p[i].x * s.x, p[i].y * s.y);
103 | }
104 |
105 | noFill(); stroke(1); strokeWeight(2);
106 | beginShape();
107 | for (let i = 0; i < log.length; i ++) {
108 | vertex(log[i].x * s.x, log[i].y * s.y);
109 | }
110 | endShape();
111 |
112 | pop();
113 | }
114 |
115 |
116 | function bN(i, k, x){
117 | let w1 = 0, w2 = 0;
118 | if(k == 0){
119 | if (x >= knots[i] && x < knots[i + 1]) {
120 | return 1;
121 | } else {
122 | return 0;
123 | }
124 | } else {
125 | if ((knots[i + k] - knots[i]) != 0 ){
126 | w1 = ((x - knots[i]) / (knots[i + k] - knots[i])) * bN(i, k - 1, x);
127 | }
128 |
129 | if ((knots[i + k + 1] - knots[i + 1]) != 0) {
130 | w2 = ((knots[i + k + 1] - x) / (knots[i + k + 1] - knots[i + 1])) * bN(i + 1, k - 1, x);
131 | }
132 | return w1 + w2;
133 | }
134 | }
135 |
136 | /** drawLabel **/
137 |
138 | /** drawCircleMarker **/
139 |
--------------------------------------------------------------------------------
/pitch.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Pitch and Frequency
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Pitch and Frequency
15 |
Sketching with Math and Quasi Physics
16 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
17 |
Sound is vibration transmitted through a medium, i.e. a solid, liquid or gas. A high pitch sound corresponds to a high frequency sound wave and a low pitch sound corresponds to a low frequency sound wave. The frequency is most often measured in hertz(Hz) . One hertz means that an event repeats once per second, in case of wave, one cycle per second.
18 |
19 |
Twelve Tone Equal Temperament
20 |
21 |
Twelve-tone equal temperament divides the octave into 12 equal parts(semitones). The frequency ratio of two adjacent notes is the twelfth root of two:
22 | \(12\sqrt2=2^{1⁄12}\approx1.059463\) .
23 | The frequency \(f\) of the nth key on a piano is
24 |
25 |
$$f(n)=2^\frac{n-49}{12}\times(A=440Hz)$$
26 |
27 |
* While A=440Hz is widely used and accepted as standard, slightly different frequencies are used in some cases. See Concert pitch(Wikipedia) for reference.
28 |
29 |
30 |
31 |
Just Intonation
32 |
33 |
In just intonation, the frequencies of notes are defined by ratios of small whole numbers, e.g.
34 |
Major 2nd: \(\frac98\) (= \(\frac32\times\frac32\times\frac12\) = an octave below the perfect 5th of the perfect 5th)
35 |
Major 3rd: \(\frac54\)
36 |
Perfect 4th: \(\frac43\) (= \(\frac21/\frac32\) = perfect 5th below the octave)
37 |
Perfect 5th: \(\frac32\)
38 |
Major 6th: \(\frac53\) (= \(\frac54\times\frac43\) = the perfect 4th of the major 3rd)
39 |
Major 7th: \(\frac{15}8\) (= \(\frac54\times\frac32\) = the perfect 5th of the major 3rd)
40 |
Octave: \(\frac21\)
41 |
42 |
43 |
44 |
index
45 |
kynd 2019 | Please suggest edits and/or better code at Github
46 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | .note-latest {
2 | background-color: #FFFF9F;
3 | padding: 16px 24px 16px 24px;
4 | display: inline-block;
5 | border-radius: 8px;
6 | font-weight: 900;
7 | }
8 |
9 | body { margin:0; padding: 0; font-family: 'Open Sans', sans-serif; }
10 | #header {width: 100%; }
11 | #main { max-width:960px; margin: 0 auto 0 auto; }
12 | .example { width:100%; height: 540px;; margin: 0; padding:0; }
13 | .example iframe {width: 100%; height: 540px; margin: 0; padding:0; border: none; }
14 | #main .example { width:100%; height: 400px; }
15 | #main .example iframe {width: 100%; height: 400px; }
16 |
17 | h1 { font-family: 'Fredericka the Great', cursive; font-weight: normal; font-size: 4em;
18 | line-height: 1.5em; margin: 32px 0px 0px 0px; padding: 0; }
19 |
20 | h2 { font-family: 'Amatic SC', cursive; font-weight: bold; font-size: 2em; line-height: 1.5em;
21 | margin: 64px 0px 12px 0px; padding: 0; }
22 |
23 | h3 {font-family: 'Open Sans', sans-serif; font-weight: bold; font-size: 1em;
24 | line-height: 1.5em; margin: 24px 0px 12px 0px; padding: 0; }
25 |
26 | p {font-size: 1em; line-height: 1.7em; font-family: 'Open Sans', sans-serif;
27 | font-weight: 300; color: #222222; margin: 24px 0px 24px 0px; }
28 |
29 | dt, dd {font-size: 0.9em; line-height: 1.7em; font-family: 'Open Sans', sans-serif;
30 | font-weight: 300; color: #222222; }
31 |
32 | a { color: #024997; text-decoration: none; border-bottom: dotted 1px #024997; padding: 2px; }
33 |
34 | a:hover { color: #2962ff; border-bottom: dashed 1px #2962ff; }
35 |
36 | li { margin: 4px 0 8px 0; }
37 | .example-footer { display: flex; flex-direction: row; flex-wrap: wrap;
38 | margin: 8px 0px 12px 0px;
39 | }
40 |
41 | .example-footer .note { display: block; flex-grow: 1; flex-shrink: 1;
42 | vertical-align: middle; font-size: 0.7em; line-height: 1.2em; color: #888888;
43 | margin: 4px 0px 4px 0px; }
44 |
45 | .button-container { flex-grow: 1; flex-shrink: 1; text-align: right; }
46 |
47 | a.button { display: inline-block; line-height: 1.5em; font-size: 1.3em;
48 | font-weight: bold; text-align:right; font-family: 'Amatic SC', cursive;
49 | white-space: nowrap; min-width: 80px; text-align: center;
50 | margin: 4px 0px 0px 8px; }
51 |
52 | a.button { border: dashed 1px #024997;
53 | border-radius: 4px; padding: 2px 4px 2px 4px; }
54 |
55 | a.button:hover { border: dashed 1px #2962ff; }
56 |
57 | a.button:first-child { margin-left: 0; }
58 |
59 |
60 |
61 | .hidden { display: none; }
62 |
63 | #index { margin-left: 32px; list-style-type: upper-roman; }
64 |
65 | #index a { border: none; font-family: 'Open Sans', sans-serif;
66 | font-weight: 300; font-size: 1.2em; color: #222222; }
67 |
68 | #index li { padding: 8px 24px 8px 32px; }
69 |
70 | #index li.disabled, #index li.disabled a { color: #AAAAAA; }
71 |
72 | .code-block { border-top: dashed 1px #eeeeee; border-bottom: dashed 1px #eeeeee; }
73 |
74 | code { font-family: 'Roboto Mono', cursive; line-height: 1.7em; font-size: 0.8em;
75 | margin: 24px 0px 24px 0px; }
76 |
77 | div.math-wrapper { overflow:auto; }
78 |
79 | div.math-wrapper p { display: inline-block; margin: 0px 16px 24px 16px; }
80 |
81 | span.math-wrapper { display: inline-block; margin: 0 4px 0 4px; }
82 |
83 | footer { font-size: 0.8em; line-height: 1.5em; text-align:right;
84 | font-family: 'Open Sans', sans-serif; font-weight: 300;
85 | margin:64px 0px 24px 0px; padding-top: 12px; border-top: solid 1px #DDDDDD; }
86 |
87 | .row {
88 | display: flex;
89 | flex-direction: row;
90 | }
91 |
92 | .row div:first-child {
93 | flex: 1 1;
94 | }
95 |
96 | .row div {
97 | flex: 3 3;
98 | }
99 |
100 | .index-link {
101 | margin-top: 64px;
102 | }
103 |
104 | @media (max-width: 540px) {
105 | .example {height: 400px; }
106 | .example iframe { height: 400px; }
107 | }
108 |
109 | @media (max-width: 960px) {
110 | h1, h2, h3, p, pre, footer, dl, div.example-footer {
111 | padding-left: 16px; padding-right: 16px; }
112 | .math p { font-size: 0.8em; }
113 | }
114 |
--------------------------------------------------------------------------------
/random.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Taming Randomness
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Taming Randomness
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Uniform Random
19 |
let v = random(1)
20 |
21 |
22 |
23 |
Random2
24 |
let v = pow(random(1), 2)
25 |
26 |
27 |
Randomn
28 |
let v = pow(random(1), n)
29 |
30 |
31 |
(Random + Random) / 2
32 |
let v = (random(1) + random(1)) / 2;
33 |
34 |
35 |
(Random1 + Random2 + ... + Randomn ) / n
36 |
let v = 0;
37 | for (let i = 0; i < n; i ++) {
38 | v += random(1);
39 | }
40 | v /= n;
41 |
42 |
43 |
44 |
Normal Distribution(Gaussian)
45 |
// Box-Muller Transform (Unif(0,1) => N(0,1))
46 | // avoiding log(0) by using (1 - random(1))
47 | let mean = 0.5, variance = 0.1;
48 | let v = sqrt(-2 * log(1 - random(1))) * cos(2 * Math.PI * Math.random(1)) * variance + mean;
49 |
50 |
note: randomGaussian() is available in p5.js
51 |
52 |
53 |
Perin Noise
54 |
Distribution
55 |
let v = noise(x); x += 0.001;
56 |
57 |
see implementation of noise() function in p5.js
58 |
59 |
60 |
Variation over time
61 |
let v = noise(x); x += 0.01;
62 |
63 |
64 |
65 |
Random Walkers
66 |
67 |
68 |
index
69 |
kynd 2019 | Please suggest edits and/or better code at Github
70 |
71 |
72 |
73 |
74 |
75 |
76 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/js/examples/verlet/ragdoll3d.js:
--------------------------------------------------------------------------------
1 | let project;
2 | let points = [], sticks = [];
3 | let headTarget;
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 |
8 | project = getProjectionFunc(height / 3 * 2, height, 2);
9 | let u = height / 16;
10 | points.push(new VerletPoint( createVector(0, u * 2 - u * 8)) ); // 0
11 | points.push(new VerletPoint( createVector(-u * 2, u * 3 - u * 8)) ); // 1
12 | points.push(new VerletPoint( createVector(u * 2, u * 3 - u * 8)) ); // 2
13 | points.push(new VerletPoint( createVector(-u * 1.5, u * 8 - u * 8)) ); // 3
14 | points.push(new VerletPoint( createVector(u * 1.5, u * 8 - u * 8)) ); // 4
15 | points.push(new VerletPoint( createVector(-u * 5, u * 3 - u * 8)) ); // 5
16 | points.push(new VerletPoint( createVector(-u * 8, u * 3 - u * 8)) ); // 6
17 | points.push(new VerletPoint( createVector(u * 5, u * 3 - u * 8)) ); // 7
18 | points.push(new VerletPoint( createVector(u * 8, u * 3 - u * 8)) ); // 8
19 | points.push(new VerletPoint( createVector(-u * 1.5, u * 12 - u * 8)) ); // 9
20 | points.push(new VerletPoint( createVector(-u * 1.5, u * 16 - u * 8)) ); // 10
21 | points.push(new VerletPoint( createVector(u * 1.5, u * 12 - u * 8)) ); // 11
22 | points.push(new VerletPoint( createVector(u * 1.5, u * 16 - u * 8)) ); // 12
23 |
24 | sticks.push(new VerletStick(points[0], points[1]));
25 | sticks.push(new VerletStick(points[0], points[2]));
26 | sticks.push(new VerletStick(points[1], points[2]));
27 | sticks.push(new VerletStick(points[1], points[3]));
28 | sticks.push(new VerletStick(points[2], points[4]));
29 | sticks.push(new VerletStick(points[3], points[4]));
30 | sticks.push(new VerletStick(points[1], points[4]));
31 | sticks.push(new VerletStick(points[2], points[3]));
32 |
33 | sticks.push(new VerletStick(points[1], points[5]));
34 | sticks.push(new VerletStick(points[5], points[6]));
35 | sticks.push(new VerletStick(points[2], points[7]));
36 | sticks.push(new VerletStick(points[7], points[8]));
37 |
38 | sticks.push(new VerletStick(points[3], points[9]));
39 | sticks.push(new VerletStick(points[9], points[10]));
40 | sticks.push(new VerletStick(points[4], points[11]));
41 | sticks.push(new VerletStick(points[11], points[12]));
42 |
43 | }
44 |
45 | function draw() {
46 | clear();
47 | background(254, 131, 49);
48 | points.forEach((p, i)=>{
49 | p.update();
50 | p.position.y += 0.1;
51 | p.position.y = min(p.position.y, height / 2);
52 | });
53 |
54 | for (let i = 0; i < 2; i ++) {
55 | sticks.forEach((s)=>{
56 | s.update();
57 | });
58 | }
59 |
60 | let f = (frameCount - 1) % 60;
61 | if (f == 0) {
62 | let u = height / 16;
63 | headTarget = createVector(random(-u * 4, u * 4), random(u * 2) - u * 8, random(-u , u));
64 | }
65 |
66 | if (f < 30) {
67 | points[0].position.add(headTarget.sub(points[0].position).normalize().mult(4));
68 | }
69 |
70 | push();
71 | translate(width / 2, height / 2);
72 | fill(255); stroke(0); strokeWeight(3);
73 |
74 | strokeWeight(1);
75 | points.forEach((p)=>{
76 | p.screenPos = project(p.position);
77 | });
78 |
79 | sticks.forEach((s)=>{
80 | let p0 = s.pa.screenPos;
81 | let p1 = s.pb.screenPos;
82 | line(p0.x, p0.y, p1.x, p1. y);
83 | });
84 |
85 |
86 | //points.forEach((p)=>{drawCircleMarker(p.screenPos, 4);});
87 |
88 | pop();
89 | }
90 |
91 | function drawCircleMarker(p, size) {
92 | ellipse(p.x, p.y, size * 2, size * 2);
93 | }
94 |
95 | function getProjectionFunc(n, z, m = 1) {
96 | let nearClip = n;
97 | let cameraZ = z;
98 | let multiplier = m;
99 | return (v)=>{
100 | let r = abs(cameraZ - nearClip) / abs(cameraZ - v.z) * multiplier;
101 | return createVector(v.x * r, v.y * r);
102 | }
103 | // Look up for Projection Matrix for more proper 3D projection
104 | // e.g. http://www.songho.ca/opengl/gl_projectionmatrix.html
105 | }
106 |
107 |
108 | /** VerletPoint **/
109 |
110 | /** VerletStick **/
--------------------------------------------------------------------------------
/js/examples/easing/sequence.js:
--------------------------------------------------------------------------------
1 | let msec = 0, prevNow = 0;
2 | let tween, bezier;
3 | let actors = [];
4 |
5 | function setup() {
6 | canvas = createCanvas(windowWidth, windowHeight);
7 | tween = new Tween();
8 | bezier = tween.createCubicBezier({x:0.4, y: 0.0}, {x:0.2, y: 1});
9 | for (let i = 0; i < 10; i++) {
10 | let o = createVector(width / 2, height / 2);
11 | let d = createVector(randomBool() ? -1: 1, randomBool() ? -1: 1)
12 | let actor = randomBool() ? new ArcActor(o, d) : new LineActor(o, d);
13 | actors.push(actor);
14 | }
15 | }
16 |
17 | function draw() {
18 | clear();
19 | background(255, 60, 0);
20 | ellapseTime();
21 |
22 | push();
23 | noFill(); stroke(0);
24 | for (let i = actors.length - 1; i >= 0; i --) {
25 | actors[i].update();
26 | actors[i].draw();
27 |
28 | if (actors[i].reproductive) {
29 | actors.push(actors[i].reproduce());
30 | actors[i].reproductive = false;
31 | }
32 | if (actors[i].isDone) {
33 | actors.splice(i, 1);
34 | }
35 | }
36 | pop();
37 | }
38 |
39 | function ellapseTime() {
40 | msec += min(100, window.performance.now() - prevNow);
41 | prevNow = window.performance.now();
42 | }
43 |
44 | class Actor {
45 | constructor(o, d) {
46 | if (o.x < 0 || o.x >= width) { o.x = width / 2; }
47 | if (o.y < 0 || o.y >= width) { o.y = height / 2; }
48 | this.origin = o;
49 | this.dir = d.normalize();
50 | this.startMs = msec;
51 | this.duration = randomBool() ? 500 : 1000;
52 | this.reproductive = false;
53 | this.isDone = false;
54 | this.reproduceFlag = false;
55 | }
56 |
57 | update() {
58 | let t = map(msec - this.startMs, 0, this.duration, 0, 1);
59 | this.t0 = t * 1.5;
60 | this.t1 = t * 1.5 - 0.5;
61 | if (this.t0 >= 0.99 && !this.reproduceFlag) {
62 | this.reproductive = this.reproduceFlag = true;
63 | }
64 | if (t >= 0.99) {this.isDone = true; }
65 | }
66 | }
67 |
68 | class ArcActor extends Actor{
69 | constructor(o, d) {
70 | super(o, d);
71 | let rotDir = randomBool() ? -1 : 1;
72 | let size = randomBool() ? 30 : 60;
73 | this.center = o.copy().add(d.copy().rotate(Math.PI / 2 * rotDir).mult(size));
74 | this.angle = Math.floor(Math.random() * 3 + 1) * Math.PI / 2 * rotDir;
75 | this.radius = this.origin.copy().sub(this.center);
76 | }
77 |
78 | reproduce() {
79 | let o = this.getHeadPosition(this.angle);
80 | let d = this.dir.copy().rotate(this.angle);
81 | return randomBool() ? new ArcActor(o, d) : new LineActor(o, d);
82 | }
83 |
84 | getHeadPosition(angle) {
85 | return this.center.copy().add(this.radius.copy().rotate(angle));
86 | }
87 |
88 | draw() {
89 | let a0 = bezier(this.t0) * this.angle;
90 | let a1 = bezier(this.t1) * this.angle;
91 | let aDiff = a1 - a0;
92 | let n = Math.floor(Math.abs(aDiff / 0.1));
93 | beginShape();
94 | for (let i = 0; i <= n; i ++) {
95 | let p = this.getHeadPosition(a0 + aDiff / n * i);
96 | vertex(p.x, p.y);
97 | }
98 | endShape();
99 | }
100 | }
101 |
102 |
103 | class LineActor extends Actor{
104 | constructor(o, d) {
105 | super(o, d);
106 | this.length = randomBool() ? 180 : 120;
107 | }
108 |
109 | reproduce() {
110 | let o = this.getHeadPosition(tween.powerIn(this.t0, 3));
111 | if (randomBool()) {
112 | let d = this.dir.copy().rotate(randomBool() ? -PI / 2 : PI / 2);
113 | return new LineActor(o, d);
114 | } else {
115 | return new ArcActor(o, this.dir.copy());
116 | }
117 | }
118 |
119 | getHeadPosition(t) {
120 | return this.origin.copy().add(this.dir.copy().mult(t * this.length));
121 | }
122 |
123 | draw() {
124 | let p0 = this.getHeadPosition(tween.powerOut(this.t0, 3));
125 | let p1 = this.getHeadPosition(tween.powerIn(this.t1, 3));
126 | line(p0.x, p0.y, p1.x, p1.y);
127 | endShape();
128 | }
129 | }
130 |
131 | function randomBool() {
132 | return Math.random() < 0.5;
133 | }
134 |
135 | /** Tween **/
136 |
137 | /** drawCircleMarker **/
138 |
--------------------------------------------------------------------------------
/js/examples/collision/collision_triangles.js:
--------------------------------------------------------------------------------
1 | let A, B;
2 |
3 | function setup() {
4 | canvas = createCanvas(windowWidth, windowHeight);
5 |
6 | A = new Triangle(0, 0, createVector(0, -80), createVector(-80, 40), createVector(80, 40));
7 | B = new Triangle(0, 0, createVector(0, -80), createVector(-40, 40), createVector(40, 40));
8 | }
9 |
10 | function draw() {
11 | clear();
12 | background(249, 246, 236);
13 | let t = radians(frameCount) / 2;
14 | A.position.x = cos(t) * 120;
15 | A.position.y = sin(t * 2) * 120;
16 | B.position.x = -cos(t * 3) * 120;
17 | B.position.y = -sin(t * 4) * 120;
18 | A.rotation = t;
19 | B.rotation = -t;
20 | A.update();
21 | B.update();
22 |
23 | // test
24 |
25 | let renderingData = [];
26 | let result = true;
27 | for (let i = 0; i < 3; i++) {
28 | let i0 = i;
29 | let i1 = (i + 1) % 3;
30 | let i2 = (i + 2) % 3;
31 | let vec = A.p[i1].copy().sub(A.p[i0]).normalize();
32 | let axis = createVector(vec.y, - vec.x);
33 | let o = axis.dot(A.p[i0]);
34 | let dA0 = axis.dot(A.p[i1]);
35 | let dA1 = axis.dot(A.p[i2]);
36 | let Amin = min(dA0, dA1);
37 | let Amax = max(dA0, dA1);
38 |
39 | let dB0 = axis.dot(B.p[0]);
40 | let dB1 = axis.dot(B.p[1]);
41 | let dB2 = axis.dot(B.p[2]);
42 | let Bmin = min(dB0, dB1, dB2);
43 | let Bmax = max(dB0, dB1, dB2);
44 |
45 | renderingData.push({vec: vec, axis: axis, o: o, Amin: Amin, Amax: Amax, Bmin, Bmax, result: false});
46 | if (
47 | ( Bmin <= Amin && Amin <= Bmax ) ||
48 | ( Bmin <= Amax && Amax <= Bmax ) ||
49 | ( Amin <= Bmin && Bmin <= Amax ) ||
50 | ( Amin <= Bmax && Bmax <= Amax )
51 | ) {
52 | renderingData[i].result = true;
53 | continue;
54 | }
55 | result = false;
56 | }
57 |
58 | // rendering
59 |
60 | push();
61 | translate(width / 2, height / 2);
62 | noStroke();
63 | if (result) {
64 | fill(225, 81, 106);
65 | } else {
66 | fill(255);
67 | }
68 | A.draw();
69 | B.draw();
70 |
71 | noFill(); stroke(0); strokeWeight(1);
72 | A.draw();
73 | B.draw();
74 |
75 | fill(0);
76 |
77 | let n = floor(frameCount / 180) % 4;
78 | let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
79 | for (let i = 0; i < n; i ++) {
80 | let d = renderingData[i];
81 | let origin = A.p[i].copy();
82 | let axis = new Line().fromPointAndVector(origin, d.axis);
83 |
84 | stroke(0); strokeWeight(1);
85 | axis.draw(boundary);
86 |
87 | let pAmin = origin.copy().add(d.axis.copy().mult(d.Amin - d.o));
88 | let pAmax = origin.copy().add(d.axis.copy().mult(d.Amax - d.o));
89 | let pBmin = origin.copy().add(d.axis.copy().mult(d.Bmin - d.o));
90 | let pBmax = origin.copy().add(d.axis.copy().mult(d.Bmax - d.o));
91 |
92 | stroke(0, 0, 0, 32);
93 | axis.getPerpendicular(pAmin).draw(boundary);
94 | axis.getPerpendicular(pAmax).draw(boundary);
95 | axis.getPerpendicular(pBmin).draw(boundary);
96 | axis.getPerpendicular(pBmax).draw(boundary);
97 |
98 | if (d.result) {
99 | let sorted = [d.Amin, d.Amax, d.Bmin, d.Bmax].sort((a,b)=>{return a > b ? 1: -1});
100 | let p0 = origin.copy().add(d.axis.copy().mult(sorted[1] - d.o));
101 | let p1 = origin.copy().add(d.axis.copy().mult(sorted[2] - d.o));
102 | stroke(0); strokeWeight(3);
103 | line(p0.x, p0.y, p1.x, p1.y);
104 | }
105 | }
106 | pop();
107 | }
108 |
109 | class Triangle {
110 | constructor(x, y, p0, p1, p2) {
111 | this.position = createVector(x, y);
112 | this.op = [];
113 | this.p = [];
114 | this.op.push(p0);
115 | this.op.push(p1);
116 | this.op.push(p2);
117 | this.p.push(createVector());
118 | this.p.push(createVector());
119 | this.p.push(createVector());
120 | this.rotation = 0;
121 | this.update();
122 | }
123 |
124 | update() {
125 | for (let i = 0; i < 3; i ++) {
126 | this.p[i] = rotate2d(this.op[i], this.rotation).add(this.position);
127 | }
128 | }
129 |
130 | draw() {
131 | beginShape();
132 | for (let i = 0; i < 3; i ++) {
133 | vertex(this.p[i].x, this.p[i].y);
134 | }
135 | endShape(CLOSE);
136 | }
137 | }
138 |
139 | /** rotate2d **/
140 |
141 | /** Line **/
142 |
--------------------------------------------------------------------------------
/collision.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Detecting Collision
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Detecting Collision
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Circles
19 |
Two circles,
20 | \(A\) and
21 | \(B\) collide if the distance between the center points is equal or less than the two radii added together.
22 |
23 |
$$distance(A_{center},B_{center}) \leq A_{radius}+B_{radius}\Rightarrow$$
24 |
$$distance(A_{center},B_{center})-A_{radius}-B_{radius}\leq 0$$
25 |
26 |
27 |
28 |
29 |
Line and Circle
30 |
The distance from a point
31 | \(P\) to a line that passes through points
32 | \(A\) and
33 | \(B\) is
34 |
35 |
$$distance=\left\|\overrightarrow{AP}\right\|\left|\sin(\theta)\right|=\left|(\overrightarrow{AP}_x\cdot \overrightarrow{AB}_y-\overrightarrow{AB}_x\cdot \overrightarrow{AP}_y)\right|/\left\|\overrightarrow{AB}\right\|$$ where
36 | \(\theta\) is the angle between
37 | \(\overrightarrow{AP}\) and
38 | \(\overrightarrow{AB}\)
39 |
40 |
41 |
42 |
Rectangles
43 |
Two rectangles,
44 | \(A\) and
45 | \(B\) that are axis aligned collide if
46 |
47 |
$$(A_{left}\leq B_{right})\;\wedge\;(A_{right}\geq B_{left})\;\wedge\;(A_{top}\leq B_{bottom})\wedge(A_{bottom}\geq B_{top})$$
48 |
49 |
This is to project the shapes to x and y-axis and checking overlap on each axis. Note that screen coordinate system in which y increase from top to bottom is assumed.
50 |
51 |
52 |
53 |
54 |
Triangles
55 |
Similarly, collision between two convex polygons can be detected by projecting the shapes to the vectors perpendicular to each side of one of the polygons.
56 |
57 |
58 |
59 |
Learn More
60 |
Collision Detection Using the Separating Axis Theorem
61 |
62 |
63 |
64 |
65 |
index
66 |
kynd 2019 | Please suggest edits and/or better code at Github
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | let elms = document.getElementsByClassName("example");
2 | let flms = [];
3 | let codeLoadCnt = 0;
4 |
5 | Array.prototype.forEach.call(elms, (elm, i)=> {
6 | let h = elm.clientWidth, w = elm.clientHeight;
7 |
8 | let iframe = createElement(document, "iframe", {scrolling:"no"}, "");
9 | elm.appendChild(iframe);
10 | var interval = setInterval(function() {
11 | var frame = iframe.contentWindow;
12 | var doc = iframe.contentDocument || iframe.contentWindow.document;
13 |
14 |
15 | if(doc.readyState == "complete") {
16 | clearInterval(interval);
17 | buildIframeContents(elm, frame, doc, i);
18 | }
19 | flms.push(frame);
20 | }, 100);
21 | });
22 |
23 | function buildIframeContents(elm, frame, doc, i) {
24 | let scriptPath = "js/examples/" + elm.getAttribute("data-embed") + ".js";
25 | frame.__parent = window;
26 | frame.__autorun = (i == 0);
27 |
28 | let css = createElement(doc, "link", {href: "css/example.css", rel: "stylesheet"}, "");
29 | doc.head.appendChild(css);
30 | appendScript(doc, "js/examples/lib.js")
31 | .then(()=>{appendScript(doc, scriptPath)
32 | .then(()=>{appendScript(doc, "js/examples/p5setup.js")
33 | .then(()=>{appendScript(doc, "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js")
34 | }) });
35 |
36 | if (i != 0) {
37 | createExampleFooter(elm, frame, scriptPath);
38 | }
39 | });
40 | }
41 |
42 | function createExampleFooter(elm, frame, scriptPath) {
43 | let exampleFooter = createElement(document, "p", {class: "example-footer"}, "");
44 | let buttonContainer = createElement(document, "div", {class: "button-container"}, "");
45 | let note = createElement(document, "span", {class: "note"}, "Click the example to run");
46 |
47 | let open = createElement(document, "a", {href: "", class: "button"}, "Show sample code");
48 | let edit = createElement(document, "a", {href: elm.getAttribute("data-edit"), class: "button", target:"_blank"}, "Edit in Codepen");
49 | exampleFooter.appendChild(note);
50 | buttonContainer.appendChild(open);
51 | buttonContainer.appendChild(edit);
52 | exampleFooter.appendChild(buttonContainer);
53 | elm.parentNode.insertBefore(exampleFooter, elm.nextElementSibling);
54 |
55 | let xhr = new XMLHttpRequest();
56 | xhr.open('GET', scriptPath);
57 | xhr.onload = ()=> {
58 | let script = xhr.responseText;
59 | let re = /\/\*\* (.+) \*\*\//g;
60 | let match = script.match(re);
61 | if (match) {
62 | Array.prototype.forEach.call(match, (s)=>{
63 | let func = frame[s.split(" ")[1]];
64 | if (func) {
65 | script = script.replace(s, func.toString());
66 | } else {
67 | console.log("failed replacing comment with code: " + s);
68 | }
69 | });
70 | }
71 |
72 | let text = document.createTextNode(script);
73 | let code = createElement(document, "code", {}, text);
74 | let pre = createElement(document, "pre", {class: "javascript"}, code);
75 | let codeBlock = createElement(document, "div", {class: "code-block hidden"}, pre);
76 |
77 | elm.parentNode.insertBefore(codeBlock, exampleFooter.nextElementSibling);
78 |
79 | open.addEventListener("click", (evt)=>{
80 | evt.preventDefault();
81 | if (codeBlock.classList.contains("hidden")) {
82 | open.innerHTML = "Hide sample code";
83 | codeBlock.classList.remove("hidden");
84 | } else {
85 | open.innerHTML = "Show sample code";
86 | codeBlock.classList.add("hidden");
87 | }
88 | });
89 | if (--codeLoadCnt == 0) {
90 | hljs.initHighlightingOnLoad();
91 | }
92 | }
93 | codeLoadCnt ++; xhr.send();
94 | }
95 |
96 | function appendScript(doc, path) {
97 | return new Promise((resolve, reject)=>{
98 | let script = createElement(doc, "script", {src: path}, "");
99 | script.onload = ()=>{resolve();};
100 | doc.head.appendChild(script);
101 | });
102 | };
103 |
104 | function focusExample(flm) {
105 | for (let i = 0; i < flms.length; i ++) {
106 | flms[i].stop();
107 | }
108 | flm.start();
109 | }
110 |
111 | function createElement(doc, tag, attr, content) {
112 | let elm = doc.createElement(tag);
113 | Object.keys(attr).forEach(function(key) {
114 | elm.setAttribute(key, attr[key]);
115 | var value = this[key];
116 | });
117 | if (typeof content == 'string') {
118 | elm.innerHTML = content;
119 | } else {
120 | elm.appendChild(content);
121 | }
122 | return elm;
123 | }
124 |
--------------------------------------------------------------------------------
/wave.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Wave Anatomy
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Wave Anatomy
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Sine Wave
19 |
20 |
21 |
Square Wave (Additive Synthesis)
22 |
23 | $${\displaystyle {\begin{aligned}x_{\text{square}}(t)&={\frac {4}{\pi }}\sum _{k=1}^{\infty }{\frac {\sin \left(2\pi (2k-1)ft\right)}{2k-1}}\\&={\frac {4}{\pi }}\left(\sin(2\pi ft)+{\frac {1}{3}}\sin(6\pi ft)+{\frac {1}{5}}\sin(10\pi ft)+\dots \right)\end{aligned}}}$$
24 |
25 |
26 |
Triangle Wave (Additive Synthesis)
27 |
28 | $${\displaystyle {\begin{aligned}x_{{\mathrm {triangle}}}(t)&{}={\frac {8}{\pi ^{2}}}\sum _{{k=0}}^{\infty }(-1)^{k}\,{\frac {\sin \left(2\pi (2k+1)ft\right)}{(2k+1)^{2}}}\\&{}={\frac {8}{\pi ^{2}}}\left(\sin(2\pi ft)-{1 \over 9}\sin(6\pi ft)+{1 \over 25}\sin(10\pi ft)-\cdots \right)\end{aligned}}}$$
29 |
30 |
31 |
Sawtooth Wave (Additive Synthesis)
32 |
33 | $${\displaystyle x_{\mathrm {reversesawtooth} }(t)={\frac {2}{\pi }}\sum _{k=1}^{\infty }{(-1)}^{k}{\frac {\sin(2\pi kft)}{k}}}$$
34 |
$${\displaystyle x_{\mathrm {sawtooth} }(t)={\frac {1}{2}}-{\frac {1}{\pi }}\sum _{k=1}^{\infty }{(-1)}^{k}{\frac {\sin(2\pi kft)}{k}}}$$
35 |
36 |
37 |
Simple Harmonic Motion
38 |
Simple harmonic motion is a type of periodic motion where the restoring force obeys Hooke's Law (
39 | \(\mathbf F=-k\mathbf x\) ). The motion is sinusoidal in time and demonstrates a single resonant frequency.
40 |
41 |
42 |
Wave Equation
43 |
44 |
45 |
One dimension
46 |
$${\displaystyle {\partial ^{2}u \over \partial t^{2}}=c^{2}{\partial ^{2}u \over \partial x^{2}}}$$
47 |
Approximation in Code
48 |
$$\frac{\partial^2u}{\partial t^2}\Rightarrow\;(u_{t+1}-u_t)\;-\;(u_{t-1}-u_t)\;=\;u_{t+1}\;+\:u_{t-1\;}-\;2u_t$$
49 |
$$c^2\frac{\partial^2u}{\partial x^2}\Rightarrow\;c^2\left[(u_{x-1}-u_x)\;-\;(u_{x+1}-u_x)\right]\;=\;c^2(u_{x-1}\;+u_{x+1\;}-\;2u_x)$$
50 |
$$u_{t+1}\;+\:u_{t-1\;}-\;2u_t=\;c^2(u_{x-1}\;+u_{x+1\;}-\;2u_x)$$
51 |
$$u_{t+1}\;=\;2u_t\;\;+\;c^2(u_{x-1}\;+u_{x+1\;}-\;2u_x)\;-\:u_{t-1\;}$$
52 |
53 |
54 |
55 |
Two dimensions
56 |
57 |
58 |
59 |
60 |
61 |
$$\frac{\partial^2u}{\partial t^2}=c^2\left(\frac{\partial^2u}{\partial x^2}\;+\;\frac{\partial^2u}{\partial y^2}\right)$$
62 |
$$\Rightarrow u_{t+1}\;=\;2u_t\;\;+\;c^2(u_{x-1}\;+u_{x+1\;}+u_{y-1}\;+u_{y+1\;}-\;4u_x)\;-\:u_{t-1\;}$$
63 |
Open WebGL Demo Source
64 |
65 |
66 |
67 |
index
68 |
kynd 2019 | Please suggest edits and/or better code at Github
69 |
70 |
71 |
72 |
73 |
74 |
75 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/handy_math.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Handy Math
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Handy Math
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Sine, Cosine and Tangent
19 |
20 |
21 |
$$\mathrm{sine}=\frac{\mathrm{opposite}}{\mathrm{hypotenuse}}$$
22 |
$$\mathrm{cosine}=\frac{\mathrm{adjacent}}{\mathrm{hypotenuse}}$$
23 |
$$\mathrm{tangent}=\frac{\mathrm{sine}}{\mathrm{cosine}}$$
24 |
25 |
* Note that p5.js is based on the screen coordinate system in which y increase from top to bottom. The opposite is flipped by multiplying -1 in the rendering below.
26 |
27 |
28 |
29 |
Rotating 2D points
30 |
31 |
32 |
$$\begin{bmatrix}x'\\y'\end{bmatrix}=\begin{bmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}$$
33 |
34 |
35 |
Learn more
36 |
A Gentle Primer on 2D Rotations
37 |
38 |
Euclidean distance between two points
39 |
40 |
Euclidean distance is the most intuitive, "ordinary" straight-line distance between two points in Euclidean space.
41 |
42 |
Two dimensions
43 |
$$p=(p_x,p_y),\;q=(q_x,q_y)$$
44 |
$$\mathrm{distance}(p,q)=\sqrt{(p_x-q_x)^2+(p_y-q_y)^2}$$
45 |
46 |
n dimensions
47 |
$$p=(p_1,p_2\cdots,p_n),\;q=(q_1,q_2\cdots,q_n)$$
48 |
$$\mathrm{distance}(p,q)=\sqrt{(p_1-q_1)^2+(p_2-q_2)^2+\cdots+(p_n-q_n)^2}=\sqrt{\sum_{i=1}^n(p_i+q_i)^2}$$
49 |
50 |
51 |
52 |
53 |
Manhattan distance between two points
54 |
Euclidean distance is not the only way to measure distance between two points. In mathmatics, distance is defined by a function called distance function or metric , which can be any function that satisfy a set of conditions.
55 |
Manhattan distance is an example of a non-Euclidean distance, which is the sum of the absolute differences of their Cartesian coordinates, or the distance a car would drive in a city laid out in square blocks.
56 |
57 |
Two dimensions
58 |
$$p=(p_x,p_y),\;q=(q_x,q_y)$$
59 |
$$distance\left(p,\;q\right)\;=\;\left|p_x\;-\;q_x\right|\;-\;\left|p_y\;-\;qy_{}\right|\;$$
60 |
61 |
62 |
63 |
64 |
Perspective Projection (Fixed Camera)
65 |
66 |
\(\lbrack x,y,z\rbrack\) projects to \(\left[x\frac{\displaystyle d_1}{\displaystyle d_2},y\frac{\displaystyle d_1}{\displaystyle d_2}\right]\)
67 |
68 |
69 | \(d_1=\) Focal length
70 | the axial distance from the camera center to the image plane
71 | \(d_2=\) Subject distance
72 | the axial distance from the camera center to the subject
73 |
74 |
75 |
76 |
77 |
78 |
79 |
Dot Product
80 |
Two dimensions
81 |
82 |
$${\boldsymbol v}_\mathbf1=\lbrack x_1,y_1\rbrack,\hspace{8px}{\boldsymbol v}_\mathbf2=\lbrack x_2,y_2\rbrack$$
83 |
$${\boldsymbol v}_\mathbf1\cdot{\boldsymbol v}_\mathbf2=x_1x_2+y_1y_2$$
84 |
85 |
n dimensions
86 |
87 |
$$\boldsymbol a=\lbrack a_1,a_2,a_3,\dots,a_n\rbrack,\hspace{8px}\boldsymbol b=\lbrack b_1,b_2,b_3,\dots,b_n\rbrack$$
88 |
$$\boldsymbol a\cdot\boldsymbol b=a_1b_1+a_2b_2+a_3b_3\dots a_nb_n$$
89 |
90 |
91 |
92 | Two non-zero vectors a and b are orthogonal if and only if a ⋅ b = 0.
93 | If the dot product is positive, the angle between the vectors is less than 90°.
94 | If the dot product is negative, the angle between the vectors is more than 90°.
95 |
96 |
97 |
98 |
99 |
Cross Product
100 |
3 dimensions
101 |
102 |
$${\boldsymbol v}_\mathbf1=\lbrack x_1,y_1,z_1\rbrack,\;{\boldsymbol v}_\mathbf2=\lbrack x_2,y_2,z_2\rbrack$$
103 |
$${\boldsymbol v}_\mathbf1\times{\boldsymbol v}_\mathbf2=\lbrack y_1z_2-z_1y_2,z_1x_2-x_1z_2,x_1y_2-y_1x_2\rbrack$$
104 |
105 |
106 |
107 | The cross product is orthogonal to both of the original vectors(v1 and v2), which implies the cross product is perpendicular to the plane defined by the original vectors.
108 | If the cross product of two vectors is the zero vector, either one or both of the inputs is the zero vector, or they are parallel or antiparallel.
109 |
110 |
111 |
112 |
113 |
index
114 |
kynd 2019 | Please suggest edits and/or better code at Github
115 |
116 |
117 |
118 |
119 |
120 |
121 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/drawings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Geometric Drawings
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Geometric Drawings
16 |
Sketching with Math and Quasi Physics
17 |
There is a newer and more elaborate version of this site. Visit Sketching with Math and Quasi Physics on Notion.
18 |
Lines
19 |
Two lines,
20 | \(a_1x+by_1+\;c_1=0\)
21 | and
22 | \(a_2x+by_2+\;c_2=0\)
23 | intersect if
24 | \(a_1b_2\neq a_2b_1\)
25 |
26 |
The point of intersection is
27 |
28 |
$$x=(b_1c_2-b_2c_1)/(a_1b_2-a_2b_1)$$
29 |
$$y=(a_1c_2-a_2c_1)/(a_1b_2-a_2b_1)$$
30 |
31 |
32 |
33 |
34 |
Line Segments
35 |
36 |
37 |
Circle
38 |
39 |
40 |
Bézier Curve
41 |
42 |
Linear Bézier curves
43 |
A linear Bézier curve is simply a straight line between two points, which can be defined as linear interpolation between two points
44 |
$$\mathbf {B}_{linear\mathbf {P} _{0}, \mathbf {P} _{1}} (t)=(1-t)\mathbf {P} _{0}+t\mathbf {P} _{1}{\mbox{ , }}0\leq t\leq 1$$
45 |
46 |
Quadratic Bézier curves
47 |
A quadratic Bézier curves can be defined as linear interpolation between corresponding points on two linear Bézier curves.
48 |
$${\displaystyle \mathbf {B}_{quadratic \mathbf {P} _{0}, \mathbf {P} _{1}, \mathbf {P} _{2}} (t)=(1-t)\mathbf {B}_{linear \mathbf {P} _{0}, \mathbf {P} _{1}}(t)+t\mathbf {B}_{linear \mathbf {P} _{0}, \mathbf {P} _{2}}(t){\mbox{ , }}0\leq t\leq 1}$$
49 |
Qubic Bézier curves
50 |
And a cubic Bézier curves is linear interpolation between corresponding points on two quadratic Bézier curves.
51 |
$$\mathbf {B}_{cubic{\mathbf {P} _{0}, \mathbf {P} _{1}, \mathbf {P} _{2},\mathbf {P} _{3}}} (t)=(1-t)\mathbf {B} _{quadratic \mathbf {P} _{0},\mathbf {P} _{1},\mathbf {P} _{2}}(t)+t\mathbf {B} _{quadratic \mathbf {P} _{1},\mathbf {P} _{2},\mathbf {P} _{3}}(t)$$
52 |
$$=(1-t)^{3}\mathbf {P} _{0}+3(1-t)^{2}t\mathbf {P} _{1}+3(1-t)t^{2}\mathbf {P} _{2}+t^{3}\mathbf {P} _{3}{\mbox{ , }}0\leq t\leq 1$$
53 |
54 |
55 |
56 |
57 |
B-Spline Curve
58 |
\(P\) is a set of control points and \(t\) is a vector of non-decreasing numbers called "knot vector" which has \(number\;of\;control\;points\;+\;order\;of\;the\;curve(n)\;+\;1\) elements, e.g. \((0, 0, 0, 1, 2, 3, 3, 3)\).
B-spline basis function, \(B\) is defined on the knot vector and used to weight the control points.
59 |
60 |
61 |
$${\displaystyle Spline_{n,t}(x)=\sum _{i}P _{i}B_{i,n}(x)}$$
62 |
$$B_{i,0}(x):=$$
63 |
$$\begin{array}{lc}1&\mathrm{if}\; {t}_{i}\leq{x}<{t}_{i + 1}\end{array},$$
64 |
$$\begin{array}{lc}0&otherwise\end{array}$$
65 |
$${\displaystyle B_{i,k}(x):={\frac {x-t_{i}}{t_{i+k}-t_{i}}}B_{i,k-1}(x)+{\frac {t_{i+k+1}-x}{t_{i+k+1}-t_{i+1}}}B_{i+1,k-1}(x)}$$
66 |
67 |
68 |
69 |
Learn more
70 |
B-spline Basis Functions: Definition
71 |
B-spline curve
72 |
73 |
Circumcircle and Circumcenter
74 |
75 |
76 | Circumcircle
77 | The circle that passes through three vertices of a triangle.
78 | Circumcenter
79 | The center of the circumcircle. The intersection of the perpendicular bisectors of a triangle.
80 |
81 |
82 |
83 |
84 |
Incircle and Incenter
85 |
86 |
87 | Incircle
88 | The circle tangent to the three sides of a triangle.
89 | Incenter
90 | The center of the incircle. The intersection of angle bisectors of a triangle.
91 |
92 |
93 |
94 |
95 |
Excircles and Excenters
96 |
97 |
98 | Excircles
99 | The circles tangent to one of a triangle's sides and to the extensions of the other two.
100 | Excenters
101 | The centers of an excircles. Points where the external angle bisectors of a triangle intersect.
102 |
103 |
104 |
105 |
106 |
107 |
Orthocenter
108 |
109 |
110 | Orthocenter
111 | The intersection of the three altitudes of a triangle.
112 |
113 |
114 |
115 |
116 |
Centroid
117 |
118 |
119 | Centroid
120 | The arithmetic mean position of all the points in a shape. The centroid of a triangle is the intersection of its three medians.
121 |
122 |
123 |
124 |
125 |
Reuleaux Triangle
126 |
127 | A reuleaux triangle can rotate within a square while touching all four sides of a square.
128 |
129 |
130 |
131 |
Spinner
132 |
133 |
134 |
index
135 |
kynd 2019 | Please suggest edits and/or better code at Github
136 |
137 |
138 |
139 |
140 |
141 |
142 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------