Cotton.JS

Cotton.JS
v 1.3.1

Cotton.JS is a JavaScript library that allows you to make a mouse interaction animation easily.

LIKE A FLOATING COTTON!

Getting Started


Download

Via npm

npm install cottonjs

Manual download

Installation

ES modules

If you download the files via npm, you just need to import Cotton.JS in your own project :

import Cotton from 'cottonjs'

Script tag include

Simply download and include with a script tag.

<script src="cotton.min.js"></script>

or using CDN

<script src="https://cdn.jsdelivr.net/gh/cotton123236/cottonjs@latest/lib/cotton.min.js"></script>

Basic Usage

HTML

Create an element that you would like to animate.

<div id="cotton-cursor"></div>

CSS

Style your element.

1. Highly suggest setting the position property to fixed if not using the airMode, and set pointer-events to none to make sure the real mouse can touch the DOM element.
2. Please do not use transition on the transform property, it will cause some problems.

#cotton-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  pointer-events: none;
  background-color: #f9cabc;
  transform: translate(-20px, -20px);    /* move out from window before cotton init */
}

JavaScript

Initialize Cotton in JavaScript.

Highly recommened use id to define your cotton element, because it needs to be the only one on initialization.

const cottonCursor = new Cotton('#cotton-cursor')

// or using DOM element
const cursor = document.querySelector('#cotton-cursor')
const cottonCursor = new Cotton(cursor)

See some DEMOS directly.

Documentation


Parameters

Cotton : which means the element that you initialize.
Models : which means the elements that would interact with your cotton.

All available parameters :

Name Type Default Description
scene string | element 'body' The animation will work when only the mouse is moving in the scene.
This parameter accept string or DOM element like: document.querySelector('body')

The scene element has to be the only one.

models string | NodeList '.cotton-model' Define the elements that you want your cotton to interact with.
This parameter accept string or a NodeList like: document.querySelectorAll('.cotton-model')
cottonInitClass string 'cotton-init' The cottonInitClass will be added when cotton is initialized, and will be removed when you call the stop() method.
cottonMovingClass string 'cotton-moving' The cottonMovingClass will be added when the mouse enter the scene, and will be removed when the mouse leave the scene.

cottonMovingClass will also be removed when you call the stop() method.

cottonActiveClass string 'cotton-active' The cottonActiveClass will be added on cotton when mouse enter the models, and will be removed mouse leave the models.
modelsActiveClass string 'model-active' The modelsActiveClass will be added on model when mouse enter the model, and will be removed mouse leave the model.
speed number 0.125 The lower the number, the greater the delay

The speed property must be > 0 and <= 1.
If this parameter is not specified, it will be set to default.

centerMouse boolean true By default, cotton's center point will follow the mouse center. If set to false, cotton's left-top will follow the mouse center.

airMode boolean | object false By default, the cotton element will do transform relative to the top left of the window when doing the transform.
If set to true, then cotton will do transform relative to its own center point. And the following properties will be set automatically.
airMode: {
    resistance: 15,
    reverse: false
}
or you can just set an object with specified properties directly.

In airMode, the transform value will not increase if cotton is not in viewport.

airMode.resistance number 15 This property have to register on airMode.
The higher the number, the less the transform.

The resistance property must be >= 1 and <= 100.
If this parameter is not specified, it will be set to default.
If set to 1, cotton will follow the mouse completely.

airMode.reverse boolean false This property have to register on airMode.
By default, the airMode cotton will move forward to the mouse.
If set to true, the airMode cotton will move backward to the mouse.
airMode.alive boolean false This property have to register on airMode.
For better efficacy, cotton will save element's origin position when initialize.
But if set alive to true, it will keep getting element's position when mouse moving.

Sometimes it will be useful.
(like you use airMode in a position: fixed modal.)

Methods

After you initialize the cotton element, you can use the methods of its initialized instance in the variable. As the following example :

const cotton = new Cotton('#cotton-cursor')

// call the stop method of cotton
cotton.stop()

All available methods :

