canvas#canvas

.infos
	p
		|Experiment by 
		a(href="http://www.arnaudrocca.fr", target="_blank") Arnaud Rocca
View Compiled
html, body
	width 100%
	height 100%
	margin 0
	padding 0
	overflow hidden
	background #8DF
	background-image radial-gradient(ellipse farthest-corner at center top, #FFF 0%, #8DF 100%)
	background-repeat no-repeat
	background-attachment fixed
	font-size 10px

canvas
	position absolute
	display block
	
.infos
	position absolute
	margin 0
	bottom 10px
	right 10px
	color #000
	font-family sans-serif
	font-weight 400
	font-size 1rem
	line-height .5rem
	
	a
		text-decoration none
		color #07C
		transition .3s
		
		&:hover
			color #2AF
View Compiled
window.onload = function() {

	'use strict';

	var canvas = document.getElementById('canvas'),
		ctx = canvas.getContext('2d'),
		width = canvas.width = window.innerWidth,
		height = canvas.height = window.innerHeight,
		min = 1.25,
		timer = 0,
		deltaTime = 0,
		lastTime = Date.now();

	ctx.translate(width / 2, 100);

	window.onresize = function() {
		width = canvas.width = window.innerWidth;
		height = canvas.height = window.innerHeight;
		ctx.translate(width / 2, 100);
	};

	update();
	
	/**
	 * update
	 */
	function update() {

		deltaTime = Date.now() - lastTime;
		lastTime = Date.now();
		timer += options.speed * deltaTime / 1000;

		ctx.clearRect(-width / 2, -100, width, height);

		for (var x = 0; x < options.mapSize; x++) {
			for (var y = 0; y < options.mapSize; y++) {
				switch(options.direction) {
					case 'x':
						var z = min + Math.sin(timer + Math.sin((y - x) * options.strength / 10));
						break;
					case 'y':
						var z = min + Math.cos(timer + Math.cos((x + y) * options.strength / 10));
						break;
					default:
						break;
				}
				drawBlock(x, y, z);
			}
		}

		requestAnimationFrame(update);

	}

	/**
	 * drawBlock
	 * - Draw an isometric block
	 *
	 * @param {number} x - The position on X
	 * @param {number} y - The position on Y
	 * @param {number} z - The height of the block
	 */
	function drawBlock(x, y, z) {

		var top   = '#2AF',
			right = '#19E',
			left  = '#07C';

		ctx.save();
		ctx.translate((x - y) * options.width / 2, (x + y) * options.height / 2);

		// Top
		ctx.beginPath();
		ctx.moveTo(0, -z * options.height);
		ctx.lineTo(options.width / 2, options.height / 2 - z * options.height);
		ctx.lineTo(0, options.height - z * options.height);
		ctx.lineTo(-options.width / 2, options.height / 2 - z * options.height);
		ctx.closePath();
		ctx.fillStyle = top;
		ctx.fill();
		ctx.strokeStyle = left;
		ctx.stroke();

		// Left
		ctx.beginPath();
		ctx.moveTo(-options.width / 2, options.height / 2 - z * options.height);
		ctx.lineTo(0, options.height - z * options.height);
		ctx.lineTo(0, options.height);
		ctx.lineTo(-options.width / 2, options.height / 2);
		ctx.closePath();
		ctx.fillStyle = left;
		ctx.fill();
		ctx.strokeStyle = left;
		ctx.stroke();

		// Right
		ctx.beginPath();
		ctx.moveTo(options.width / 2, options.height / 2 - z * options.height);
		ctx.lineTo(0, options.height - z * options.height);
		ctx.lineTo(0, options.height);
		ctx.lineTo(options.width / 2, options.height / 2);
		ctx.closePath();
		ctx.fillStyle = right;
		ctx.fill();
		ctx.strokeStyle = right;
		ctx.stroke();

		ctx.restore();

	}
	
}

// Options
var Options = function() {
	this.mapSize = 12;
	this.width = 50;
	this.height = 25;
	this.speed = 5;
	this.strength = 2;
	this.direction = 'x';
};

var options = new Options(),
		gui = new dat.GUI();
gui.close();

gui.add(options, 'mapSize', 5, 20).step(1);
gui.add(options, 'width', 30, 60);
gui.add(options, 'height', 15, 30);
gui.add(options, 'speed', 1, 10);
gui.add(options, 'strength', 1, 5);
gui.add(options, 'direction', ['x', 'y']);
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5.1/dat.gui.min.js