├── images
└── favicon.ico
├── projects
├── trees
│ ├── index.css
│ ├── image.png
│ ├── index.html
│ └── index.js
├── converge
│ ├── image.png
│ ├── index.css
│ ├── index.html
│ └── index.js
├── hehehe
│ ├── rickroll.mp4
│ ├── index.css
│ ├── index.html
│ └── index.js
└── tiny-mirror
│ ├── image.jpg
│ ├── index.css
│ ├── index.html
│ └── index.js
├── README.md
└── index.html
/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wybiral/code-art/HEAD/images/favicon.ico
--------------------------------------------------------------------------------
/projects/trees/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-size: 0;
3 | margin: 0;
4 | padding: 0;
5 | }
--------------------------------------------------------------------------------
/projects/trees/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wybiral/code-art/HEAD/projects/trees/image.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # code-art
2 |
3 | [https://wybiral.github.io/code-art/](https://wybiral.github.io/code-art/)
4 |
--------------------------------------------------------------------------------
/projects/converge/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wybiral/code-art/HEAD/projects/converge/image.png
--------------------------------------------------------------------------------
/projects/hehehe/rickroll.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wybiral/code-art/HEAD/projects/hehehe/rickroll.mp4
--------------------------------------------------------------------------------
/projects/tiny-mirror/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wybiral/code-art/HEAD/projects/tiny-mirror/image.jpg
--------------------------------------------------------------------------------
/projects/tiny-mirror/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | body {
7 | padding-top: 20px;
8 | text-align: center;
9 | font-family: Arial;
10 | }
--------------------------------------------------------------------------------
/projects/converge/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-size: 0;
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | body {
8 | background-color: #666;
9 | text-align: center;
10 | font-family: Arial;
11 | }
12 |
13 | canvas {
14 | margin: 20px auto;
15 | box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.5);
16 | }
17 |
--------------------------------------------------------------------------------
/projects/hehehe/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | body {
7 | padding-top: 20px;
8 | text-align: center;
9 | font-family: Arial;
10 | }
11 |
12 | body, html {
13 | width: 100%;
14 | height: 100%;
15 | }
16 |
17 | canvas, video {
18 | display: none;
19 | width: 32px;
20 | height: 32px;
21 | }
--------------------------------------------------------------------------------
/projects/hehehe/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <-- hehehe
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Hint: Look at the favicon
13 | (if nothing happens, click on this page)
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/projects/trees/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Trees
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/projects/converge/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Converge
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/projects/tiny-mirror/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tiny Mirror
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Hint: Look at the favicon
18 | (doesn't really work on mobile)
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/projects/hehehe/index.js:
--------------------------------------------------------------------------------
1 | window.onload = () => {
2 | // Create favicon link element
3 | const favicon = document.createElement('link');
4 | favicon.rel = 'shortcut icon';
5 | favicon.type = 'image/png';
6 | favicon.href = '../../images/favicon.ico';
7 | document.getElementsByTagName('head')[0].appendChild(favicon);
8 | // Create hidden canvas
9 | const w = 32;
10 | const h = 32;
11 | const canvas = document.getElementById('canvas');
12 | canvas.width = w;
13 | canvas.height = h;
14 | // Grab canvas context
15 | const ctx = canvas.getContext('2d');
16 | // Create hidden video element
17 | const video = document.getElementById('video');
18 | video.width = w;
19 | video.height = h;
20 | // Loop forever
21 | const loop = () => {
22 | // Copy video to canvas
23 | ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
24 | // Set canvas to favicon
25 | favicon.setAttribute('href', canvas.toDataURL());
26 | // Loop
27 | setTimeout(loop, 50);
28 | };
29 | loop();
30 | document.body.onclick = () => video.play();
31 | document.body.onfocus = () => video.play();
32 | document.body.onmouseover = () => video.play();
33 | };
34 |
35 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Code Art
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 | Code Art
21 |
22 | -
23 |
24 |
Procedurally generated trees grow on a canvas.
25 |
26 | -
27 |
28 |
A visual experiment in unification.
29 |
30 | -
31 |
32 |
Check yourself out in 16x16 resolution.
33 |
34 | -
35 |
36 |
Never gonna give you up.
37 |
38 | -
39 |
40 |
Procedurally generated video game music.
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/projects/tiny-mirror/index.js:
--------------------------------------------------------------------------------
1 | // Handle FF
2 | navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia;
3 |
4 | window.onload = () => {
5 | // Create favicon link element
6 | const favicon = document.createElement('link');
7 | favicon.rel = 'shortcut icon';
8 | favicon.type = 'image/png';
9 | favicon.href = '../../images/favicon.ico';
10 | document.getElementsByTagName('head')[0].appendChild(favicon);
11 | // Create hidden canvas
12 | const w = 32;
13 | const h = 32;
14 | const canvas = document.createElement('canvas');
15 | canvas.style = 'display: none';
16 | canvas.width = w;
17 | canvas.height = h;
18 | document.body.appendChild(canvas);
19 | // Grab canvas context
20 | const ctx = canvas.getContext('2d');
21 | // Create hidden video element
22 | const video = document.createElement('video');
23 | video.style = 'display: none';
24 | video.width = canvas.width;
25 | video.height = canvas.height;
26 | document.body.appendChild(video);
27 | // Assign user media to video and start loop
28 | navigator.mediaDevices.getUserMedia({video: true}).then(stream => {
29 | video.srcObject = stream;
30 | video.play();
31 | loop();
32 | });
33 | // Flag for mirror image
34 | let mirror = false;
35 | // Loop forever
36 | const loop = () => {
37 | // save transform
38 | ctx.save();
39 | // Mirror image based on checkbox
40 | if (mirror) {
41 | ctx.translate(canvas.width, 0);
42 | ctx.scale(-1, 1);
43 | }
44 | // Copy video to canvas
45 | ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
46 | // restore transform
47 | ctx.restore();
48 | // Set canvas to favicon
49 | favicon.setAttribute('href', canvas.toDataURL());
50 | // Loop
51 | setTimeout(loop, 100);
52 | };
53 | // Handle checkbox change event
54 | document.getElementById('mirror').addEventListener('change', e => {
55 | mirror = e.target.checked;
56 | });
57 | };
58 |
59 |
--------------------------------------------------------------------------------
/projects/converge/index.js:
--------------------------------------------------------------------------------
1 | window.onload = function() {
2 | const width = 700;
3 | const height = 700;
4 | let canvas = document.createElement('canvas');
5 | canvas.width = width;
6 | canvas.height = height;
7 | document.body.appendChild(canvas);
8 | let ctx = canvas.getContext('2d');
9 | ctx.fillStyle = 'rgb(255,255,255)';
10 | ctx.fillRect(0, 0, width, height);
11 | let bodies = [];
12 | for (let i = 0; i < 2000; i++) {
13 | bodies.push(create());
14 | }
15 | start(ctx, bodies);
16 | };
17 |
18 | function start(ctx, bodies) {
19 | function loop() {
20 | const avgDistance = integrate(bodies);
21 | if (avgDistance > 5) {
22 | requestAnimationFrame(loop);
23 | }
24 | for (var i = 0; i < bodies.length; i++) {
25 | var a = bodies[i];
26 | ctx.strokeStyle = 'rgba(' + a.r + ', ' + a.g + ', ' + a.b + ', 0.1)';
27 | ctx.beginPath();
28 | ctx.moveTo(a.x0, a.y0);
29 | ctx.lineTo(a.x, a.y);
30 | ctx.stroke();
31 | }
32 | }
33 | loop();
34 | }
35 |
36 | function integrate(bodies) {
37 | const n = bodies.length;
38 | let totalDistance = 0.0;
39 | for (let i = 0; i < n; i++) {
40 | let a = bodies[i];
41 | for (let j = i + 1; j < n; j++) {
42 | let b = bodies[j];
43 | const dx = a.x - b.x;
44 | const dy = a.y - b.y;
45 | const d = Math.sqrt(dx * dx + dy * dy);
46 | const af = b.mass / d;
47 | const bf = a.mass / d;
48 | if (d > 0.01) {
49 | a.xv -= (dx / d) * af;
50 | a.yv -= (dy / d) * af;
51 | b.xv += (dx / d) * bf;
52 | b.yv += (dy / d) * bf;
53 | }
54 | totalDistance += d;
55 | }
56 | }
57 | for (let i = 0; i < n; i++) {
58 | let a = bodies[i];
59 | a.x0 = a.x;
60 | a.y0 = a.y;
61 | a.x += a.xv;
62 | a.y += a.yv;
63 | a.xv *= 0.95;
64 | a.yv *= 0.95;
65 | }
66 | return totalDistance / (n * n);
67 | }
68 |
69 | function create() {
70 | const r = Math.random() * 50 + 300;
71 | const a = Math.random() * Math.PI * 2;
72 | const x = 350 + Math.cos(a) * r;
73 | const y = 350 + Math.sin(a) * r;
74 | return {
75 | x: x,
76 | y: y,
77 | xv: Math.random() * 0.2 - 0.1,
78 | yv: Math.random() * 0.2 - 0.1,
79 | mass: 0.01,
80 | r: 0 | (x / 700) * 255,
81 | g: 0 | (1 - ((x + y) / 1400)) * 255,
82 | b: 0 | (y / 700) * 255
83 | };
84 | }
--------------------------------------------------------------------------------
/projects/trees/index.js:
--------------------------------------------------------------------------------
1 | // That's right... I'm using globals... *gasp*
2 | let width;
3 | let height;
4 | let canvas;
5 | let ctx;
6 |
7 | window.onload = function() {
8 | width = window.innerWidth;
9 | height = window.innerHeight;
10 | canvas = document.createElement('canvas');
11 | canvas.width = width;
12 | canvas.height = height;
13 | document.body.appendChild(canvas);
14 | ctx = canvas.getContext('2d');
15 | ctx.fillStyle = 'rgb(255,255,200)';
16 | ctx.fillRect(0, 0, width, height);
17 | setTimeout(() => mainLoop([create()]), 5000);
18 | };
19 |
20 | function mainLoop(particles) {
21 | let nextParticles = [];
22 |
23 | requestAnimationFrame(function() {
24 | mainLoop(nextParticles);
25 | });
26 |
27 | let spawnCutoff = width / 1000000;
28 | if (Math.random() < spawnCutoff) {
29 | nextParticles.push(create());
30 | }
31 |
32 | ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
33 | for (let i = 0, len = particles.length; i < len; i++) {
34 | renderParticle(particles[i]);
35 | updateParticle(particles[i], nextParticles);
36 | }
37 |
38 | // Nothing lasts forever. Not even these pixels.
39 | ctx.fillStyle = 'rgba(255, 255, 200, 0.05)';
40 | let n = (width * height * 0.001) | 0;
41 | for (let i = 0; i < n; i++) {
42 | let x = Math.random() * width;
43 | let y = Math.random() * height;
44 | ctx.fillRect(x, y, 1, 1);
45 | }
46 | }
47 |
48 | function renderParticle(p) {
49 | let radius = p.radius;
50 | let n = 1 + (radius * radius * Math.PI * 0.5) | 0;
51 | for (let i = 0; i < n; i++) {
52 | let a = Math.random() * Math.PI * 2;
53 | let r = Math.sqrt(Math.random()) * radius;
54 | let x = p.x + Math.cos(a) * r;
55 | let y = p.y + Math.sin(a) * r;
56 | ctx.fillRect(x, y, 1, 1);
57 | }
58 | }
59 |
60 | function updateParticle(p, nextParticles) {
61 | let d = Math.random() * 1.25;
62 | p.x += Math.cos(p.angle) * d;
63 | p.y += Math.sin(p.angle) * d;
64 | p.angle += Math.random() * 0.02 - 0.01;
65 | p.radius *= 0.998;
66 | if (p.radius > 0.5) {
67 | // This means that the branch continues on
68 | nextParticles.push(p);
69 | let splitCutoff = Math.min(0.005, 1.0 / (p.radius * 10));
70 | if (Math.random() < splitCutoff) {
71 | // And this means that it splits to become two branches
72 | nextParticles.push({
73 | x: p.x,
74 | y: p.y,
75 | angle: p.angle + Math.random() - 0.5,
76 | radius: p.radius * 0.9
77 | });
78 | p.angle += Math.random() - 0.5;
79 | p.radius *= 0.9;
80 | }
81 | } else {
82 | // Let's have a moment of silence for the loss of this great branch.
83 | // ...
84 | }
85 | }
86 |
87 | // A newborn branch. Isn't it cute?
88 | function create() {
89 | return {
90 | x: Math.random() * width,
91 | y: height + 5,
92 | angle: -Math.PI / 2,
93 | radius: Math.random() * 20 + 20,
94 | };
95 | }
96 |
--------------------------------------------------------------------------------