Methods Description
cotton.stop() Cancel the animation immediately.
The cotton element will not interact with the mouse. And the cottonInitClass will be removed when you call this method.
cotton.move() Restart the animation.
And the cottonInitClass will be added again when you call this method.
cotton.updateModels() This method will update the nodelist of models and also bind the callbacks that you defined automatically. It is very useful when you append new models or remove models.

Callbacks

Cotton provide several callbacks to allow you make more different and interesting setup.
You need to use on parameter to difine the callbacks on cotton initialization. As the following example :

const cotton = new Cotton('#cotton-cursor', {
  // ...
  on: {
    enterModel: function() {
      console.log('enter model')
    }
  }
})

All available callbacks :

Callback Arguments Description
enterModel (cotton, model, event) Callback will execute when mouse enter the model.
First argument is the cotton element. Second argument is the model that your mouse is touching. And the third argument is the event when mouse enter.
leaveModel (cotton, model, event) Callback will execute when mouse leave the model.
First argument is the cotton element. Second argument is the model that your mouse is touching. And the third argument is the event when mouse leave.
enterScene (cotton, scene, event) Callback will execute when mouse enter the scene.
First argument is the cotton element. Second argument is the scene that you defined on cotton initialization. And the third argument is the event when mouse enter.
leaveScene (cotton, scene, event) Callback will execute when mouse leave the scene.
First argument is the cotton element. Second argument is the scene that you defined on cotton initialization. And the third argument is the event when mouse leave.
cottonMove (cotton, event) Callback will execute when mouse is moving in the scene.
First argument is the cotton element. Second argument is the event when mouse is moving.

The keyword this in these callback function is the initialized instance. So you also can use all the methods in these callbacks with this keyword.

const cotton = new Cotton('#cotton-cursor',{
  // ...
  on: {
    enterModel: function() {
      this.stop();
    },
    enterModel: function() {
      this.move();
    }
  }
})

But do not use stop() on erterScene or move() on leaveScene, because it will cause conflict.

Mobile Device

Because there is no mouse on mobile devices, Cotton.JS will automatically detect user device and won't initialize when using mobile.

Demos


Simple Usage

<body>

  <div id="ball"></div>
  <div id="circle"></div>

  <a class="pill-btn" href="#">MODEL</a>

</body>
* {
  cursor: none
}

/* cotton settings */
#ball, #circle {
  top: 0;
  left: 0;
  z-index: 9;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-40px, -40px);
}
#ball {
  width: 10px;
  height: 10px;
  background-color: #ff6847;
}
#circle {
  width: 40px;
  height: 40px;
  border: 1px solid #f9cabc;
  transition: background-color .3s, border .3s, opacity .3s;
}
#circle.cotton-active {
  background-color: #333;
  border: 1px solid #333;
  opacity: .6;
}

/* models settings */
.pill-btn {
  display: inline-block;
  min-width: 80px;
  text-align: center;
  border-radius: 25px;
  color: #fff;
  background-color: #ff9c85;
  padding: 14px 40px;
  text-decoration: none;
}
// init ball
const ball = new Cotton('#ball', {
  speed: 1
})

// init circle
const circle = new Cotton('#circle', {
  models: '.pill-btn',
  on: {
    enterModel(cotton, model) {
      model.textContent = 'ACTIVE'
    },
    leaveModel(cotton, model) {
      model.textContent = 'MODEL'
    }
  }
})

Magnet Cotton

<body>

  <div id="ball"></div>
  <div id="circle"></div>

  <a class="pill-btn" href="#">MODEL</a>

</body>
* {
  cursor: none
}

/* cotton settings */
#ball, #circle {
  top: 0;
  left: 0;
  z-index: 9;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-40px, -40px);
}
#ball {
  width: 10px;
  height: 10px;
  background-color: #ff6847;
  transition: opacity .3s, width .3s, height .3s, background-color .3s;
}
#circle {
  width: 40px;
  height: 40px;
  border: 1px solid #f9cabc;
}
#ball.cotton-active {
  width: 25px;
  height: 25px;
  opacity: .6;
  background-color: #fff
}

/* models settings */
.pill-btn {
  display: inline-block;
  min-width: 80px;
  text-align: center;
  border-radius: 25px;
  color: #fff;
  background-color: #ff9c85;
  padding: 14px 40px;
  text-decoration: none;
}
// init ball
const ball = new Cotton('#ball', {
  speed: 1,
  models: '.pill-btn',
})

