title: Animate so that objects don't touch but repel?
body: <p>I have a project I got from a tutorial. It consist of a loop that that places objects at different points on canvas using a spritsheet. I can figure most of the components but one thing I could not do is make sure that the bubbles don't touch each other, that is to make it repel once they touch or get close to one another.</p>
  <p>Here is an example of when two objects are just crossing over each other:</p>
  <p><a href="https://i.stack.imgur.com/lSGGB.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/lSGGB.png" alt="enter image description here" /></a></p>
  <p>as you can see the carrot is crossing over to the pink circle; is there way to make it repel instead?
  The play code is here:</p>
  <p><a href="https://codepen.io/ahdee/pen/abVyNRo" rel="nofollow noreferrer">https://codepen.io/ahdee/pen/abVyNRo</a></p>
  <p>CSS</p>
  <pre><code>.bubble-wrap {
    overflow: hidden;
    height: 1600px;
  }
  
  .bubbles {
    position: relative;
    background: salmon;
  }
  
  .bubble { 
    position: absolute;
    width: 152px;
    height: 152px;
    border-radius: 50%;
    box-shadow: 
      0 15px 35px rgba(0, 0, 0, 0.1),
      0 3px 10px rgba(0, 0, 0, 0.1);
    background-image: url(https://www.dropbox.com/s/dok32aojteb42c9/logo-spritesheet.png?dl=1);
    background-size: 1076px 1076px;
  }
  
  .logo1 { background-position:   0      0; }
  .logo2 { background-position:  -154px  0; }
  .logo3 { background-position:  -308px  0; }
  .logo4 { background-position:  -462px  0; }
  .logo5 { background-position:  -616px  0; }
  .logo6 { background-position:  -770px  0; }
  .logo7 { background-position:  -924px  0; }
  .logo8 { background-position:   0     -154px; }
  .logo9 { background-position:  -154px -154px; }
  .logo10 { background-position: -308px -154px; }
  .logo11 { background-position: -462px -154px; }
  .logo12 { background-position: -616px -154px; }
  .logo13 { background-position: -770px -154px; }
  .logo14 { background-position: -924px -154px; }
  .logo15 { background-position:  0     -308px; }
  .logo16 { background-position: -154px -308px; }
  .logo17 { background-position: -308px -308px; }
  .logo18 { background-position: -462px -308px; }
  .logo19 { background-position: -616px -308px; }
  .logo20 { background-position: -770px -308px; }
  .logo21 { background-position: -924px -308px; }
  .logo22 { background-position:  0     -462px; }
  .logo23 { background-position: -154px -462px; }
  .logo24 { background-position: -308px -462px; }
  .logo25 { background-position: -462px -462px; }
  .logo26 { background-position: -616px -462px; }
  .logo27 { background-position: -770px -462px; }
  .logo28 { background-position: -924px -462px; }
  .logo29 { background-position:  0     -616px; }
  .logo30 { background-position: -154px -616px; }
  .logo31 { background-position: -308px -616px; }
  .logo32 { background-position: -462px -616px; }
  .logo33 { background-position: -616px -616px; }
  
  body {
    background: #E6EEF7;
  }
  
  
  </code></pre>
  <p>JS</p>
  <pre><code>const SCROLL_SPEED = 0.02;
  const NOISE_SPEED = 0.00014;
  const NOISE_AMOUNT = 1000;
  const CANVAS_WIDTH = 800;
  
  const bubblesEl = document.querySelector('.bubbles');
  const links = [&quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                  , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                 , &quot;http://www.example.com&quot;
                ];
  
  
  const bubbleSpecs = [
    { s: 1, x: 1134, y: 750  },
    { s: .6, x: 1620, y: 271 }, 
    { s: .6, x: 1761, y: 372 },
    { s: .6, x: 2499, y: 79  },
    { s: .6, x: 2704, y: 334 },
    { s: .6, x: 2271, y: 356 },
    { s: .6, x: 795,  y: 226 },
    { s: .6, x: 276,  y: 256 },
    { s: .6, x: 1210, y: 365 },
    { s: .6, x: 444,  y: 193 },
    { s: .6, x: 2545, y: 387 },
    { s: .8, x: 1303, y: 193 },
    { s: .8, x: 907,  y: 88  },
    { s: .8, x: 633,  y: 320 },
    { s: .8, x: 323,  y: 60  },
    { s: .8, x: 129,  y: 357 },
    { s: .8, x: 1440, y: 342 },
    { s: .8, x: 1929, y: 293 },
    { s: .8, x: 2135, y: 198 },
    { s: .8, x: 2276, y: 82  },
    { s: .8, x: 2654, y: 182 },
    { s: .8, x: 2783, y: 60  },
    {        x: 1519, y: 118 },
    {        x: 1071, y: 233 },
    {        x: 1773, y: 148 },
    {        x: 2098, y: 385 },
    {        x: 2423, y: 244 },
    {        x: 901,  y: 385 },
    {        x: 624,  y: 111 },
    {        x: 75,   y: 103 },
    {        x: 413,  y: 367 },
    {        x: 2895, y: 271 },
    {        x: 1990, y: 75  }
  ];
  
  class Bubbles {
    constructor(specs) {
      this.bubbles = [];
  
      specs.forEach((spec, index) =&gt; {
        this.bubbles.push(new Bubble(index, spec));
      })
      
      requestAnimationFrame(this.update.bind(this));
    }
    
    update() {
      this.bubbles.forEach(bubble =&gt; bubble.update());
      this.raf = requestAnimationFrame(this.update.bind(this))
    }  
  }
  
  
  class Bubble {
    constructor(index, {x, y, s = 1}) {
      this.index = index;
      this.x = x;
      this.y = y;
      this.scale = s;
  
      this.noiseSeedX = Math.floor(Math.random() * 64000);
      this.noiseSeedY = Math.floor(Math.random() * 64000);
  
      this.link = document.createElement(&quot;a&quot;);
      
      this.el = document.createElement(&quot;div&quot;);
      this.el.className = `bubble logo${this.index + 1}`;
      this.link.appendChild(this.el);
      this.link.href = links[index];
      this.link.target = '_blank';
  
      bubblesEl.appendChild(this.link);
    }
    
    update() {
      this.noiseSeedX += NOISE_SPEED;
      this.noiseSeedY += NOISE_SPEED;
      let randomX = noise.simplex2(this.noiseSeedX, 0);
      let randomY = noise.simplex2(this.noiseSeedY, 0);
       
      this.x -= SCROLL_SPEED;
      this.xWithNoise = this.x + (randomX * NOISE_AMOUNT);
      this.yWithNoise = this.y + (randomY * NOISE_AMOUNT)
      
      if (this.x &lt;  -200) {
        this.x = CANVAS_WIDTH;
      }
      
      this.el.style.transform = `translate(${this.xWithNoise}px, ${this.yWithNoise}px) scale(${this.scale})`;
    }
  }
  
  // For perlin noise
  noise.seed(Math.floor(Math.random() * 64000));
  
  const bubbles = new Bubbles(bubbleSpecs);
  
  
  </code></pre>
  <p>html</p>
  <pre><code>&lt;div class=&quot;bubble-wrap&quot;&gt;
    &lt;div class=&quot;bubbles&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
  </code></pre>