Hold the text to see the magic !!!
Created
June 19, 2015 17:13
-
-
Save whizkydee/91bd0daa6ee8699e611b to your computer and use it in GitHub Desktop.
Hold Me
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body onload="init()" onresize="windowResize()"> | |
<div style="position:relative;top:250px;z-index:1;-moz-user-select: none;-khtml-user-select: none; | |
user-select: none;"> | |
<center>Hold me.</center> | |
</div> | |
<div style="z-index:4; position:absolute; top:0; left:0"> | |
<canvas id="canvas"></canvas> | |
</div> | |
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var g; | |
var anvas; | |
var width = window.innerWidth; | |
var height = window.innerHeight; | |
var windowHalfX = window.innerWidth / 2; | |
var windowHalfY = window.innerHeight / 2; | |
var mouseX = 0; | |
var mouseY = 0; | |
var pmouseX = 0; | |
var pmouseY = 0; | |
var mousePressed = false; | |
var drawRate = 6; | |
var frameCount = 0; | |
var PI = Math.PI; | |
var TWO_PI = 2 * Math.PI; | |
var HALF_PI = Math.PI * 0.5; | |
function init() { | |
canvas = document.getElementById('canvas'); | |
canvas.width = width; | |
canvas.height = height; | |
g = canvas.getContext('2d'); | |
g.setTransform(1, 0, 0, 1, 0, 0); | |
document.addEventListener('mousemove', onDocumentMouseMove, false); | |
document.addEventListener('mousedown', onDocumentMouseDown, false); | |
document.addEventListener('mouseup', onDocumentMouseUp, false); | |
document.addEventListener('keydown', onDocumentKeyDown, false); | |
setup(); | |
drawInternal(); | |
} | |
function windowResize() { | |
// width = window.innerWidth ; | |
// height = window.innerHeight ; | |
// canvas.width = width; | |
// canvas.height = height; | |
g.setTransform(1, 0, 0, 1, 0, 0); | |
} | |
function onDocumentMouseMove(event) { | |
mouseX = event.clientX - canvas.offsetLeft; | |
mouseY = event.clientY - canvas.offsetTop; | |
} | |
function onDocumentMouseDown(event) { | |
mousePressed = true; | |
mousePressedEvent(); | |
} | |
function onDocumentMouseUp(event) { | |
mousePressed = false; | |
} | |
function onDocumentKeyDown(event) { | |
//setup(); | |
} | |
function drawInternal() { | |
draw(); | |
setTimeout('drawInternal()', drawRate); | |
pmouseX = mouseX; | |
pmouseY = mouseY; | |
frameCount++; | |
} | |
function clear() { | |
g.clearRect(0, 0, width, height); | |
} | |
function line(x1, y1, x2, y2) { | |
g.beginPath(); | |
g.moveTo(x1, y1); | |
g.lineTo(x2, y2); | |
g.closePath(); | |
g.stroke(); | |
} | |
function fillStrokeCircle(x, y, radius) { | |
if (radius <= 0) | |
radius = 0; | |
g.beginPath(); | |
g.arc(x, y, radius, 0, TWO_PI, true); | |
g.closePath(); | |
g.fill(); | |
g.stroke(); | |
} | |
function fillCircle(x, y, radius) { | |
if (radius <= 0) | |
radius = 0; | |
g.beginPath(); | |
g.arc(x, y, radius, 0, TWO_PI, true); | |
g.closePath(); | |
g.fill(); | |
} | |
function strokeCircle(x, y, radius) { | |
if (radius <= 0) | |
radius = 0; | |
g.beginPath(); | |
g.arc(x, y, radius, 0, TWO_PI, true); | |
g.stroke(); | |
} | |
function dist(ax, ay, bx, by) { | |
var dx = bx - ax; | |
dy = by - ay; | |
return Math.sqrt(dx * dx + dy * dy + dz * dz); | |
} | |
var currentRandom = Math.random; | |
// Pseudo-random generator | |
function Marsaglia(i1, i2) { | |
// from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c | |
var z = i1 || 362436069, | |
w = i2 || 521288629; | |
var nextInt = function() { | |
z = (36969 * (z & 65535) + (z >>> 16)) & 0xFFFFFFFF; | |
w = (18000 * (w & 65535) + (w >>> 16)) & 0xFFFFFFFF; | |
return (((z & 0xFFFF) << 16) | (w & 0xFFFF)) & 0xFFFFFFFF; | |
}; | |
this.nextDouble = function() { | |
var i = nextInt() / 4294967296; | |
return i < 0 ? 1 + i : i; | |
}; | |
this.nextInt = nextInt; | |
} | |
Marsaglia.createRandomized = function() { | |
var now = new Date(); | |
return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF); | |
}; | |
// Noise functions and helpers | |
function PerlinNoise(seed) { | |
var rnd = seed !== undefined ? new Marsaglia(seed) : Marsaglia.createRandomized(); | |
var i, j; | |
// http://www.noisemachine.com/talk1/17b.html | |
// http://mrl.nyu.edu/~perlin/noise/ | |
// generate permutation | |
var p = new Array(512); | |
for (i = 0; i < 256; ++i) { | |
p[i] = i; | |
} | |
for (i = 0; i < 256; ++i) { | |
var t = p[j = rnd.nextInt() & 0xFF]; | |
p[j] = p[i]; | |
p[i] = t; | |
} | |
// copy to avoid taking mod in p[0]; | |
for (i = 0; i < 256; ++i) { | |
p[i + 256] = p[i]; | |
} | |
function grad3d(i, x, y, z) { | |
var h = i & 15; // convert into 12 gradient directions | |
var u = h < 8 ? x : y, | |
v = h < 4 ? y : h === 12 || h === 14 ? x : z; | |
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v); | |
} | |
function grad2d(i, x, y) { | |
var v = (i & 1) === 0 ? x : y; | |
return (i & 2) === 0 ? -v : v; | |
} | |
function grad1d(i, x) { | |
return (i & 1) === 0 ? -x : x; | |
} | |
function lerp(t, a, b) { | |
return a + t * (b - a); | |
} | |
this.noise3d = function(x, y, z) { | |
var X = Math.floor(x) & 255, | |
Y = Math.floor(y) & 255, | |
Z = Math.floor(z) & 255; | |
x -= Math.floor(x); | |
y -= Math.floor(y); | |
z -= Math.floor(z); | |
var fx = (3 - 2 * x) * x * x, | |
fy = (3 - 2 * y) * y * y, | |
fz = (3 - 2 * z) * z * z; | |
var p0 = p[X] + Y, | |
p00 = p[p0] + Z, | |
p01 = p[p0 + 1] + Z, | |
p1 = p[X + 1] + Y, | |
p10 = p[p1] + Z, | |
p11 = p[p1 + 1] + Z; | |
return lerp(fz, | |
lerp(fy, lerp(fx, grad3d(p[p00], x, y, z), grad3d(p[p10], x - 1, y, z)), | |
lerp(fx, grad3d(p[p01], x, y - 1, z), grad3d(p[p11], x - 1, y - 1, z))), | |
lerp(fy, lerp(fx, grad3d(p[p00 + 1], x, y, z - 1), grad3d(p[p10 + 1], x - 1, y, z - 1)), | |
lerp(fx, grad3d(p[p01 + 1], x, y - 1, z - 1), grad3d(p[p11 + 1], x - 1, y - 1, z - 1)))); | |
}; | |
this.noise2d = function(x, y) { | |
var X = Math.floor(x) & 255, | |
Y = Math.floor(y) & 255; | |
x -= Math.floor(x); | |
y -= Math.floor(y); | |
var fx = (3 - 2 * x) * x * x, | |
fy = (3 - 2 * y) * y * y; | |
var p0 = p[X] + Y, | |
p1 = p[X + 1] + Y; | |
return lerp(fy, | |
lerp(fx, grad2d(p[p0], x, y), grad2d(p[p1], x - 1, y)), | |
lerp(fx, grad2d(p[p0 + 1], x, y - 1), grad2d(p[p1 + 1], x - 1, y - 1))); | |
}; | |
this.noise1d = function(x) { | |
var X = Math.floor(x) & 255; | |
x -= Math.floor(x); | |
var fx = (3 - 2 * x) * x * x; | |
return lerp(fx, grad1d(p[X], x), grad1d(p[X + 1], x - 1)); | |
}; | |
} | |
// these are lifted from Processing.js | |
// processing defaults | |
var noiseProfile = { | |
generator: undefined, | |
octaves: 4, | |
fallout: 0.5, | |
seed: undefined | |
}; | |
function noise(x, y, z) { | |
if (noiseProfile.generator === undefined) { | |
// caching | |
noiseProfile.generator = new PerlinNoise(noiseProfile.seed); | |
} | |
var generator = noiseProfile.generator; | |
var effect = 1, | |
k = 1, | |
sum = 0; | |
for (var i = 0; i < noiseProfile.octaves; ++i) { | |
effect *= noiseProfile.fallout; | |
switch (arguments.length) { | |
case 1: | |
sum += effect * (1 + generator.noise1d(k * x)) / 2; | |
break; | |
case 2: | |
sum += effect * (1 + generator.noise2d(k * x, k * y)) / 2; | |
break; | |
case 3: | |
sum += effect * (1 + generator.noise3d(k * x, k * y, k * z)) / 2; | |
break; | |
} | |
k *= 2; | |
} | |
return sum; | |
}; | |
function Worm(x, y) { | |
this.x = x; | |
this.y = y; | |
this.lx = x; | |
this.ly = y; | |
this.heading = Math.sin(frameCount * 0.083) * PI;; | |
this.rotation = Math.random() * (PI / (Math.random() * 70)); | |
this.rate = 0; | |
this.maxLength = 15 + (noise(frameCount * 0.0025, frameCount * 0.1) * 15); | |
this.detail = 2; | |
this.thickness = 3; | |
this.thicknessTarget = 5 + Math.random() * 10; | |
var cIndex = parseInt(Math.random() * colors.length); | |
this.c = colors[cIndex]; | |
this.life = 30 + Math.random() * 120; | |
this.segments = new Array(); | |
this.ooo = true; | |
this.counter = noise(frameCount * 0.1, frameCount * .1); | |
this.update = function() { | |
this.life--; | |
if (this.life > 0) { | |
this.thickness += (this.thicknessTarget - this.thickness) * 0.1; | |
this.thickness += 0.1; | |
if (this.thickness > this.thicknessTarget) | |
this.thickness = this.thicknessTarget; | |
this.heading += this.rotation; | |
this.rate = Math.cos(this.counter / 200.0) * (10 + noise(frameCount * 0.05) * 10); | |
this.rotation = Math.sin(this.counter / this.rate) * (this.segments.length + 1) * 0.010; | |
this.counter++; | |
var speedMod = (this.segments.length * this.segments.length * this.segments.length) * 0.0015 * this.thickness / this.thicknessTarget; | |
var totalSpeed = (this.detail + speedMod); | |
var nx = Math.cos(this.heading) * totalSpeed; | |
var ny = Math.sin(this.heading) * totalSpeed; | |
this.walk(nx, ny); | |
} else { | |
if (this.segments.length > 1) { | |
this.segments.pop(); | |
} else { | |
this.thickness *= 0.95; | |
this.thickness -= 0.2; | |
if (this.thickness < 0.1) | |
this.ooo = true; | |
return; | |
} | |
} | |
this.ooo = true; | |
for (var i = 0; i < this.segments.length; i++) { | |
var segment = this.segments[i]; | |
if (segment.ooo() == false) { | |
this.ooo = false; | |
break; | |
} | |
} | |
} | |
this.walk = function(nx, ny) { | |
this.lx = this.x; | |
this.ly = this.y; | |
this.x += nx; | |
this.y += ny; | |
var newSegment = new Segment(this.lx, this.ly, this.x, this.y, this.thickness); | |
this.segments.unshift(newSegment); | |
if (this.segments.length > 1) | |
this.segments[this.segments.length - 1].smoothAgainst(this.segments[this.segments.length - 2]); | |
if (this.segments.length >= this.maxLength) { | |
this.segments.pop(); | |
} | |
} | |
} | |
function Segment(x1, y1, x2, y2, thickness) { | |
this.x1 = x1; | |
this.y1 = y1; | |
this.x2 = x2; | |
this.y2 = y2; | |
this.thickness = thickness; | |
var angle = Math.atan2(y2 - y1, x2 - x1); | |
this.lAngle = angle - HALF_PI; | |
var lDeltaX = Math.cos(this.lAngle) * thickness; | |
var lDeltaY = Math.sin(this.lAngle) * thickness; | |
this.leftX1 = x1 + lDeltaX; | |
this.leftY1 = y1 + lDeltaY; | |
this.leftX2 = x2 + lDeltaX; | |
this.leftY2 = y2 + lDeltaY; | |
this.rAngle = angle + HALF_PI; | |
var rDeltaX = Math.cos(this.rAngle) * thickness; | |
var rDeltaY = Math.sin(this.rAngle) * thickness; | |
this.rightX1 = x1 + rDeltaX; | |
this.rightY1 = y1 + rDeltaY; | |
this.rightX2 = x2 + rDeltaX; | |
this.rightY2 = y2 + rDeltaY; | |
this.smoothAgainst = function(last) { | |
this.leftX1 = last.leftX2 = (last.leftX2 + this.leftX1) * 0.5; | |
this.leftY1 = last.leftY2 = (last.leftY2 + this.leftY1) * 0.5; | |
this.rightX1 = last.rightX2 = (last.rightX2 + this.rightX1) * 0.5; | |
this.rightY1 = last.rightY2 = (last.rightY2 + this.rightY1) * 0.5; | |
} | |
this.ooo = function() { | |
if (this.x1 < 0 || this.y1 < 0 || this.x1 > width || this.y1 > height || | |
this.x2 < 0 || this.y2 < 0 || this.x2 > width || this.y2 > height) | |
return true; | |
else | |
return false; | |
} | |
} | |
var worms; | |
var colors = []; | |
colors[0] = '#2cd9fe'; | |
colors[1] = '#2cfecf'; | |
colors[2] = '#373fdf'; | |
colors[3] = '#88fe1f'; | |
colors[4] = '#48d6ff'; | |
colors[5] = '#b3fcff'; | |
colors[6] = '#f76cad'; | |
colors[7] = '#505083'; | |
colors[8] = '#113a7e'; | |
colors[9] = '#014050'; | |
colors[10] = '#ccf3ef'; | |
colors[11] = '#009437'; | |
colors[12] = '#8fb300'; | |
function setup() { | |
worms = new Array(); | |
} | |
function draw() { | |
clear(); | |
for (var w = 0; w < worms.length; w++) { | |
var worm = worms[w]; | |
worm.update(); | |
g.fillStyle = worm.c; | |
g.lineWidth = 2; | |
g.strokeStyle = '#ffffff'; | |
if (worm.segments.length > 1) { | |
g.beginPath(); | |
g.moveTo(worm.segments[0].leftX1, worm.segments[0].leftY1); | |
for (var i = 0; i < worm.segments.length; i++) { | |
var segment = worm.segments[i]; | |
g.lineTo(segment.leftX1, segment.leftY1); | |
} | |
g.lineTo(worm.segments[worm.segments.length - 1].rightX1, worm.segments[worm.segments.length - 1].rightY1); | |
for (var i = worm.segments.length - 1; i >= 0; i--) { | |
var segment = worm.segments[i]; | |
g.lineTo(segment.rightX1, segment.rightY1); | |
} | |
g.closePath(); | |
// g.stroke(); | |
g.fill(); | |
g.stroke(); | |
} | |
g.strokeStyle = '#ffffff'; | |
if (worm.segments.length >= 1) { | |
var x = worm.segments[0].x1; | |
var y = worm.segments[0].y1; | |
var thickness = worm.segments[0].thickness; | |
if (worm.thickness < thickness) | |
thickness = worm.thickness; | |
if (thickness <= 0) | |
thickness = 0.000001; | |
g.beginPath(); | |
g.arc(x, y, thickness, worm.segments[0].lAngle, worm.segments[0].rAngle, false); | |
g.closePath(); | |
//g.fill(); | |
g.stroke(); | |
var xEnd = worm.segments[worm.segments.length - 1].x1; | |
var yEnd = worm.segments[worm.segments.length - 1].y1; | |
thickness = worm.segments[worm.segments.length - 1].thickness; | |
if (worm.thickness < thickness) | |
thickness = worm.thickness; | |
if (thickness <= 0) | |
thickness = 0.000001; | |
g.beginPath(); | |
g.arc(xEnd, yEnd, thickness, worm.segments[worm.segments.length - 1].lAngle, worm.segments[worm.segments.length - 1].rAngle, true); | |
g.closePath(); | |
//g.fill(); | |
g.stroke(); | |
thickness = worm.thickness - 0.6; | |
if (worm.thickness < thickness) | |
thickness = worm.thickness; | |
fillCircle(worm.segments[0].x1, worm.segments[0].y1, thickness); | |
thickness = worm.segments[worm.segments.length - 1].thickness - 0.6; | |
if (worm.thickness < thickness) | |
thickness = worm.thickness; | |
fillCircle(worm.segments[worm.segments.length - 1].x1, worm.segments[worm.segments.length - 1].y1, thickness); | |
if (worm.life > 0) { | |
g.fillStyle = "#FFFFFF"; | |
fillCircle(worm.segments[0].x1, worm.segments[0].y1, thickness * 0.72); | |
} | |
} | |
} | |
for (var w = 0; w < worms.length; w++) { | |
var worm = worms[w]; | |
if (worm.ooo) { | |
worms.splice(w, 1); | |
w--; | |
} | |
} | |
if (frameCount % 2 == 0 && mousePressed && worms.length < 50) { | |
var direction = Math.atan2(pmouseY - mouseY, pmouseX - mouseX) + PI; | |
var newWorm = new Worm(mouseX, mouseY); | |
worms.push(newWorm); | |
if (mouseX != pmouseX && mouseY != pmouseY) | |
newWorm.heading = direction; | |
} | |
} | |
function mousePressedEvent() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url(http://fonts.googleapis.com/css?family=Lobster); | |
body { | |
background: #222222; | |
font-family:'Lobster', serif; | |
font-size: 72px; | |
color: #FFFFFF; | |
margin: 0px; | |
overflow: hidden; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment