This demo makes use of seeded random numbers to get random bubbles not so random :)

Interesting part here is that each image as its own random bubbles, but its randomness is “saved” during animation, thanks to seeded random numbers inside paint worklet.

Uncheck option to see the difference. Without seeded ramdom numbers, each repaint generates random bubbles

Support: Chrome with flags (paint worklet, but inherited custom properties)

Such Wow.
Very Awesome.
So CSS!
.el {
  --bubbles: 75
  --bubbles-size: 0;
  --seed: 1;
  transition: --bubbles-size .4s ease-out;
}
.el:nth-child(2) {
  --seed: 2;
}
.text {
  mask-image: paint(bubbles);
}
.el:hover {
  --bubbles-size: 80;
  transition-timing-function: ease-in;
}
registerPaint('bubbles', class {
  paint(ctx, geom, properties) {
    const seed = properties.get('--seed').toString();
    Math.seedrandom(seed);

    // do random things now
  }
}