diff --git a/index.js b/index.js
index 9f0edeb..fa00d1f 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,4 @@
+new cursoreffects.rainbowCursor({ element: document.querySelector("#rainbow") })
new cursoreffects.fairyDustCursor({ element: document.querySelector("#fairyDust") })
new cursoreffects.ghostCursor({ element: document.querySelector("#ghost") })
new cursoreffects.trailingCursor({ element: document.querySelector("#trailing") })
diff --git a/package.json b/package.json
index 55f0599..276e444 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "cursor-effects",
"type": "module",
"description": "Old-school cursor effects for your browser built in modern JavaScript.",
- "version": "1.0.2",
+ "version": "1.0.3",
"main": "./dist/cjs.cjs",
"module": "./dist/esm.js",
"exports": {
diff --git a/readme.md b/readme.md
index de4d92c..9a5b449 100644
--- a/readme.md
+++ b/readme.md
@@ -59,6 +59,14 @@ new emojiCursor({ emoji: ["🔥", "🐬", "🦆"] });
A few of these have custom options as well (if you are interested in more options, opening an issue or PR is the way to go).
+### rainbowCursor
+
+You can change the colors, size and length in `rainbowCursor`
+
+```js
+new cursoreffects.rainbowCursor({length: 3, colors: ['red', 'blue'], size: 4});
+```
+
### springyEmojiCursor
You can change the emoji in `springyEmojiCursor`'s emoji with the `emoji` a single string emoji.
diff --git a/src/index.js b/src/index.js
index 27c6507..f98c4ad 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,4 +5,5 @@ export * from './trailingCursor.js';
export * from './followingDotCursor.js'
export * from './bubbleCursor.js';
export * from './emojiCursor.js';
-export * from './ghostCursor.js';
\ No newline at end of file
+export * from './ghostCursor.js';
+export * from './rainbowCursor.js';
\ No newline at end of file
diff --git a/src/rainbowCursor.js b/src/rainbowCursor.js
new file mode 100644
index 0000000..6fe4a08
--- /dev/null
+++ b/src/rainbowCursor.js
@@ -0,0 +1,142 @@
+export function rainbowCursor(options) {
+ let hasWrapperEl = options && options.element;
+ let element = hasWrapperEl || document.body;
+
+ let width = window.innerWidth;
+ let height = window.innerHeight;
+ let cursor = { x: width / 2, y: width / 2 };
+ let particles = [];
+ let canvas, context;
+
+ const totalParticles = options?.length || 20;
+ const colors = options?.colors || [
+ "#FE0000",
+ "#FD8C00",
+ "#FFE500",
+ "#119F0B",
+ "#0644B3",
+ "#C22EDC",
+ ]
+ const size = options.size || 3
+
+ let cursorsInitted = false;
+
+ function init() {
+ canvas = document.createElement("canvas");
+ context = canvas.getContext("2d");
+ canvas.style.top = "0px";
+ canvas.style.left = "0px";
+ canvas.style.pointerEvents = "none";
+
+ if (hasWrapperEl) {
+ canvas.style.position = "absolute";
+ element.appendChild(canvas);
+ canvas.width = element.clientWidth;
+ canvas.height = element.clientHeight;
+ } else {
+ canvas.style.position = "fixed";
+ document.body.appendChild(canvas);
+ canvas.width = width;
+ canvas.height = height;
+ }
+
+ bindEvents();
+ loop();
+ }
+
+ // Bind events that are needed
+ function bindEvents() {
+ element.addEventListener("mousemove", onMouseMove);
+ window.addEventListener("resize", onWindowResize);
+ }
+
+ function onWindowResize(e) {
+ width = window.innerWidth;
+ height = window.innerHeight;
+
+ if (hasWrapperEl) {
+ canvas.width = element.clientWidth;
+ canvas.height = element.clientHeight;
+ } else {
+ canvas.width = width;
+ canvas.height = height;
+ }
+ }
+
+ function onMouseMove(e) {
+ if (hasWrapperEl) {
+ const boundingRect = element.getBoundingClientRect();
+ cursor.x = e.clientX - boundingRect.left;
+ cursor.y = e.clientY - boundingRect.top;
+ } else {
+ cursor.x = e.clientX;
+ cursor.y = e.clientY;
+ }
+
+ if (cursorsInitted === false) {
+ cursorsInitted = true;
+ for (let i = 0; i < totalParticles; i++) {
+ addParticle(cursor.x, cursor.y);
+ }
+ }
+ }
+
+ function addParticle(x, y, image) {
+ particles.push(new Particle(x, y, image));
+ }
+
+ function updateParticles() {
+ context.clearRect(0, 0, width, height);
+ context.lineJoin = "round";
+
+ let particleSets = [];
+
+ let x = cursor.x;
+ let y = cursor.y;
+
+ particles.forEach(function (particle, index, particles) {
+ let nextParticle = particles[index + 1] || particles[0];
+
+ particle.position.x = x;
+ particle.position.y = y;
+
+ particleSets.push({ x: x, y: y });
+
+ x += (nextParticle.position.x - particle.position.x) * 0.4;
+ y += (nextParticle.position.y - particle.position.y) * 0.4;
+ });
+
+ colors.forEach((color, index) => {
+ context.beginPath();
+ context.strokeStyle = color;
+
+ if (particleSets.length) {
+ context.moveTo(
+ particleSets[0].x,
+ particleSets[0].y + index * (size - 1)
+ );
+ }
+
+ particleSets.forEach((set, particleIndex) => {
+ if (particleIndex !== 0) {
+ context.lineTo(set.x, set.y + index * size);
+ }
+ });
+
+ context.lineWidth = size;
+ context.lineCap = "round";
+ context.stroke();
+ });
+ }
+
+ function loop() {
+ updateParticles();
+ requestAnimationFrame(loop);
+ }
+
+ function Particle(x, y) {
+ this.position = { x: x, y: y };
+ }
+
+ init();
+}