``````- 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``````
``````@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 & {