<h2>Static elements</h2>
<img style="--n:20;--t:0;--b:20;--na:0;" src="https://picsum.photos/id/1069/150/150">
<img style="--n:12;--t:0;--b:10;--na:0;" src="https://picsum.photos/id/1069/150/150">
<img style="--n:18;--t:1;--b:20;--na:0;--seed:33" src="https://picsum.photos/id/1069/150/150">
<img style="--n:44;--t:0;--b:30;--na:1;" src="https://picsum.photos/id/1069/150/150">
<img style="--n:24;--t:1;--b:78;--na:2;--seed:34" src="https://picsum.photos/id/1069/150/150">
<h2>Hover animations</h2>
<img class="h" style="--n:26;--t:0;--b:20;--v:0;--na:0;" src="https://picsum.photos/id/1074/150/150">
<img class="h" style="--n:20;--t:1;--b:0;--v:50;--na:0;--seed:208" src="https://picsum.photos/id/1074/150/150">
<img class="h" style="--n:30;--t:1;--b:20;--v:-10;--na:0;--seed:566" src="https://picsum.photos/id/1074/150/150">
<img class="h s" style="--n:40;--t:0;--b:0;--v:10;--na:3;" src="https://picsum.photos/id/1074/150/150">
<img class="h s" style="--n:50;--t:1;--b:0;--v:20;--na:4;--seed:115" src="https://picsum.photos/id/1074/150/150">
<h2>keyframes animations</h2>
<img class="a1" style="--n:50;--t:1;--na:0;--seed:123" src="https://picsum.photos/id/1016/150/150">
<img class="a1" style="--n:60;--t:0;--na:2;" src="https://picsum.photos/id/1016/150/150">
<img class="a1" style="--n:12;--t:0;--na:0;" src="https://picsum.photos/id/1016/150/150">
<img class="a2" style="--n:15;--na:5;--seed:50" src="https://picsum.photos/id/1016/150/150">
<img class="a2" style="--n:60;--na:5;--seed:50" src="https://picsum.photos/id/1016/150/150">

<h2>Hover + keyframes animations</h2>
<img class="a2 bo" style="--n:10;--na:6;--seed:385;--v:20" src="https://picsum.photos/id/1022/150/150">
<img class="a2 bo" style="--n:8;--na:6;--seed:966;--v:-100" src="https://picsum.photos/id/1022/150/150">
<img class="a2 bo" style="--n:30;--na:6;--seed:580;--v:50" src="https://picsum.photos/id/1022/150/150">
<img class="a2 bo" style="--n:40;--na:6;--seed:666;--v:-30" src="https://picsum.photos/id/1022/150/150">
<script>
if (CSS.paintWorklet) {              CSS.paintWorklet.addModule('/t_afif/pen/f79d9dc54946caa5a416cb7fde5dabaa.js');
} else {
  alert("Your browser cannot run this demo. Consider Chrome or Edge instead")
}
</script>
@property --b{
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}
@property --bo{
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}

img {
  cursor:pointer;
  border-radius:50%;
  -webkit-mask:paint(blob);
  transition:--b .5s,--bo .5s;
}
.h:hover {
  --b:var(--v)!important
}

.s:hover {
  --b:0.1!important;
  transition:--b .5s cubic-bezier(.5,calc(var(--v)/(-.289*.1)),.5,calc(var(--v)/(.289*.1)));
}
.a1 {
  animation:b1 2s infinite alternate;
}
@keyframes b1{
  20% { --b:25 }
  50%,90% {--b:50}
  60% {--b:40}
}
.a2 {
  animation:b2 2s infinite linear;
}
@keyframes b2{
  0% { --b:0 }
  100% {--b:1}
}
.bo:hover {
  --bo:var(--v);
}

