- var n_rows = 7, p = [];	

style
	- for(var ridx = 1; ridx < n_rows; ridx++) {
		- var col_lim_inf = n_rows - ridx;
		- var col_lim_sup = n_rows + ridx;
		- var idx_lim_inf = Math.pow(ridx, 2) + 1;
		- var idx_lim_sup = idx_lim_inf + 2*ridx;
		- var a = [[idx_lim_inf], [idx_lim_sup]];
		- var na = a.length;
		- for(var i = 1; i < n_rows - ridx; i++) {
			- for(var j = 0; j < na; j++) {
				- var k = a[j][i - 1] + 2*(i + ridx)
				- a[j].push(k);
			- }
		- }
		- var sel = `.s3gon:nth-child(n + ${idx_lim_inf}):nth-child(-n + ${idx_lim_sup})`
		- if(ridx%2)
			- p.push(sel)
		| #{sel} { --ridx: #{ridx + 1} }
		| .s3gon:nth-child(#{a[0].join('), .s3gon:nth-child(')}) { --cidx: #{col_lim_inf} }
		| .s3gon:nth-child(#{a[1].join('), .s3gon:nth-child(')}) { --cidx: #{col_lim_sup} }
	- }
	| #{p.join(', ')} { --p0: -1 }
.grid(style=`--n-rows: ${n_rows}; --n-cols: ${2*n_rows + 1}; --cidx: ${n_rows}`)
	- for(var ridx = 0; ridx < n_rows; ridx++)
		- for(var cidx = n_rows - ridx; cidx <= n_rows + ridx; cidx++)
			.s3gon
View Compiled
@import 'compass/css3';

@function getPolyPoints(
		$n: 3 /* number of poly vertices */, 
		$oa: -90deg /* angular offset of 1st poly vertex */) {
	
	$ba: 360deg/$n; // base angle corrensponding to 1 poly edge
	$pl: (); // list of points, initially empty
	
	@for $i from 0 to $n {
		$ca: $i*$ba + $oa; // angle current point is at wrt x axis
		$x: calc(50%*(1 + #{cos($ca)})); // x coord of current point
		$y: calc(50%*(1 + var(--p)*#{sin($ca)})); // y coord of current point
		$pl: $pl, $x $y // add current point coords to points list
	}
	
	@return $pl
}

$c: #ff1ead;
$l: 5vmin;
$t: 1s;

$n3gon: 3;
$ba3gon: 360deg/$n3gon;
$rc3gon: .5*$l/sin(.5*$ba3gon);
$dc3gon: 2*$rc3gon;
$ri3gon: .5*$l/tan(.5*$ba3gon);
$h3gon: .5*$l*sqrt(3);
$mv: .5*($h3gon - $dc3gon);
$mh: .5*(.5*$l - $dc3gon);

:before, :after {
	position: absolute;
	top: 0; right: 0; bottom: 0; left: 0;
}

body {
	display: grid;
	place-content: center;
	position: relative;
	margin: 0;
	height: 100vh;
	background: $c;
	
	&:before {
		opacity: .5;
		background: #000;
		animation: invert 2*$t ease-in-out (-$t) infinite alternate;
		content: ''
	}
}

.grid {
	display: grid;
	padding: -$mv (-$mh);
	filter: drop-shadow(2px 2px 5px $c)
}

.s3gon {
	--m: calc(.5*(1 - var(--p0, 1)*var(--p1, 1)));
	--p: calc(2*var(--m) - 1);
	grid-row: var(--ridx);
	grid-column: var(--cidx, var(--n-rows));
	position: relative;
	margin: calc(#{$mv} - (1 - var(--m))*#{$ri3gon}) $mh;
	width: $dc3gon; height: $dc3gon;
		
	&:before, &:after {
		border-radius: 50%;
		background: $c;
		clip-path: polygon(getPolyPoints());
		animation: shrink $t ease-out infinite alternate;
		animation-delay: calc(var(--cidx)*#{-$t}/var(--n-cols));
		content: ''
	}
	
	&:before {
		background: #000;
		animation-name: shrink, invert;
		animation-timing-function: ease-in, steps(1);
		animation-duration: $t, 2*$t
	}

	&:nth-child(odd) { --p1: -1 }
}

@keyframes shrink { 95%, 100% { transform: scale(0) } }

@keyframes invert { 50% { background: #fff; } }
View Compiled
// no JS here, but check out version #2 of this demo https://codepen.io/thebabydino/pen/bzVqQp
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.