150 lines
5.3 KiB
JavaScript
150 lines
5.3 KiB
JavaScript
/* ==========================================
|
||
ANIMATION LOGIN - PARTICLE BACKGROUND SYSTEM
|
||
==========================================
|
||
fungsi:
|
||
- Class Particle: Objek partikel dengan posisi & kecepatan
|
||
- Even Distribution: Distribusi partikel merata (15x10 grid)
|
||
- Animate Loop: Pergerakan smooth dengan requestAnimationFrame
|
||
========================================== */
|
||
|
||
|
||
/* ==========================================
|
||
SETUP CONTAINER & CONFIG
|
||
========================================== */
|
||
const particlesContainer = document.getElementById('particles');
|
||
const particleCount = 150; // Total partikel yang dibuat
|
||
const particles = []; // Array untuk simpan semua partikel
|
||
|
||
/* ==========================================
|
||
CLASS PARTICLE - Blueprint untuk setiap partikel
|
||
==========================================
|
||
Properties:
|
||
- x, y: Posisi partikel
|
||
- vx, vy: Kecepatan horizontal & vertikal (velocity)
|
||
- size: Ukuran partikel (2-5px)
|
||
- color: Warna neon random
|
||
========================================== */
|
||
class Particle {
|
||
constructor() {
|
||
// Buat element DOM untuk partikel
|
||
this.element = document.createElement('div');
|
||
this.element.className = 'particle';
|
||
this.reset(); // Initialize posisi & properti
|
||
particlesContainer.appendChild(this.element);
|
||
}
|
||
|
||
/* ==========================================
|
||
RESET - Set/reset properti partikel
|
||
========================================== */
|
||
reset() {
|
||
// Posisi random di seluruh layar
|
||
this.x = Math.random() * window.innerWidth;
|
||
this.y = Math.random() * window.innerHeight;
|
||
|
||
// Kecepatan random (-0.6 sampai +0.6 pixel/frame)
|
||
this.vx = (Math.random() - 0.5) * 1.2;
|
||
this.vy = (Math.random() - 0.5) * 1.2;
|
||
|
||
// Ukuran random (2-5px)
|
||
this.size = Math.random() * 3 + 2;
|
||
|
||
// Array warna neon untuk partikel
|
||
const colors = [
|
||
'#00d9ff', // Cyan
|
||
'#ff00ff', // Magenta
|
||
'#00ffff', // Cyan bright
|
||
'#ff0080', // Pink
|
||
'#9d00ff', // Purple
|
||
'#00ff88' // Green
|
||
];
|
||
|
||
// Pilih warna random dari array
|
||
const color = colors[Math.floor(Math.random() * colors.length)];
|
||
this.element.style.background = color;
|
||
this.element.style.boxShadow = `0 0 15px ${color}`; // Glow effect
|
||
this.element.style.width = `${this.size}px`;
|
||
this.element.style.height = `${this.size}px`;
|
||
|
||
this.updatePosition(); // Update posisi di DOM
|
||
}
|
||
|
||
/* ==========================================
|
||
UPDATE POSITION - Sync posisi ke DOM
|
||
========================================== */
|
||
updatePosition() {
|
||
this.element.style.left = `${this.x}px`;
|
||
this.element.style.top = `${this.y}px`;
|
||
}
|
||
|
||
/* ==========================================
|
||
MOVE - Update posisi berdasarkan velocity
|
||
==========================================
|
||
Fitur: Wrap-around screen (partikel keluar = muncul sisi lain)
|
||
========================================== */
|
||
move() {
|
||
// Update posisi berdasarkan kecepatan
|
||
this.x += this.vx;
|
||
this.y += this.vy;
|
||
|
||
// ♻️ WRAP-AROUND LOGIC
|
||
// Kalau keluar dari kiri → muncul dari kanan
|
||
if (this.x < -10) this.x = window.innerWidth + 10;
|
||
// Kalau keluar dari kanan → muncul dari kiri
|
||
if (this.x > window.innerWidth + 10) this.x = -10;
|
||
// Kalau keluar dari atas → muncul dari bawah
|
||
if (this.y < -10) this.y = window.innerHeight + 10;
|
||
// Kalau keluar dari bawah → muncul dari atas
|
||
if (this.y > window.innerHeight + 10) this.y = -10;
|
||
|
||
this.updatePosition(); // Sync ke DOM
|
||
}
|
||
}
|
||
|
||
/* ==========================================
|
||
EVEN DISTRIBUTION - Distribusi Partikel Merata
|
||
==========================================
|
||
Konsep: Grid 15 kolom x 10 baris (total 150 partikel)
|
||
Biar nggak menumpuk di satu area
|
||
========================================== */
|
||
const cols = 15; // Jumlah kolom
|
||
const rows = 10; // Jumlah baris
|
||
let particleIndex = 0; // Counter partikel yang sudah dibuat
|
||
|
||
// Loop baris
|
||
for (let i = 0; i < rows; i++) {
|
||
// Loop kolom
|
||
for (let j = 0; j < cols; j++) {
|
||
// Guard: stop kalau sudah 150 partikel
|
||
if (particleIndex >= particleCount) break;
|
||
|
||
const particle = new Particle();
|
||
|
||
// ⚙️ DISTRIBUSI MERATA + RANDOM OFFSET
|
||
// Formula: (index / total) × lebar/tinggi layar
|
||
particle.x = (j / cols) * window.innerWidth + (Math.random() - 0.5) * 100;
|
||
particle.y = (i / rows) * window.innerHeight + (Math.random() - 0.5) * 100;
|
||
particle.updatePosition();
|
||
|
||
particles.push(particle); // Simpan ke array
|
||
particleIndex++;
|
||
}
|
||
if (particleIndex >= particleCount) break;
|
||
}
|
||
|
||
/* ==========================================
|
||
ANIMATE - Main Animation Loop
|
||
==========================================
|
||
Menggunakan requestAnimationFrame untuk performa optimal
|
||
(60 FPS, smooth, GPU-accelerated)
|
||
========================================== */
|
||
function animate() {
|
||
// Loop semua partikel dan gerakkan
|
||
particles.forEach(p => p.move());
|
||
|
||
// Request next frame (recursive call)
|
||
// Browser otomatis sync dengan refresh rate monitor
|
||
requestAnimationFrame(animate);
|
||
}
|
||
|
||
// Start animation loop
|
||
animate(); |