Toggle navigation
Sign Up
Log In
Explore
Works
Folders
Tools
Collections
Artists
Groups
Groups
Topics
Tasks
Tasks
Jobs
Teams
Jobs
Recommendation
More Effects...
JS
// Code never lies, comments sometimes do. "use strict"; { // particles class class Particle { constructor(i, x, y, r) { this.a = 0; this.i = i; this.x = x; this.y = y; this.vx = 0.0; this.vy = 0.0; this.r = r | 0; } move(img) { this.vy += 0.1; this.x += this.vx; this.y += this.vy; // collisions for (const b of plots) { const dx = b.x - this.x; const dy = b.y - this.y; const sd = dx * dx + dy * dy; const r = this.r + b.r; if (sd < r * r) { const dist = Math.sqrt(sd); const dz = r - dist; const sx = dx / dist * dz; const sy = dy / dist * dz; this.vx -= sx * 1.2; this.vy -= sy * 1.2; this.x -= sx; this.y -= sy; } } // reset particle if (this.y > canvas.height + this.r) { this.x = canvas.width * 0.5 + 40 * (Math.random() - Math.random()); this.y = -2 * plots[0].r - this.r - 100 * Math.random(); this.vx = 0; this.vy = 20 * Math.random(); } else { // draw particle canvas.drawImage(img, this.x - this.r, this.y - this.r, 2 * this.r, 2 * this.r); } } // turbine draw(img, va) { this.r = canvas.size * 0.05 + 0.8 * Math.abs(canvas.height * 0.5 - pointer.y); this.a += va; const a = this.a + ((2 * Math.PI / 5) * this.i); this.x = canvas.width * 0.5 + 2.2 * this.r * Math.cos(a); this.y = canvas.height * 0.5 + 2.2 * this.r * Math.sin(a); canvas.drawImage(img, this.x - this.r, this.y - this.r, 2 * this.r, 2 * this.r); } } // 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; attribute vec2 aPosition; uniform mat3 uMatrix; varying vec2 vTexcoord; void main() { gl_Position = vec4(uMatrix * vec3(aPosition, 1), 1); vTexcoord = aPosition; } ` ); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource( fragmentShader, ` precision highp float; varying vec2 vTexcoord; uniform sampler2D texture; void main() { gl_FragColor = texture2D(texture, vTexcoord); } ` ); gl.compileShader(fragmentShader); const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); // webGL variables this.position = gl.getAttribLocation(program, "aPosition"); gl.enableVertexAttribArray(this.position); this.umatrix = gl.getUniformLocation(program, "uMatrix"); this.positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW ); gl.vertexAttribPointer(this.position, 2, gl.FLOAT, false, 0, 0); this.matrix = new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 1]); gl.useProgram(program); // canvas resize this.resize(); window.addEventListener("resize", () => this.resize(), false); return gl; }, createTexture(src) { const gl = this.gl; const texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src); return texture; }, drawImage(texture, x, y, width, height) { this.gl.bindTexture(this.gl.TEXTURE_2D, texture); const m = this.matrix; m[0] = this.sx * width; m[4] = this.sy * height; m[6] = x * this.sx - 1; m[7] = y * this.sy + 1; this.gl.uniformMatrix3fv(this.umatrix, false, m); this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); }, resize() { this.width = this.elem.width = this.elem.offsetWidth; this.height = this.elem.height = this.elem.offsetHeight; this.sx = 2 / this.width; this.sy = -2 / this.height; this.size = Math.min(this.width, this.height); this.gl.viewport( 0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight ); } }; const pointer = { init(canvas) { this.va = 0; this.px = 0; this.x = 100; this.y = canvas.height * 0.3; document.addEventListener( "touchstart", e => { e.preventDefault(); this.x = e.targetTouches[0].clientX | 0; this.y = e.targetTouches[0].clientY | 0; this.px = this.x; } ); ["mousemove", "touchmove"].forEach((event, touch) => { document.addEventListener( event, e => { if (touch) { e.preventDefault(); this.x = e.targetTouches[0].clientX | 0; this.y = e.targetTouches[0].clientY | 0; } else { this.x = e.clientX | 0; this.y = e.clientY | 0; } }, false ); }); } }; // draw disks const shape = (size, color) => { const shape = document.createElement("canvas"); shape.width = shape.height = (size + 2) | 0; const ctx = shape.getContext("2d"); ctx.fillStyle = color; ctx.arc(size / 2 + 1, size / 2 + 1, size / 2, 0, 2 * Math.PI); ctx.fill(); return canvas.createTexture(shape); }; // init webGL canvas const gl = canvas.init({ alpha: true, stencil: false, antialias: false, depth: false }); // additive blending "lighter" gl.blendFunc(gl.ONE, gl.ONE); gl.enable(gl.BLEND); // init pointer pointer.init(canvas); // create textures const particleTexture = shape(1.25 * canvas.size * 0.1, "#631"); const plotTexture = shape(canvas.size * 0.4, "#000"); // create particles const particles = Array.from( { length: 3000 }, (v, i) => new Particle( 0, canvas.width * 0.5 + 40 * (Math.random() - Math.random()), -i * 0.5, (Math.random() + 0.25) * canvas.size * 0.05 ) ); // create turbine const plots = Array.from( { length: 5 }, (v, i) => new Particle(i, 0, 0, canvas.size * 0.2) ); // main animation loop const run = () => { requestAnimationFrame(run); pointer.va += (pointer.x - pointer.px) * 0.0002; if (Math.abs(pointer.va) > 0.01) pointer.va *= 0.99; for (const p of particles) p.move(particleTexture); for (const b of plots) b.draw(plotTexture, pointer.va); pointer.px = pointer.x; }; run(); }
CSS
html, body { position: absolute; overflow: hidden; margin: 0; padding: 0; width: 100%; height: 100%; background:#000; touch-action: none; content-zooming: none; } canvas { position: absolute; width: 100%; height: 100%; background:#191919; background: radial-gradient(circle at center, rgba(60,70,100,1) 0%,rgba(0,0,0,1) 60%); }
HTML
Join Effecthub.com
Working with Global Gaming Artists and Developers!
Login
Sign Up
Or Login with Your Email Address:
Email
Password
Remember
Or Sign Up with Your Email Address:
Your Email
This field must contain a valid email
Set Password
Password should be at least 1 character
Stay informed via email