// init circle
const circle = new Cotton('#circle', {
  models: '.pill-btn',
  on: {
    enterModel(cotton, model) {
      this.stop();
      magnet(cotton, model, 10);
    },
    leaveModel(cotton, model) {
      this.move();
      cotton.setAttribute('style', '');
    }
  }
})

// custom magnet function
function magnet(cotton, model, space) {
  const w = model.getBoundingClientRect().width,
        h = model.getBoundingClientRect().height,
        top = model.getBoundingClientRect().top,
        left = model.getBoundingClientRect().left,
        radius = parseInt(getComputedStyle(model).borderRadius);
  cotton.style.top = top - space + 'px';
  cotton.style.left = left - space + 'px';
  cotton.style.width = w + space * 2 + 'px';
  cotton.style.height = h + space * 2 + 'px';
  cotton.style.borderRadius = radius + space + 'px';
  cotton.style.transform = 'none';
  cotton.style.transition = '.3s';
}

Hover Message

<body>

  <div id="arrow">
    <div></div>
  </div>
  <div id="photo">
    <img src="">
  </div>

  <h1>Hover To See The Logo</h1>

  <ul>
    <li data-photo="../img/angular.png">Angular</li>
    <li data-photo="../img/react.png">React</li>
    <li data-photo="../img/vue.png">Vue</li>
    <li data-photo="../img/svelte.png">Svelte</li>
  </ul>

</body>
* {
  cursor: none;
}

/* cotton settings */
#arrow {
  z-index: 9;
  top: 0;
  left: 0;
  transform: translate(-30px, -30px);
  pointer-events: none;
}
#arrow > div {
  border-width: 15px 7px 15px 7px;
  border-style: solid;
  border-color: #ff6847 transparent transparent transparent;
  transform: rotate(150deg);
  transition: .3s;
}
#arrow.cotton-active > div {
  border-width: 24px 10px 24px 10px;
  opacity: .6;
}
#photo {
  z-index: 8;
  top: 10px;
  left: 20px;
  width: 100px;
  height: 100px;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s;
}
#photo.show {
  opacity: 1;
}
#photo img {
  width: 100%;
}

/* models settings */
ul {
  display: flex;
  color: #ff6847;
  list-style-type: none;
  margin-bottom: 50px;
  padding-inline-start: 0px;
}
li {
  font-size: 18px;
  font-weight: 300;
  padding: 10px;
  margin: 0 20px;
}
// arrow init
const arrow = new Cotton('#arrow', {
  models: 'li',
  speed: 1,
})

// photo init
const photo = new Cotton('#photo', {
  models: 'li',
  cottonActiveClass: 'show',
  centerMouse: false,
  on: {
    enterModel(cotton, model) {
      const photoURL = model.dataset.photo;
      cotton.querySelector('img').setAttribute('src', photoURL)
    }
  }
})

AirMode

<body>

  <div id="ball"></div>

  <section>

    <h1 class="cotton-model">airMode</h1>
    <h2 class="cotton-model">airMode</h2>

  </section>

</body>
* {
  cursor: noen;
}

/ * cotton */
#ball {
  z-index: 9;
  top: 0;
  left: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #ff9c85;
  transform: translate(-20px, -20px);
  pointer-events: none;
  transition: width .3s, height .3s, background-color .3s, opacity .3s;
}
#ball.cotton-active {
  width: 60px;
  height: 60px;
  background-color: #333;
  opacity: .6;
}

/* models & cotton with airMode */
section {
  position: relative;
}
h1, h2 {
  font-family: 'Poppins';
  font-weight: 600;
  font-size: 7rem;
  color: #ff9c85;
  margin: 0;
}
h2 {
  position: absolute;
  top: 0;
  left: 0;
  opacity: .5;
}
// init ball and set h1 & h2 as models (default class)
const ball = new Cotton('#ball', {
  speed: 1
})

// init h1 with airMode
const h1 = new Cotton('h1', {
  airMode: true
})

// init h2 with airMode reverse
const h2 = new Cotton('h2', {
  airMode: {
    reverse: true
  }
})