- var n4hedron = 4; //- faces of tetrahedron
- var n3gon = 3; // vertices of triangle
- var r = .375; //- circumradius
- var rr = .05; //- vertex rounding radius
- var obb = 'objectBoundingBox';
- var p = 3;
- var f = Math.pow(10, 3);

//-get actual triangle
mixin roundpoly(n)
	- var ca = 2*Math.PI/n; //- central angle
	- var d = ''; //- init path data
	- var va = (n - 2)*Math.PI/n;
	- var oa = .5*(Math.PI - va);
	//- generate triangle coords in loop
	- for(var i = 0; i < n; i++) {
		- var a = i*ca - .5*Math.PI;
		- var x = .5 + r*Math.cos(a);
		- var y = .5 + r*Math.sin(a);
		//- now make triangle rounded
		- var sa = a - oa; //- start angle
		- var sx = Math.round(f*(x + rr*Math.cos(sa)))/f;
		- var sy = Math.round(f*(y + rr*Math.sin(sa)))/f;
		- d += (i?'L':'M') + sx + ' ' + sy;
		- var ea = a + oa; //- start angle
		- var ex = Math.round(f*(x + rr*Math.cos(ea)))/f;
		- var ey = Math.round(f*(y + rr*Math.sin(ea)))/f;
		- d += 'A' + rr + ' ' + rr + ' 0 0 1 ';
		- d += ex + ' ' + ey;
	- }
	clipPath(id=`o${n}` clipPathUnits=obb)
		path(d=d)

svg(width='0' height='0')
	+roundpoly(n3gon)

.a3d
	.switcher
		.s3d
			- var n = n4hedron*n3gon + 1;
			while n--
				.s3gon
		.s3d.s4hedron
			while n3gon--
				.s3gon

p also check out 
	a(href='https://codepen.io/thebabydino/details/LNEbOz/' target='_blank') my previous pyramorphix demo
View Compiled
@import 'compass/css3';

$l: 45vmin;
$t: 1.5s;
$p: 20%;

$n3gon: 3;
$ca3gon: 360deg/$n3gon;
$rc3gon: .5*$l/sin(.5*$ca3gon);
$va3gon: ($n3gon - 2)*180deg/$n3gon;
$h3gon: $l*sin($va3gon);

$n: $n3gon + 1;

$n4hedron: 4;
$ax4hedron: asin(.5*$l/$h3gon)*180deg/pi();
$va4hedron: 90deg - 2*$ax4hedron;
$ri4hedron: $rc3gon*tan($va4hedron);

%mid { background: #ebe3aa; }

body {
	overflow: hidden;
	height: 100vh;
	perspective: 32em;
	background: #5d4157;
}

div {
	position: absolute;
	top: 50%; left: 50%;
	transform-style: preserve-3d;
}

.a3d { animation: r 4*$t linear -2.5*$t infinite; }

@keyframes r { to { transform: rotateY(1turn); } }

.switcher { animation: s $n4hedron*$t steps(1) infinite; }

@keyframes s {
	25% { transform: rotateX(.5turn) rotateY(.25turn); }
	50% { transform: rotateY(.5turn); }
	75% { transform: rotateZ(.5turn) rotateY(.25turn); }
}

.s4hedron { animation: rv $t cubic-bezier(.68, -.56, .26, 1.56) infinite; }

@keyframes rv {
	0%, #{$p} { transform: none; }
	#{100% - $p}, 100% { transform: rotate3d(sqrt(2), 1, 0, $ca3gon); }
}

.s3gon {
	margin: -.5*$rc3gon;
	width: $rc3gon; height: $rc3gon;
	backface-visibility: hidden;
	background: #888;
	-webkit-clip-path: url(#o3);
	clip-path: url(#o3);
	
	// position on tetrahedron
	@for $i from 0 to $n4hedron {
		$k: floor($i/2);
		
		@for $j from 0 to $n {
			$az: (($j + $i)%$n3gon + .5)*$ca3gon;
			$comp-idx: 1;
			$idx: min($i, 1)*($n3gon + 1) /* 1st = base face */
				+ max($i - 1, 0)*$n3gon /* next faces */ 
				+ $j + 1 /* currentface */;
			
			@if $i > 0 and $j == $n3gon {
				$idx: $i;
				$comp-idx: 2;
			}
			
			.s3d:nth-child(#{$comp-idx}) &:nth-child(#{$idx}) {
				transform: 
					/* distribute in 3D */
					if($k > 0, rotate(.5turn), ())
					rotateY(($k + 2*($i%2) - 1)*.25turn)
					rotateX($ax4hedron) 
					translateZ($ri4hedron) 
					/* distribute in 2D */
					if($j > 0, rotate($az) translateY(-.5*$rc3gon), ());
				@if $j == 0 { @extend %mid; }
			}
		}
	}
	
	.s4hedron & {
		animation: fade $t ease-in-out infinite;
	}
}

@keyframes fade { #{$p}, #{100% - $p} { background: #a8caba; } }
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.