``````#fps
#entry-point``````
``````\$background: #000;
\$font-color: #fff;

body {
background: \$background;
}

#fps {
position: absolute;
color: \$font-color;
top: 5px;
left: 5px;
}

#entry-point {
position: relative;
width: 500px;
height: 500px;
left: 0;
right: 0;
margin: 0 auto 0 auto;
top: 50vh;
transform: translateY(-50%);

svg {
width: 500px;
height: 500px;
background: \$background;
}
}``````
``````const Circle = ({ attr: { r, fill, stroke, strokeWidth }, position }) => (
<circle
r={r}
fill={fill === undefined ? 'none' : fill}
stroke={stroke === undefined ? 'none' : stroke}
strokeWidth={2}
transform={`translate(\${position[0]}, \${position[1]})`}
/>
);

const Path = ({ attr: { path, fill, stroke, strokeWidth }, position, phi }) => (
<path
d={path}
fill={fill === undefined ? 'none' : fill}
stroke={stroke === undefined ? 'none' : stroke}
strokeWidth={2}
transform={`rotate(\${phi}, \${position[0]}, \${position[1]}) translate(\${position[0]}, \${position[1]})`}
/>
);

const Teardrop = ({ position, phi, a, b, m }) => {
let path = 'M 0 0'
for (let i = 0; i <= 360; i++) {
const rad = i * Math.PI / 180;
const x = a * Math.cos(rad);
const y = b * Math.sin(rad) * Math.pow(Math.sin(rad/2), m);
path += ` L \${x} \${y}`;
}
return (
<Path
attr={{ path, stroke: mandalaStroke, fill: mandalaFill }}
position={position}
phi={phi}
/>
);
}

const Group = ({ position, phi, children }) => (
<g
transform={`rotate(\${phi}, \${position[0]}, \${position[1]}) translate(\${position[0]}, \${position[1]})`}
>
{children}
</g>
);

const mandalaFill = '#382D7B';
const mandalaStroke = '#9370DB';

