This is Cornus Ammonis’s new variant on the worms, from here. Click to magnify.
Last active
August 29, 2015 14:02
-
-
Save robinhouston/1b3026425c829cb76398 to your computer and use it in GitHub Desktop.
Worms 2
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Ammonis worms with magnifier</title> | |
<style> | |
body { margin: 0; overflow: hidden; } | |
#canvas { cursor: -webkit-zoom-in; cursor: -moz-zoom-in; cursor: zoom-in; } | |
#canvas.magnifying { cursor: none; } | |
#magnifier { border: 1px solid #333; padding: 8px; position: absolute; width: 400px; height: 400px; top: 0; left: 0; background: white; pointer-events: none; } | |
</style> | |
</head> | |
<body> | |
<script> | |
var W = 256, H = 256, N = W*H; // Tile dimensions | |
var doc = document.documentElement, | |
canvas = document.createElement("canvas"), | |
cx = canvas.getContext("2d"), | |
tile = document.createElement("canvas"), | |
tcx = tile.getContext("2d"), | |
magnifier = document.createElement("canvas"), | |
mcx = magnifier.getContext("2d"), | |
mag_x, mag_y, | |
magnifying = false; | |
// Parameters from https://www.dropbox.com/s/zq81tanm6ndyw6o/worm2.vti | |
var clampMin = -10, | |
clampMax = 10, | |
D_a = 0.001, | |
D_b = 0.004, | |
abClampMin = -100, // Use 100 rather than 50 to get | |
abClampMax = 100, // smaller faster-moving worms. | |
aConst = 0.2, | |
bConst = -0.7, | |
scale = 4; | |
function resizeCanvas() { | |
canvas.width = doc.clientWidth; | |
canvas.height = doc.clientHeight; | |
} | |
function init() { | |
tile.width = W; | |
tile.height = H; | |
canvas.id = "canvas"; | |
magnifier.id = "magnifier"; | |
magnifier.width = magnifier.height = 100; | |
window.addEventListener("resize", function() { | |
resizeCanvas(); | |
drawTiles(); | |
}, false); | |
resizeCanvas(); | |
document.body.appendChild(canvas); | |
canvas.addEventListener("mousedown", mouseDown, false); | |
canvas.addEventListener("mouseup", mouseUp, false); | |
initReactionDiffusion(); | |
startReactionDiffusion(); | |
} | |
function mouseDown(e) { | |
canvas.addEventListener("mousemove", mouseMove, false); | |
document.body.appendChild(magnifier); | |
mouseMove(e); | |
magnifying = true; | |
canvas.className = "magnifying"; | |
} | |
function mouseMove(e) { | |
var s = magnifier.style, | |
x = Math.max(0, Math.min(canvas.width - 418, (e.x || e.clientX) - 200)), | |
y = Math.max(0, Math.min(canvas.height - 418, (e.y || e.clientY) - 200)); | |
s.transform = s.webkitTransform = s.MozTransform = s.OTransform = s.msTransform = | |
"translate(" + x + "px," + y + "px)"; | |
mag_x = Math.max(0, Math.min(canvas.width - 100, (e.x || e.clientX) - 50)); | |
mag_y = Math.max(0, Math.min(canvas.height - 100, (e.y || e.clientY) - 50)); | |
} | |
function mouseUp(e) { | |
canvas.removeEventListener("mousemove", mouseMove); | |
document.body.removeChild(magnifier); | |
magnifying = false; | |
canvas.className = null; | |
} | |
function drawTiles() { | |
renderTile(); | |
cx.fillStyle = cx.createPattern(tile, "repeat"); | |
cx.fillRect(0, 0, canvas.width, canvas.height); | |
if (magnifying) { | |
var x = mag_x % tile.width, | |
y = mag_y % tile.height, | |
w = magnifier.width, | |
h = magnifier.height; | |
mcx.clearRect(0, 0, w, h); | |
mcx.drawImage(canvas, x, y, w, h, 0, 0, w, h); | |
} | |
} | |
var α, β, af, α1, β1, α2, β2, α3, β3, α4, β4, α_temp, β_temp; | |
function initReactionDiffusion() { | |
α = []; β = []; | |
for (var i=0; i<N; i++) { | |
α[i] = Math.random() * (abClampMax - abClampMin) + abClampMin; | |
β[i] = Math.random() * (abClampMax - abClampMin) + abClampMin; | |
} | |
α1 = []; α2 = []; α3 = []; α4 = []; | |
β1 = []; β2 = []; β3 = []; β4 = []; | |
α_temp = []; β_temp = []; | |
} | |
function frame() { | |
rk4(f, 0.5); | |
drawTiles(); | |
af = requestAnimationFrame(frame); | |
} | |
function startReactionDiffusion() { | |
af = requestAnimationFrame(frame); | |
} | |
function renderTile() { | |
var imd = tcx.createImageData(W, H), | |
d = imd.data; | |
for (var i=0; i<N; i++) { | |
var v = ((abClampMax - α[i]) / (abClampMax - abClampMin) * 255)|0; | |
d[4*i + 0] = v; | |
d[4*i + 1] = v; | |
d[4*i + 2] = v; | |
d[4*i + 3] = 0xFF; | |
} | |
tcx.putImageData(imd, 0, 0); | |
} | |
function f(α_in, β_in, c, δα, δβ, δα_out, δβ_out) { | |
var α, β; | |
if (c == 0) { | |
α = α_in; | |
β = β_in; | |
} else { | |
α = α_temp; | |
β = β_temp; | |
for (var i=0; i<N; i++) { | |
α[i] = α_in[i] + c*δα[i]; | |
β[i] = β_in[i] + c*δβ[i]; | |
} | |
} | |
for (var y=0; y<H; y++) { | |
for (var x=0; x<W; x++) { | |
var i = W*y + x, | |
px = (x+W-1)%W, sx = (x+1)%W, | |
py = (y+H-1)%H, sy = (y+1)%H; | |
var laplacian_a = α[W*py+x] + α[W*y+sx] + α[W*sy+x] + α[W*y+px] - 4*α[i], | |
laplacian_b = β[W*py+x] + β[W*y+sx] + β[W*sy+x] + β[W*y+px] - 4*β[i]; | |
δα_out[i] = Math.max(clampMin, Math.min(clampMax, | |
(D_a * (α[i] * α[i] - β[i] * β[i])) + scale * laplacian_b + aConst * β[i] )); | |
δβ_out[i] = Math.max(clampMin, Math.min(clampMax, | |
(D_b * (2 * α[i] * β[i])) - scale * laplacian_a + bConst * α[i] )); | |
} | |
} | |
} | |
// Fourth-order Runge-Kutta method | |
function rk4(f, h) { | |
f(α, β, 0, null, null, α1, β1); | |
f(α, β, h/2, α1, β1, α2, β2); | |
f(α, β, h/2, α2, β2, α3, β3); | |
f(α, β, h, α3, β3, α4, β4); | |
for (var i=0; i<N; i++) { | |
α[i] = Math.max(abClampMin, Math.min(abClampMax, α[i] + (h/6) * (α1[i] + 2*α2[i] + 2*α3[i] + α4[i]) )); | |
β[i] = Math.max(abClampMin, Math.min(abClampMax, β[i] + (h/6) * (β1[i] + 2*β2[i] + 2*β3[i] + β4[i]) )); | |
} | |
} | |
init(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment