- var y_table_top = 100;
- var x_table_support = 90;
- var r_table_foot = 65;
- var x_glass = 87;
- var y_glass = -215;
- var d_ctrl = 20;
- var x_diff_liquid = 7;
- var y_diff_liquid_top = 50;
- var y_diff_liquid_bottom = 20;
- var r_orange = 65;
- var n_slices = 8;
- var slice_deg = 360/n_slices;
- var slice_rad = 2*Math.PI/n_slices;
- var x_slice = Math.round(r_orange*Math.cos(slice_rad));
- var y_slice = Math.round(r_orange*Math.sin(slice_rad));
- var k_orange = (r_orange + d_ctrl)/r_orange;
- var xc_slice = Math.round(k_orange*x_slice);
- var yc_slice = Math.round(k_orange*y_slice);

svg(viewbox='-600 -500 1200 900')
  defs
    ellipse#te(cy='#{y_table_top}' 
               rx='190' ry='40')/
    linearGradient#table(gradientTransform='rotate(90)')
      stop(offset='0%' stop-color='#f2740c')/
      stop(offset='100%' stop-color='#f6781b')/
    path#liquid(d='M#{-(x_glass - x_diff_liquid)} #{y_glass + y_diff_liquid_top} L#{(x_glass - x_diff_liquid)} #{y_glass + y_diff_liquid_top} L#{(x_glass - x_diff_liquid)} #{y_table_top - y_diff_liquid_bottom} C#{(x_glass - x_diff_liquid)} #{y_table_top - y_diff_liquid_bottom + d_ctrl} #{-(x_glass - x_diff_liquid)} #{y_table_top - y_diff_liquid_bottom + d_ctrl} #{-(x_glass - x_diff_liquid)} #{y_table_top - y_diff_liquid_bottom}')/
    circle#bubble(r='7')/
    circle#bubble-small(r='5')/
    path#slice(d='M0 0 L#{r_orange} 0 C#{r_orange + d_ctrl} 0 #{xc_slice} #{yc_slice} #{x_slice} #{y_slice}z' transform='rotate(#{-.5*slice_deg}) scale(.8)')/
    linearGradient#glass
      stop(offset='50%' stop-color='rgba(255, 255,255,.3)')/
      stop(offset='50%' stop-color='rgba(255, 255,255,.2)')/
  
  g#assembly
    g.table
      path.table__support(d='M#{-x_table_support} #{y_table_top} L#{x_table_support} #{y_table_top} L#{x_table_support} #{y_table_top + 195} A#{r_table_foot} #{r_table_foot} 0 0 1 #{x_table_support + r_table_foot} #{y_table_top + 195 + r_table_foot} L#{-x_table_support - r_table_foot} #{y_table_top + 195 + r_table_foot} A#{r_table_foot} #{r_table_foot} 0 0 1 #{-x_table_support} #{y_table_top + 195}z')/
      use.table__main(xlink:href='#te' y='15')/
      use.table__top(xlink:href='#te')/
        
    g.orange(transform='translate(#{x_glass} #{y_glass}) rotate(#{.25*slice_deg})')
      circle(r='#{r_orange}')/
      g.slices
        while n_slices--
          use(xlink:href='#slice' transform='rotate(#{n_slices*slice_deg}) translate(2)')/
      circle(r='10')/
    
    g.content--bg
      use(xlink:href='#liquid')/
    
    line.straw(x1='-72' y1='-378' x2='16' y2='84')/
    
    g.content
      use(xlink:href='#liquid')/
      g.bubbles
        use(xlink:href='#bubble' x='-19' y='-114')/
        use(xlink:href='#bubble' x='-48' y='-78')/
        use(xlink:href='#bubble' x='-36' y='-14')/
        use(xlink:href='#bubble' x='-18' y='41')/
        use(xlink:href='#bubble-small' x='-48' y='31')/
        use(xlink:href='#bubble' x='53' y='43')/
        use(xlink:href='#bubble' x='27' y='-2')/
        use(xlink:href='#bubble' x='16' y='-49')/
        use(xlink:href='#bubble-small' x='48' y='-48')/
        use(xlink:href='#bubble-small' x='29' y='-80')/
        use(xlink:href='#bubble-small' x='62' y='-83')/
    
    path.glass(d='M#{-x_glass} #{y_glass} L#{x_glass} #{y_glass} L#{x_glass} #{y_table_top} C#{x_glass} #{y_table_top + d_ctrl} #{-x_glass} #{y_table_top + d_ctrl} #{-x_glass} #{y_table_top}')/