const Mandala = ({ theta }) => (
<Group
position={[500, 500]}
phi={theta / 50}
>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 500, fill: mandalaFill, stroke: mandalaStroke }}
/>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 480, fill: mandalaFill, stroke: mandalaStroke }}
/>
{Array.apply(null, Array(24)).map(() => {}).map((elem, i) => (
<Teardrop
phi={15 * i + 180}
position={
[400 * Math.cos(Math.PI * i / 12), 400 * Math.sin(Math.PI * i / 12)]
}
m={5}
a={80}
b={40 + 10 * Math.cos(theta / 600)}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Group
phi={0}
position={
[467.5 * Math.cos(Math.PI * i / 3), 467.5 * Math.sin(Math.PI * i / 3)]
}
>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 23 + 5 * Math.cos(theta / 300), fill: mandalaFill, stroke: mandalaStroke }}
/>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 10 + 7 * Math.cos(theta / 300), fill: mandalaFill, stroke: mandalaStroke }}
/>
</Group>
))}
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 435, fill: mandalaFill, stroke: mandalaStroke }}
/>
{Array.apply(null, Array(48)).map(() => {}).map((elem, i) => (
<Group
phi={0}
position={[0, 0]}
>
<Path
position={[0, 0]}
phi={0}
attr={{
path: `M 0 0 L \${435 * Math.cos(Math.PI * i / 24)} \${435 * Math.sin(Math.PI * i / 24)}`,
stroke: mandalaStroke
}}
/>
<Circle
position={
[417 * Math.cos(Math.PI * (i + 0.5) / 24), 417 * Math.sin(Math.PI * (i + 0.5) /24)]
}
phi={0}
attr={{ r: 5 + 3 * Math.cos(Math.PI * i / 9 + theta / 1e4), fill: mandalaFill, stroke: mandalaStroke }}
/>
</Group>
))}
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 400, fill: mandalaFill, stroke: mandalaStroke }}
/>
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Group
position={
[280 * Math.cos(Math.PI * (i + 0.5) / 3), 280 * Math.sin(Math.PI * (i + 0.5) / 3)]
}
phi={-theta / 50}
>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 115, fill: mandalaFill, stroke: mandalaStroke }}
/>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 100, fill: mandalaFill, stroke: mandalaStroke }}
/>
{Array.apply(null, Array(12)).map(() => {}).map((elem, i) => (
<Teardrop
position={
[30 * Math.cos(Math.PI * i / 6), 30 * Math.sin(Math.PI * i / 6)]
}
phi={30 * i}
m={2}
a={60}
b={80}
/>
))}
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 60 + 5 * Math.cos(theta / 300), fill: mandalaFill, stroke: mandalaStroke }}
/>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 40, fill: mandalaFill, stroke: mandalaStroke }}
/>
</Group>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Group
phi={60 * i}
position={
[280 * Math.cos(Math.PI * i / 3), 280 * Math.sin(Math.PI * i / 3)]
}
>
<Teardrop
position={[0, 0]}
phi={0}
a={200}
b={240}
m={2}
/>
<Teardrop
position={[0, 0]}
phi={0}
a={160}
b={200}
m={2}
/>
<Circle
attr={{ r: 80, fill: mandalaFill, stroke: mandalaStroke }}
position={[80, 0]}
phi={0}
/>
<Circle
attr={{ r: 70, fill: mandalaFill, stroke: mandalaStroke }}
position={[80, 0]}
phi={0}
/>
<Group
phi={theta / 25}
position={[80, 0]}
>
{Array.apply(null, Array(6)).map(() => {}).map((elem, j) => (
<Teardrop
position={
[-20 * Math.cos(Math.PI * (j + 0.5) / 3), -20 * Math.sin(Math.PI * (j + 0.5) / 3)]
}
phi={60 * j + 30}
m={5}
a={30}
b={30}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, j) => (
<Teardrop
position={
[50 * Math.cos(Math.PI * j / 3), 50 * Math.sin(Math.PI * j / 3)]
}
phi={60 * j}
m={5}
a={35}
b={35}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, j) => (
<Circle
position={
[70 * Math.cos(Math.PI * j / 3), 70 * Math.sin(Math.PI * j / 3)]
}
phi={0}
attr={{ r: 10, fill: mandalaFill, stroke: mandalaStroke }}
/>
))}
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 30, fill: mandalaFill, stroke: mandalaStroke }}
/>
<Circle
phi={0}
position={[0, 0]}
attr={{ r: 18 + 2 * Math.cos(theta / 300), fill: mandalaFill, stroke: mandalaStroke }}
/>
</Group>
</Group>
))}
<Circle
attr={{ r: 290, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
phi={0}
/>
{Array.apply(null, Array(24)).map(() => {}).map((elem, i) => (
<Circle
attr={{ r: 30, stroke: mandalaStroke, fill: mandalaFill }}
position={
[260 * Math.cos(Math.PI * i /12), 260 * Math.sin(Math.PI * i / 12)]
}
/>
))}
<Circle
attr={{ r: 260, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
phi={0}
/>
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Group
phi={-theta / 50}
position={
[150 * Math.cos(Math.PI * i / 3), 150 * Math.sin(Math.PI * i / 3)]
}
>
<Circle
attr={{ r: 100, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
phi={0}
/>
{Array.apply(null, Array(24)).map(() => {}).map((elem, j) => {
const path = `M 0 0 L \${100 * Math.cos(Math.PI * j / 12)} \${100 * Math.sin(Math.PI * j / 12)}`;
return (
<Path
attr={{ path, stroke: mandalaStroke }}
position={[0, 0]}
phi={0}
/>
);
})}
</Group>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Teardrop
position={
[220 * Math.cos(Math.PI * (i + 0.5) / 3), 220 * Math.sin(Math.PI * (i + 0.5) / 3)]
}
phi={60 * i + 30}
a={80}
b={200}
m={5}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Group
phi={theta / 25}
position={
[190 * Math.cos(Math.PI * (i + 0.5) / 3), 190 * Math.sin(Math.PI * (i + 0.5) / 3)]
}
>
<Circle
attr={{ r: 45 + 5 * Math.cos(theta / 300), stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
phi={0}
/>
<Circle
attr={{ r: 28, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
phi={0}
/>
{Array.apply(null, Array(3)).map(() => {}).map((elem, i) => (
<Circle
attr={{ r: 8, stroke: mandalaStroke, fill: mandalaFill }}
position={
[12 * Math.cos(2 * Math.PI * i / 3), 12 * Math.sin(2 * Math.PI * i /3)]
}
/>
))}
</Group>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Teardrop
position={
[200 * Math.cos(Math.PI * i / 3), 200 * Math.sin(Math.PI * i / 3)]
}
phi={60 * i}
a={120}
b={180}
m={6}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Teardrop
position={
[180 * Math.cos(Math.PI * i / 3), 180 * Math.sin(Math.PI * i / 3)]
}
phi={60 * i}
a={60}
b={90}
m={6}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Circle
attr={{ r: 15, stroke: mandalaStroke, fill: mandalaFill }}
position={
[280 * Math.cos(Math.PI * i / 3), 280 * Math.sin(Math.PI * i / 3)]
}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Circle
attr={{ r: 8 + 2 * Math.cos(theta / 300), stroke: mandalaStroke, fill: mandalaFill }}
position={
[310 * Math.cos(Math.PI * i / 3), 310 * Math.sin(Math.PI * i / 3)]
}
/>
))}
{Array.apply(null, Array(12)).map(() => {}).map((elem, i) => (
<Circle
attr={{ r: 30, stroke: mandalaStroke, fill: mandalaFill }}
position={
[120 * Math.cos(Math.PI * i / 6), 120 * Math.sin(Math.PI * i / 6)]
}
/>
))}
{Array.apply(null, Array(12)).map(() => {}).map((elem, i) => (
<Circle
attr={{ r: 20 + 2 * -Math.cos(theta / 600), stroke: mandalaStroke, fill: mandalaFill }}
position={
[120 * Math.cos(Math.PI * i / 6), 120 * Math.sin(Math.PI * i / 6)]
}
/>
))}
<Circle
attr={{ r: 120, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
/>
<Circle
attr={{ r: 100 + 5 * Math.cos(theta / 600), stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
/>
<Group
position={[0, 0]}
phi={-theta / 50}
>
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Teardrop
position={
[70 * Math.cos(Math.PI * (i + 0.5) / 3), 70 * Math.sin(Math.PI * (i + 0.5) / 3)]
}
phi={60 * i + 30}
a={30}
b={60}
m={5}
/>
))}
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Circle
position={
[80 * Math.cos(Math.PI * i / 3), 80 * Math.sin(Math.PI * i / 3)]
}
phi={60 * i}
attr={{ r: 7, fill: mandalaFill, stroke: mandalaStroke }}
/>
))}
</Group>
{Array.apply(null, Array(6)).map(() => {}).map((elem, i) => (
<Teardrop
position={
[80 * Math.cos(Math.PI * i / 3), 80 * Math.sin(Math.PI * i / 3)]
}
phi={60 * i}
a={40}
b={70}
m={5}
/>
))}
<Circle
attr={{ r: 50, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
/>
{Array.apply(null, Array(12)).map(() => {}).map((elem, i) => (
<Path
attr={{ path: 'M 0 0 L 35 35', stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
phi={i * 30}
/>
))}
<Circle
attr={{ r: 32 + 2 * Math.cos(theta / 400), stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
/>
<Circle
attr={{ r: 20, stroke: mandalaStroke, fill: mandalaFill }}
position={[0, 0]}
/>
</Group>
);

const App = ({ theta, children }) => (
<svg
viewBox="0 0 1000 1000"
>
<Circle
attr={{ r: 499, stroke: '#333' }}
position={[500, 500]}
/>
<Mandala theta={theta} />
</svg>
);

const beginning = Date.now();
let then = Date.now();

function renderApp() {
const now = Date.now() - beginning;
ReactDOM.render(
(<App theta={now} />),
document.getElementById('entry-point')
);
ReactDOM.render(
(<div>{`\${Math.round(1e4 / (now - then)) / 10} fps`}</div>),
document.getElementById('fps')
);
then = now;
window.requestAnimationFrame(renderApp);
}

renderApp();``````

### External CSS

This Pen doesn't use any external CSS resources.