body {
  background:pink;
}
registerPaint('blob', class  {

   static get inputProperties() {
    return [
      '--n',
      '--na',
      '--v',
      '--b',
      '--bo',
      '--t',
      '--seed'
    ]
  }
  
  paint(ctx, size, properties) {
    var point = [];
    const cx = size.width/2;
    const cy = size.height/2;
    const N = parseInt(properties.get('--n'));
    const Na = parseInt(properties.get('--na'));
    const T = parseInt(properties.get('--t'));
    const B = parseFloat(properties.get('--b'));
    const Bo = parseFloat(properties.get('--bo'));
    const V = parseFloat(properties.get('--v'));
    var RADIUS;
    
    switch (Na) {
        case 0: 
        case 1: 
        case 2: 
          if(V < 0)
             RADIUS = size.width/2 + V;
          else
             RADIUS = size.width/2;
          break;
        case 3: 
        case 4:
          RADIUS = size.width/2 - Math.abs(V);
          break;  
        case 5:  
        case 6:
          var r = (size.width)*Math.sin(Math.PI/(N*2));
          RADIUS = size.width/2 - r;
          break;
        default:
          RADIUS = size.width/2
    }
    
    const mask = 0xffffffff;
    const seed = parseInt(properties.get('--seed'));
    let m_w  = (123456789 + seed) & mask;
    let m_z  = (987654321 - seed) & mask;
    let random =  function() {
      m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
      m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;

      var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
      result /= 4294967296;
      return result;
    }
    
    for(var i = 0; i < N; i++) {
      var x,y;
      switch (Na) {
        case 0: /* default movement*/
          var r = RADIUS - B*(i%2);
          if(T == 1)
             r = RADIUS - B*random();
          x = Math.cos((i / N) * (2 * Math.PI)) * r + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * r + cy;
          break;
        case 1: /* x-axis to the center */
          var r = RADIUS - B*(i%2);
          if(T == 1)
             r = RADIUS - B*random();
          x = Math.cos((i / N) * (2 * Math.PI)) * r + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * RADIUS + cy;
          break;
        case 2: /* y-axis to the center */
          var r = RADIUS - B*(i%2);
          if(T == 1)
             r = RADIUS - B*random();
          x = Math.cos((i / N) * (2 * Math.PI)) * RADIUS + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * r + cy;
          break;
        case 3: /* x-axis same direction */          
          var sign = 1;
          if(i<0.75*N && i>0.25*N) 
            sign = -1; 
          var r = RADIUS - B*sign*(i%2);
          if(T == 1)
             r = RADIUS - B*sign*random();
          x = Math.cos((i / N) * (2 * Math.PI)) * r + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * RADIUS + cy;
          break;
        case 4: /* y-axis same direction */
          var sign = 1;
          if(i<0.5*N && i>0*N) 
            sign = -1; 
          var r = RADIUS - B*sign*(i%2);
          if(T == 1)
             r = RADIUS - B*sign*random();
          x = Math.cos((i / N) * (2 * Math.PI)) * RADIUS + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * r + cy;
          break;
        case 5: /* circular movement */
          var r = (size.width)*Math.sin(Math.PI/(N*2));
          var rr = r*random();
          var xx = rr*Math.cos(B * (2 * Math.PI));
          var yy = rr*Math.sin(B * (2 * Math.PI)); 
          x = Math.cos((i / N) * (2 * Math.PI)) * RADIUS + xx + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * RADIUS + yy + cy;
          break;
        case 6: /* spiral movement */
          var r = (size.width)*Math.sin(Math.PI/(N*2));
          var rr = r*random();
          var xx = rr*Math.cos(B * (2 * Math.PI));
          var yy = rr*Math.sin(B * (2 * Math.PI)); 
          var ro = RADIUS - Bo*random();
          x = Math.cos((i / N) * (2 * Math.PI)) * ro + xx + cx;
          y = Math.sin((i / N) * (2 * Math.PI)) * ro + yy + cy;
          break;
        default: /* draw a circle by default */
          var x = Math.cos((i / N) * (2 * Math.PI)) * RADIUS + cx;
          var y = Math.sin((i / N) * (2 * Math.PI)) * RADIUS + cy;
      }
      point[i] = [x,y];
    }
    
    
    ctx.beginPath();
    var xc1 = (point[0][0] + point[N - 1][0]) / 2;
    var yc1 = (point[0][1] + point[N - 1][1]) / 2;

    ctx.moveTo(xc1, yc1);
    for(var i = 0; i < N - 1; i++) {
      var xc = (point[i][0] + point[i + 1][0]) / 2;
      var yc = (point[i][1] + point[i + 1][1]) / 2;
      ctx.quadraticCurveTo(point[i][0], point[i][1], xc, yc)
    }
    ctx.quadraticCurveTo(point[N - 1][0], point[N - 1][1], xc1, yc1);
    ctx.fillStyle = '#000';
    ctx.closePath();
    ctx.fill();
    }
})

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.