hi i saw this https://nomy.club/
which looks like the particles in word nomy and it behaves like the particles are coming from front and goes back and fades away how can we create that?
i have already created the particles in word, but unable to think of this coming from front and fading in back or we can say its like a shadow
const createParticle = (
x,
y,
width,
height,
ctx,
color,
particleRadius = 1,
repulsionStrength = 50
) => {
const current = {
x: Math.random() * width,
y: Math.random() * height
};
const destination = {
x,
y
};
let vx = (Math.random() - 0.5) * 10;
let vy = (Math.random() - 0.5) * 10;
const friction = Math.random() * 0.01 + 0.909;
let hasBounced = false; // New flag for single bounce
// Parse baseColor and adjust lightness
const randomLightness = Math.random() * 0.4 + 0.6; // 60% to 100% brightness
const particleColor = adjustColorBrightness("#136173", randomLightness);
return {
render(mouseX, mouseY) {
const a = current.x - mouseX;
const b = current.y - mouseY;
const distance = Math.sqrt(a * a + b * b);
let accX = (destination.x - current.x) / 200;
let accY = (destination.y - current.y) / 200;
if (!hasBounced && distance < repulsionStrength) {
// If within repulsion radius and hasn't bounced yet
accX = -(a / 40);
accY = -(b / 40);
hasBounced = false; // Mark as bounced
}
// Add small random offsets to create random "wave-like" motion
const randomOffsetX = (Math.random() - 0.5) * 2; // Random offset for X
const randomOffsetY = (Math.random() - 0.5) * 2; // Random offset for Y
current.x += randomOffsetX;
current.y += randomOffsetY;
vx += accX;
vy += accY;
vx *= friction;
vy *= friction;
current.x += vx;
current.y += vy;
// Use the dynamic color
ctx.fillStyle = particleColor;
// ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(current.x, current.y, particleRadius, Math.PI * 2, 0);
ctx.fill();
if (distance < repulsionStrength) {
accX = -(a / 40);
accY = -(b / 40);
vx += accX;
vy += accY;
}
}
};
};
// Helper function to adjust brightness
const adjustColorBrightness = (hexColor, brightnessFactor) => {
// Convert hex to RGB
const r = parseInt(hexColor.slice(1, 3), 16);
const g = parseInt(hexColor.slice(3, 5), 16);
const b = parseInt(hexColor.slice(5, 7), 16);
// Adjust brightness
const adjust = (color) =>
Math.min(255, Math.max(0, Math.floor(color * brightnessFactor)));
const baselineIncrease = 10; // Lighten by 20%
const newR = adjust(r * baselineIncrease);
const newG = adjust(g * baselineIncrease);
const newB = adjust(b * baselineIncrease);
// Convert back to hex
return `rgb(${newR}, ${newG}, ${newB})`;
};
export default createParticle;
this is my particle.js
import createParticle from "./particle";
import fromEvent from "../../hooks/fromEvent";
import createPositionTracker from "./positionTracker";
const { getPosition, setPosition } = createPositionTracker();
const numberOfParticlesPerCharacter = 100;
const createTextParticlesAnimation = (
canvas,
colors,
text
) => {
const { setCanvasDimensions, getCanvasDimensions, ctx } = canvas;
if (!ctx) {
return;
}
const { width, height } = getCanvasDimensions();
const colorsLength = colors.length;
const textLength = text?.length;
let particles = [];
const clearCanvas = (width, height) =>
ctx.clearRect(0, 0, width, height);
let time = 0; // Internal time tracker for oscillation
const drawParticles = () => {
const particlesAmount = particles.length;
const { x, y } = getPosition();
time += 1; // Increment the internal time counter
requestAnimationFrame(drawParticles);
clearCanvas(width, height);
for (let i = 0; i < particlesAmount; i++) {
particles[i].render(x, y, time);
}
};
const setUpText = () => {
const canvas = ctx.canvas; // Access the canvas dimensions directly
const width = canvas.width / window.devicePixelRatio; // Adjust for DPI
const height = canvas.height / window.devicePixelRatio;
ctx.font = "bold " + width / 10 + "px sans-serif"; // Dynamic font size
ctx.textAlign = "center"; // Horizontal alignment
ctx.textBaseline = "middle"; // Vertical alignment
const x = width / 2; // Center horizontally
const y = height / 2; // Center vertically
ctx.fillText(text, x, y); // Draw text at the center
ctx.globalCompositeOperation = "screen"; // Composite operation
};
const refreshCanvasDimensions = () => {
const { innerWidth, innerHeight } = window;
setCanvasDimensions(innerWidth, innerHeight);
};
const getRandomIndex = (max) => Math.floor(Math.random() * max);
const createParticles = () => {
refreshCanvasDimensions();
const { width, height } = getCanvasDimensions();
clearCanvas(width, height);
setUpText(width, height);
const { data } = ctx.getImageData(0, 0, width, height);
particles = [];
const numberOfParticles = textLength * numberOfParticlesPerCharacter;
for (let i = 0; i < width; i += Math.round(width / numberOfParticles)) {
for (let j = 0; j < height; j += Math.round(width / numberOfParticles)) {
if (data[(i + j * width) * 4 + 3] > 150) {
const color = colors[getRandomIndex(colorsLength)];
particles.push(createParticle(i, j, width, height, ctx, color));
}
}
}
};
let eventHandlers = null;
const addEventListeners = () => {
const onMouseMove = (e) => {
const rect = canvas.ctx.canvas.getBoundingClientRect(); // Get canvas position
const offsetX = e.clientX - rect.left; // Adjust for canvas position
const offsetY = e.clientY - rect.top; // Adjust for canvas position
setPosition(offsetX, offsetY);
};
const onTouchMove = (e) => {
const rect = canvas.ctx.canvas.getBoundingClientRect(); // Get canvas position
const touch = e.touches[0]; // Get the first touch
const offsetX = touch.clientX - rect.left; // Adjust for canvas position
const offsetY = touch.clientY - rect.top; // Adjust for canvas position
setPosition(offsetX, offsetY);
};
const onTouchEnd = () => setPosition(-9999, -9999);
eventHandlers = [
fromEvent(window, "resize", createParticles),
fromEvent(window, "mousemove", onMouseMove),
fromEvent(window, "touchmove", onTouchMove),
fromEvent(window, "touchend", onTouchEnd),
];
eventHandlers.forEach(({ subscribe }) => subscribe());
};
const start = () => {
if (!eventHandlers) {
addEventListeners();
createParticles();
drawParticles();
}
};
const stop = () => {
if (eventHandlers) {
eventHandlers.forEach(({ unsubscribe }) => unsubscribe());
}
};
return { start, stop };
};
export default createTextParticlesAnimation;
this is my createTextParticlesAnimation.js
can anyone suggest me how can we do that??