View Compiled
$bg: #f5891f /* top */, #f6781b /*bottom*/;
$table: #f58420 #f2740c;
$orange: #fcc786;
$liquid: #99d6ff;
$bubble: #b6d9f1;

@mixin proportional-box($a: 4, $b: 3) {
  position: absolute;
  top: 0; left: calc(50vw - #{$a/$b*50vh});
  width: $a/$b*100vh; height: 100vh;
  
  @media (max-aspect-ratio: #{$a}/#{$b}) {
    top: calc(50vh - #{$b/$a*50vw}); left: 0;
    width: 100vw; height: $b/$a*100vw;
  }
}

html { background: #222; }

svg {
  overflow: hidden; /* because IE */
  @include proportional-box();
  background: linear-gradient($bg);
}

.assembly { opacity: 0; }

.table {
  &__top { fill: nth($table, 1); }
  &__main { fill: nth($table, 2); }
  &__support { fill: url(#table); }
}

.orange {
  circle { fill: $orange; }
  use { fill: nth($bg, 1); }
}

.straw {
  stroke: #fff;
  stroke-width: 13;
}

.content {
  use { fill: rgba($liquid, .4); }
  &--bg use { fill: rgba($liquid, .5); }
}

[id*='bubble'] {
  fill: none;
  stroke: rgba($bubble, .95);
  stroke-width: 5;
}

.glass { fill: url(#glass); }
View Compiled
Object.getOwnPropertyNames(Math).map(function(p) {
  window[p] = Math[p];
});

var timeline = {
      'glassEnter': 20, 
      'glassStop': 50, 
      'oscStop': 120, 
      'glassStart': 130, 
      'glassExit': 160, 
      'end': 180
    },

    assembly = document.getElementById('assembly'), 
    x_off, x, 
    liquid = document.getElementById('liquid'), 
    d_fixed, x_fixed, y_base, amp = 45, 
    t = 0;

var init = function() {
  var svg = document.querySelector('svg'),
      vb = svg.getAttribute('viewBox').split(' '),
      vb_w = ~~vb[2], vb_x = ~~vb[0],
      te = document.getElementById('te'),
      max_assembly_w = 2*te.getAttribute('rx'), 
      d_a = liquid.getAttribute('d').split('L'), a_tmp;
  
  x_off = vb_w + vb_x + .5*max_assembly_w;
  x = -x_off;
    
  a_tmp = d_a[0].replace('M', '').split(' ');
  x_fixed = abs(~~a_tmp[0]);
  y_base = ~~a_tmp[1];
  
  if(!a_tmp[0]) { // oh, IE...
    x_fixed = abs(~~a_tmp[1]);
    y_base = ~~a_tmp[2];
  }
  
  d_a.splice(0, 2);
  d_fixed = ' L' + d_a.join(' L');
  
  assembly.setAttribute('transform', 'translate(' + x_off + ')');
  assembly.style.opacity = 1;
  ani();
};

var ani = function() {
  var dt, t_rel, curr_amp, curr_d;
  
  if(t > timeline.end) { t = 0; }
  
  if(t >= timeline.glassEnter) {
    t_rel = t - timeline.glassEnter;
    
    if(t <= timeline.glassStop) {
      dt = timeline.glassStop - timeline.glassEnter;
      
      x = -x_off*pow(1 - t_rel/dt, 3);
      assembly.setAttribute('transform', 'translate(' + x + ')');
    }
    
    if(t <= timeline.oscStop) {
      dt = timeline.oscStop - timeline.glassEnter;
      
      curr_amp = amp*(1 - t_rel/dt);
      y_var = round(curr_amp*cos(t_rel/dt*3*PI));
      
      curr_d = 'M' + -x_fixed + ' ' + (y_base - y_var) + 
        ' L' + x_fixed + ' ' + (y_base + y_var) + d_fixed;
      liquid.setAttribute('d', curr_d);
    }
  }
  
  if(t >= timeline.glassStart && t <= timeline.glassExit) {
    dt = timeline.glassExit - timeline.glassStart;
    t_rel = t - timeline.glassStart;
    x = x_off*pow(t_rel/dt, 2);
    assembly.setAttribute('transform', 'translate(' + x + ')');
    
    curr_amp = amp*t_rel/dt;
    y_var = round(curr_amp*sin(t_rel/dt*1.5*PI));

    curr_d = 'M' + -x_fixed + ' ' + (y_base - y_var) + 
      ' L' + x_fixed + ' ' + (y_base + y_var) + d_fixed;
    liquid.setAttribute('d', curr_d);
  }
  
  t++;
  
  requestAnimationFrame(ani);
};

init();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.