JSFiddle - React, Tailwind, and code Playground
by Torwan
HTML
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.17.0/TweenMax.min.js"></script>
<svg class="labSVG" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" >
<defs>
<linearGradient id="frontGrad" gradientUnits="userSpaceOnUse" x1="300" y1="100" x2="300" y2="600">
<stop offset="0.5" style="stop-color:#005DE9"/>
<stop offset="0.8" style="stop-color:#ED1E79"/>
</linearGradient>
<mask id="liquidMask">
<path class="liquidMask" fill="#FFFFFF" d="M337,273.9V129h-74v144.8c-37,14.7-63.1,50.8-63.1,93c0,55.2,44.8,100,100,100
s100-44.8,100-100C400,324.7,373.9,288.6,337,273.9z"/>
</mask>
<clipPath id="sphereMask">
<circle fill="red" stroke="none" stroke-width="0.4957" stroke-miterlimit="10" cx="300" cy="367" r="100"/>
</clipPath>
<filter id="goo" color-interpolation-filters="sRGB">
<feGaussianBlur in="SourceGraphic" stdDeviation="7 7" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -7" result="cm" />
<feComposite in="SourceGraphic" in2="cm" />
</filter>
</defs>
<g class="liquidMaskGroup" clip-path="url(#sphereMask)">
<path class="liquidBack" fill="none" d="M1199.9,365.1c-41.8,0-79.4,9.8-107.4,8.1c-38.9-2.3-54.5-16.4-83.6-19.9
c-29.1-3.5-71.5,3.4-110.4,1c-28-1.7-56.4-13.7-98.2-13.7c-41.8,0-70.2,12-98.2,13.7c-38.9,2.3-81.4-4.6-110.4-1
c-29.1,3.5-44.7,17.5-83.6,19.9c-28,1.7-65.7-8.2-107.5-8.2c-41.8,0-79.5,9.9-107.5,8.2c-38.9-2.3-54.5-16.3-83.6-19.9
c-29.1-3.5-72,3.4-110.9,1c-28-1.7-56.7-13.7-98.7-13.7V438h1200L1199.9,365.1z"/>
<g class="liquidBubblesGroup" fill="url(#frontGrad)" clip-path="url(#sphereMask)">
<path class="liquidFront" fill="url(#frontGrad)" ...
CSS
body{
background-color:#000;
overflow:hidden;
}
body, html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.labSVG{
width:100%;
height:100%;
/* max-height:600px; */
}
.flask{
stroke:#f7f7f7;
}
.liquidBack{
fill:#0248AD;
}
/*
.liquidFront, .liquidBubblesGroup{
fill:#005DE9;
}
*/
.pop{
stroke:#005DE9;
}
.darkBubbleGroup{
fill:#171717;
}
JavaScript
var select = function(s) {
return document.querySelector(s);
}, liquidFront = select('.liquidFront'), liquidMaskGroup = select('.liquidMaskGroup'), liquidBack = select('.liquidBack'), bubble0 = select('.bubble0'), bubble1 = select('.bubble1'), bubble2 = select('.bubble2'), bubble3 = select('.bubble3'), bubble4 = select('.bubble4'), pop = select('.pop'), bubblePop0 = select('.bubblePop0'), bubblePop1 = select('.bubblePop1'), bubblePop2 = select('.bubblePop2'), liquidBubblesGroup = select('.liquidBubblesGroup'), darkBubble = document.getElementsByClassName('darkBubble');
var xLink = "http://www.w3.org/1999/xlink";
var pop1 = pop.cloneNode(true);
var pop2 = pop.cloneNode(true);
liquidMaskGroup.appendChild(pop1);
liquidMaskGroup.appendChild(pop2);
var isDevice = (/android|webos|iphone|ipad|ipod|blackberry/i.test(navigator.userAgent.toLowerCase()));
if(!isDevice){
TweenMax.set(liquidBubblesGroup, {
filter:'url(#goo)',
'-webkit-filter':'url(#goo)'
})
}
var mainTimeline = new TimelineMax();
var frontLiquidTimeline = new TimelineMax({repeat:-1});
frontLiquidTimeline.to(liquidFront, 3, {
x:-600,
ease:Linear.easeNone
})
var backLiquidTimeline = new TimelineMax({repeat:-1});
backLiquidTimeline.from(liquidBack, 3, {
x:-800,
ease:Linear.easeNone
})
var b0 = new TimelineMax({repeat:-1, delay:0, repeatDelay:2, onRepeat:doRepeat, onRepeatParams:[bubble0]});
b0.timeScale(1)
b0.to(bubble0, 0.8, {
attr:{
cy:'-=80'
},
ease:Sine.easeOut
} )
.to(bubble0, 0.8, {
attr:{
cy:'+=80'
},
ease:Sine.easeIn
})
var b1 = new TimelineMax({repeat:-1, delay:3, repeatDelay:5, onRepeat:doRepeat, onRepeatParams:[bubble1]});
b1.timeScale(1)
b1.to(bubble1, 0.7, {
attr:{
cy:'-=120'
},
ease:Sine.easeOut
} )
.to(bubble1, 0.7, {
attr:{
cy:'+=120'
},
ease:Sine.easeIn
})
var b2 = new TimelineMax({repeat:-1, delay:1, repeatDelay:6, onRepeat:doRepeat, onRepeatParams:[bubble2]});
b2.timeScale(1)
b2.to(bubble2, 1, {
attr:{
...