Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                //- number of dimensions
- var nd = 3;
//- number of cubes per dimension
- var nc = 5;
//- total number of cubes
- var n = Math.pow(nc, nd);

.assembly
	.rotor
		while n--
			- var nf = 6; //- number of cube faces
			.cube
				while nf--
					.cube__face
              
            
!

CSS

              
                @import 'compass/css3';

$nc: 5; // cubes per dimension same as in Jade
$nf: 6; // number of cube faces
$n4gon: 4; // number of square edges/ vertices
$l: 1.5em; // cube edge length
$f: 2 1.5; // multiplying factors
$t: .65s; // animation duration

$m: .5*($nc - 1); // constant, compute here
$hu: 360/($nc + 1); // hue unit
// base angle corresponding to square edge
$ba4gon: 360deg/$n4gon;
$tu: 2*$t/pow($m, 3); // delay unit

body {
	overflow: hidden;
	margin: 0;
	height: 100vh;
	perspective: 40em;
	background: #111;
	text-align: center;
	
	&:before {
		color: #eee;
		font: 2.5em/ 2 satisfy, cursive;
		content: 'drag me!'
	}
}

div {
	position: absolute;
	// allows nesting 3D transformed elements
	transform-style: preserve-3d;
}

.assembly {
	top: 50%; left: 50%;
	transform: rotateX(-22.5deg) rotateY(-30deg)
}

.cube {
	animation: a $t cubic-bezier(.65, .05, .35, 1) infinite alternate;
	
	.drag & { animation-play-state: paused; }
	
	@for $i0 from 0 to $nc {
		$j0: $i0 - $m;
		$k0: pow($j0, 2);
		$xi: nth($f, 1)*$j0*$l; // initial x coord
		$xf: nth($f, 2)*$xi; // final x coord
		$r: ($nc - $i0 - .5)*$hu; // red component
		
		@for $i1 from 0 to $nc {
			$j1: $i1 - $m;
			$k1: pow($j1, 2);
			$yi: nth($f, 1)*$j1*$l; // initial y coord
			$yf: nth($f, 2)*$yi; // final y coord
			$g: ($i1 + .5)*$hu; // green component
			
			@for $i2 from 0 to $nc {
				$j2: $i2 - $m;
				$k2: pow($j2, 2);
				$zi: nth($f, 1)*$j2*$l; // initial z coord
				$zf: nth($f, 2)*$zi; // final z coord
				$b: ($nc - $i2 - .5)*$hu; // blue component
				$dt: sqrt($k0 + $k1 + $k2)*$tu;
				// current cube index
				$idx: $i0*pow($nc, 2) + $i1*$nc + $i2 + 1;
				
				&:nth-child(#{$idx}) {
					transform: translate3d($xi, $yi, $zi);
					color: rgb($r, $g, $b);
					animation-name: a#{$idx};
					animation-delay: -$dt;
				}
				
				@keyframes a#{$idx} {
					to { transform: translate3d($xf, $yf, $zf); }
				}
			}
		}
	}
	
	&__face {
		box-sizing: border-box;
		margin: -.5*$l;
		border: solid 1px #ccc;
		width: $l; height: $l;
		backface-visibility: hidden;
		background: currentcolor;
		
		@for $i from 0 to $nf {
			&:nth-child(#{$i + 1}) {
				transform: 
					if($i < $n4gon, rotateY($i*$ba4gon), 
						rotateX(pow(-1, $i)*$ba4gon)) 
					translateZ(.5*$l);
			}
		}
	}
}
              
            
!

JS

              
                const sel = '.rotor' /* selector */, 
			/* the rotor element */
			_r = document.querySelector(sel), 
			/* a new style element */
			_s = document.createElement('style'), 
			dcls = 'drag' /* drag signalling class name */;

let drag = false, x0 = null, y0 = null;

let getE = function(ev) {
	return ev.touches ? ev.touches[0] : ev;
};

let lock = function(ev) {
	let e = getE(ev);
	
	drag = true;
	x0 = e.clientX;
	y0 = e.clientY;
	_r.classList.add(dcls);
};

let act = function(ev) {
	if(drag) {
		let e = getE(ev), 
				x = e.clientX, y = e.clientY, 
				dx = x - x0, dy = y - y0, 
				d = Math.hypot(dx, dy);
		
		if(d) {
			let i = (-dy/d).toFixed(5) /* x comp of rot axis */, 
					j = (dx/d).toFixed(5) /* y comp of rot axis */, 
					a = (.2*d).toFixed(2) /* rotation angle in deg */, 
					c = 'rotate3d(' + [i, j, 0, a] + 'deg)' + 
							getComputedStyle(_r).transform 
							.replace('none', ''); /* transform chain */
			_s.textContent = sel + '{transform:' + c + ';}'
		}
		
		x0 = x;
		y0 = y;
	}
};

let release = function() {
	if(drag) {
		drag = false;
		x0 = y0 = null;
		_r.classList.remove(dcls); // OK
	}
};

document.body.appendChild(_s);

addEventListener('mousedown', lock, false);
addEventListener('touchstart', lock, false);

addEventListener('mousemove', act, false);
addEventListener('touchmove', act, false);

addEventListener('mouseup', release, false);
addEventListener('touchend', release, false);
              
            
!
999px

Console