Cool lines

In this example below you will see how to do a Cool lines with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by AndrewdrewMiller, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright AndrewdrewMiller ©
  • HTML
  • CSS
  • JavaScript
    <canvas id="canvas"></canvas>
<img id="source" src="data:image/jpeg;base64,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" alt="">

/*Downloaded from https://www.codeseek.co/AndrewdrewMiller/cool-lines-JOMjEe */
    html {
  overflow: hidden;
  touch-action: hidden;
  content-zooming: none;
}

body {
  position: absolute;
  margin: 0;
  padding: 0;
  background: #000;
  width: 100%;
  height: 100%;
}

#canvas {
  width: 100%;
  height: 100%;
  background: #000;
  position: absolute;
}

#source {
  visibility: hidden;
}


/*Downloaded from https://www.codeseek.co/AndrewdrewMiller/cool-lines-JOMjEe */
    // Inspired by https://www.airtightinteractive.com/2011/06/rutt-etra-izer/
"use strict";
{
	// webGL canvas
	const canvas = {
		init(options) {
			// set webGL context
			this.elem = document.querySelector("canvas");
			const gl = (this.gl =
				this.elem.getContext("webgl", options) ||
				this.elem.getContext("experimental-webgl", options));
			if (!gl) return false;
			// compile shaders
			const vertexShader = gl.createShader(gl.VERTEX_SHADER);
			gl.shaderSource(
				vertexShader,
				`
					precision highp float;
					const float FOV = 250.0;
					attribute vec3 aPosition, aColor;
					uniform vec2 uResolution;
					uniform vec4 uRotation;
					varying vec3 color;
					void main() {
						// 3D Rotations
						float tx, ty, tz;
						tx = uRotation.z * aPosition.x - uRotation.w * aPosition.z;
						tz = uRotation.w * aPosition.x + uRotation.z * aPosition.z;
						ty = uRotation.x * aPosition.y - uRotation.y * tz;
						tz = uRotation.y * aPosition.y + uRotation.x * tz;
						// 3D to 2D projection
						float s = FOV / (FOV - tz);
						float x = s > 0.0 ? tx * s : 0.0;
						float y = s > 0.0 ? ty * s : 0.0;
						gl_Position = vec4(
							( (uResolution.x * 0.5 + x) / uResolution.x * 2.0) - 1.0, 
							( (-uResolution.y * 0.5 -y) / uResolution.y * 2.0) + 1.0, 
							s > 0.0 ? 0.0 : 10.0,
							1.0
						);
						color = aColor;
					}
      	`
			);
			gl.compileShader(vertexShader);
			const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
			gl.shaderSource(
				fragmentShader,
				`
					precision highp float;
					varying vec3 color;
					void main() {
						gl_FragColor = vec4(color.r, color.g, color.b, 1.0);
					}
				`
			);
			gl.compileShader(fragmentShader);
			const program = (this.program = gl.createProgram());
			gl.attachShader(this.program, vertexShader);
			gl.attachShader(this.program, fragmentShader);
			gl.linkProgram(this.program);
			gl.useProgram(this.program);
			// resolution
			this.uResolution = gl.getUniformLocation(this.program, "uResolution");
			gl.enableVertexAttribArray(this.uResolution);
			// canvas resize
			this.resize();
			window.addEventListener("resize", () => this.resize(), false);
			return gl;
		},
		buffer(attribute) {
			const buffer = {
				attribute: gl.getAttribLocation(canvas.program, attribute),
				buffer: gl.createBuffer(),
				load (data, usage, size) {
					gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
					gl.vertexAttribPointer(this.attribute, size, gl.FLOAT, false, 0, 0);
					gl.bufferData(gl.ARRAY_BUFFER, data, usage);
				}
			};
			gl.enableVertexAttribArray(buffer.attribute);
			return buffer;
		},
		resize() {
			this.width = this.elem.width = this.elem.offsetWidth;
			this.height = this.elem.height = this.elem.offsetHeight;
			this.gl.uniform2f(this.uResolution, this.width, this.height);
			this.gl.viewport(
				0,
				0,
				this.gl.drawingBufferWidth,
				this.gl.drawingBufferHeight
			);
		}
	};
	// init pointer
	const pointer = {
		init(canvas) {
			this.x = canvas.width * 0.5;
			this.y = canvas.height * 0.5;
			this.ex = this.x;
			this.ey = this.y * 2;
			["mousemove", "touchstart", "touchmove"].forEach((event, touch) => {
				document.addEventListener(
					event,
					e => {
						if (touch) {
							e.preventDefault();
							this.x = e.targetTouches[0].clientX;
							this.y = e.targetTouches[0].clientY;
						} else {
							this.x = e.clientX;
							this.y = e.clientY;
						}
					},
					false
				);
			});
		},
		ease(step) {
			this.ex += (this.x - this.ex) * step;
			this.ey += (this.y - this.ey) * step;
		}
	};
	// init webGL canvas
	const gl = canvas.init({
		alpha: false,
		stencil: false,
		antialias: true,
		depth: false
	});
	// additive blending "lighter"
	gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
	gl.enable(gl.BLEND);
	// init pointer
	pointer.init(canvas);
	// init image
	const img = new Image();
	img.addEventListener("load", e => load(img));
	img.src = document.getElementById("source").src;
	// rotation matrix
	const uRotation = gl.getUniformLocation(canvas.program, "uRotation");
	gl.enableVertexAttribArray(uRotation);
	// init colors and geometry
	let nVertices = 0;
	const load = img => {
		//////////////////////
		const step = 3;
		const depth = 75;
		//////////////////////
		const image = document.createElement("canvas");
		const width = (image.width = img.width);
		const height = (image.height = img.height);
		const ctx = image.getContext("2d");
		ctx.drawImage(img, 0, 0);
		const bitmap = ctx.getImageData(0, 0, width, height).data;
		const vertices = [];
		const colors = [];
		// buffers
		const position = canvas.buffer("aPosition");
		const color = canvas.buffer("aColor");
		// push vertex
		const push = (x, y) => {
			const p = (y * width + x) * 4;
			const r = bitmap[p + 0] / 256;
			const g = bitmap[p + 1] / 256;
			const b = bitmap[p + 2] / 256;
			colors.push(r);
			colors.push(g);
			colors.push(b);
			vertices.push(x - width * 0.5);
			vertices.push(y - height * 0.5);
			vertices.push(depth * (0.34 * r + 0.5 * g + 0.16 * b));
		};
		// init the line
		let d = 1;
		for (let y = 0; y < height; y += step) {
			if (d > 0) {
				for (let x = 0; x < width; x += step) push(x, y);
			} else {
				for (let x = width; x > 0; x -= step) push(x, y);
			}
			d = -d;
		}
		// load buffers to gpu
		nVertices = Math.floor(colors.length / 3);
		position.load(new Float32Array(vertices), gl.STATIC_DRAW, 3);
		color.load(new Float32Array(colors), gl.STATIC_DRAW, 3);
		// start animation loop
		requestAnimationFrame(run);
	};
	// main animation loop
	const run = () => {
		requestAnimationFrame(run);
		pointer.ease(0.05);
		// rotation
		const ry = (pointer.ex - canvas.width * 0.5) / (canvas.width * 0.33);
		const rx = (pointer.ey - canvas.height * 0.5) / (canvas.height * 0.33);
		gl.uniform4f(uRotation, Math.cos(rx), Math.sin(rx), Math.cos(ry), Math.sin(ry));
		// draw line strip
		gl.drawArrays(gl.LINE_STRIP, 0, nVertices);
	};
}


Comments