added moving star and meteorites
This commit is contained in:
parent
2e961232f1
commit
fd57d47956
5 changed files with 480 additions and 25 deletions
|
|
@ -205,7 +205,7 @@
|
||||||
We began with a vision to create high-quality free software,
|
We began with a vision to create high-quality free software,
|
||||||
particularly in gaming where such options are often limited. We
|
particularly in gaming where such options are often limited. We
|
||||||
recognized that many free software games either lack polish or
|
recognized that many free software games either lack polish or
|
||||||
simply don't exist, inspiring us to focus on this underserved
|
simply don't exist, inspiring us to focus on this under-served
|
||||||
area.
|
area.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -481,14 +481,16 @@
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- JavaScript Files -->
|
<!-- General scripts -->
|
||||||
<script src="src/js/main.js"></script>
|
<script src="src/js/main.js"></script>
|
||||||
<script src="src/js/stars.js"></script>
|
|
||||||
<script src="src/js/navigation.js"></script>
|
<script src="src/js/navigation.js"></script>
|
||||||
<script src="src/js/form.js"></script>
|
<script src="src/js/form.js"></script>
|
||||||
<script src="src/js/portfolioCard.js"></script>
|
<script src="src/js/portfolioCard.js"></script>
|
||||||
<script src="src/js/portfolioFilter.js"></script>
|
<script src="src/js/portfolioFilter.js"></script>
|
||||||
<script src="src/js/overview.js"></script>
|
<script src="src/js/overview.js"></script>
|
||||||
<script src="src/js/sectionTracker.js"></script>
|
<script src="src/js/sectionTracker.js"></script>
|
||||||
|
|
||||||
|
<!-- Animation scripts -->
|
||||||
|
<script type="module" src="src/js/animation/starBackground.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
319
src/js/animation/Meteor.js
Normal file
319
src/js/animation/Meteor.js
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
class Meteor {
|
||||||
|
constructor(container) {
|
||||||
|
this.element = document.createElement("div");
|
||||||
|
this.element.style.position = "absolute";
|
||||||
|
this.container = container;
|
||||||
|
this.speed = Math.random() * 3 + 4;
|
||||||
|
this.life = 1.0;
|
||||||
|
this.particles = [];
|
||||||
|
|
||||||
|
// Enhanced color palette
|
||||||
|
this.colorType = Math.floor(Math.random() * 4);
|
||||||
|
this.colors = this.getMeteorColors();
|
||||||
|
|
||||||
|
// Get container dimensions for pixel-based positioning
|
||||||
|
this.containerRect = container.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Start from random edge with PIXEL-based positioning
|
||||||
|
const edge = Math.floor(Math.random() * 4);
|
||||||
|
if (edge === 0) {
|
||||||
|
// Top
|
||||||
|
this.x = Math.random() * this.containerRect.width;
|
||||||
|
this.y = -20;
|
||||||
|
} else if (edge === 1) {
|
||||||
|
// Right
|
||||||
|
this.x = this.containerRect.width + 20;
|
||||||
|
this.y = Math.random() * this.containerRect.height;
|
||||||
|
} else if (edge === 2) {
|
||||||
|
// Bottom
|
||||||
|
this.x = Math.random() * this.containerRect.width;
|
||||||
|
this.y = this.containerRect.height + 20;
|
||||||
|
} else {
|
||||||
|
// Left
|
||||||
|
this.x = -20;
|
||||||
|
this.y = Math.random() * this.containerRect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// More dynamic movement patterns
|
||||||
|
const centerX = this.containerRect.width / 2 + (Math.random() - 0.5) * 200;
|
||||||
|
const centerY = this.containerRect.height / 2 + (Math.random() - 0.5) * 200;
|
||||||
|
this.angle =
|
||||||
|
Math.atan2(centerY - this.y, centerX - this.x) +
|
||||||
|
(Math.random() - 0.5) * 0.8;
|
||||||
|
this.dx = Math.cos(this.angle) * this.speed;
|
||||||
|
this.dy = Math.sin(this.angle) * this.speed;
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
getMeteorColors() {
|
||||||
|
const colorSchemes = [
|
||||||
|
{
|
||||||
|
head: "rgba(255, 255, 255, 1)",
|
||||||
|
core: "rgba(255, 230, 150, 0.9)",
|
||||||
|
mid: "rgba(255, 180, 80, 0.7)",
|
||||||
|
outer: "rgba(255, 100, 50, 0.5)",
|
||||||
|
glow: "rgba(255, 200, 100, 0.9)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
head: "rgba(255, 255, 255, 1)",
|
||||||
|
core: "rgba(180, 220, 255, 0.9)",
|
||||||
|
mid: "rgba(100, 180, 255, 0.7)",
|
||||||
|
outer: "rgba(50, 100, 255, 0.5)",
|
||||||
|
glow: "rgba(100, 180, 255, 0.9)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
head: "rgba(255, 255, 255, 1)",
|
||||||
|
core: "rgba(220, 180, 255, 0.9)",
|
||||||
|
mid: "rgba(200, 100, 255, 0.7)",
|
||||||
|
outer: "rgba(180, 50, 255, 0.5)",
|
||||||
|
glow: "rgba(200, 150, 255, 0.9)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
head: "rgba(255, 255, 255, 1)",
|
||||||
|
core: "rgba(180, 255, 200, 0.9)",
|
||||||
|
mid: "rgba(80, 255, 150, 0.7)",
|
||||||
|
outer: "rgba(50, 200, 100, 0.5)",
|
||||||
|
glow: "rgba(150, 255, 180, 0.9)",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return colorSchemes[this.colorType];
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const size = Math.random() * 4 + 10;
|
||||||
|
const colors = this.colors;
|
||||||
|
|
||||||
|
// Create enhanced meteor head with multiple layers
|
||||||
|
const head = document.createElement("div");
|
||||||
|
head.style.width = `${size}px`;
|
||||||
|
head.style.height = `${size}px`;
|
||||||
|
head.style.borderRadius = "50%";
|
||||||
|
head.style.background = `
|
||||||
|
radial-gradient(
|
||||||
|
circle at 30% 30%,
|
||||||
|
${colors.head} 0%,
|
||||||
|
${colors.core} 30%,
|
||||||
|
${colors.mid} 60%,
|
||||||
|
${colors.outer} 100%
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
head.style.boxShadow = `
|
||||||
|
0 0 ${size * 4}px ${colors.glow},
|
||||||
|
0 0 ${size * 2}px rgba(255, 255, 255, 0.8),
|
||||||
|
inset 0 0 ${size * 0.5}px rgba(255, 255, 255, 0.9)
|
||||||
|
`;
|
||||||
|
head.style.position = "absolute";
|
||||||
|
head.style.left = "50%";
|
||||||
|
head.style.top = "50%";
|
||||||
|
head.style.transform = "translate(-50%, -50%)";
|
||||||
|
head.style.zIndex = "3";
|
||||||
|
head.style.filter = "blur(0.5px)";
|
||||||
|
|
||||||
|
// Create multi-layer tail
|
||||||
|
this.createTailLayer(size * 3, size * 1.2, colors.core, 1, "1px");
|
||||||
|
this.createTailLayer(size * 5, size * 2, colors.mid, 0.6, "2px");
|
||||||
|
this.createTailLayer(size * 8, size * 3, colors.outer, 0.3, "3px");
|
||||||
|
|
||||||
|
// Assemble meteor
|
||||||
|
this.element.appendChild(head);
|
||||||
|
this.element.style.left = `${this.x}px`;
|
||||||
|
this.element.style.top = `${this.y}px`;
|
||||||
|
this.element.style.zIndex = "10";
|
||||||
|
this.element.style.filter = "blur(0.5px)";
|
||||||
|
|
||||||
|
this.head = head;
|
||||||
|
this.size = size;
|
||||||
|
|
||||||
|
this.container.appendChild(this.element);
|
||||||
|
|
||||||
|
// Add trail particles
|
||||||
|
this.createTrailParticles();
|
||||||
|
}
|
||||||
|
|
||||||
|
createTailLayer(length, width, color, opacity, blur) {
|
||||||
|
const tail = document.createElement("div");
|
||||||
|
const tailAngle = Math.atan2(this.dy, this.dx) + Math.PI;
|
||||||
|
|
||||||
|
tail.style.width = `${length}px`;
|
||||||
|
tail.style.height = `${width}px`;
|
||||||
|
tail.style.position = "absolute";
|
||||||
|
tail.style.left = "50%";
|
||||||
|
tail.style.top = "50%";
|
||||||
|
tail.style.transformOrigin = "left center";
|
||||||
|
tail.style.transform = `translate(0, -50%) rotate(${tailAngle}rad)`;
|
||||||
|
tail.style.background = `linear-gradient(to right,
|
||||||
|
${color} 0%,
|
||||||
|
${color.replace(")", ", 0.8)").replace("rgba", "rgba")} 20%,
|
||||||
|
${color.replace(")", ", 0.4)").replace("rgba", "rgba")} 50%,
|
||||||
|
${color.replace(")", ", 0.1)").replace("rgba", "rgba")} 80%,
|
||||||
|
transparent 100%)`;
|
||||||
|
tail.style.opacity = opacity;
|
||||||
|
tail.style.filter = `blur(${blur})`;
|
||||||
|
tail.style.pointerEvents = "none";
|
||||||
|
tail.style.zIndex = "2";
|
||||||
|
tail.style.borderRadius = "0 50% 50% 0";
|
||||||
|
|
||||||
|
this.element.appendChild(tail);
|
||||||
|
this.tail = tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
createTrailParticles() {
|
||||||
|
// Create initial trail particles
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
this.addTrailParticle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addTrailParticle() {
|
||||||
|
const particle = document.createElement("div");
|
||||||
|
const size = Math.random() * 2 + 1;
|
||||||
|
const colors = this.colors;
|
||||||
|
|
||||||
|
particle.style.width = `${size}px`;
|
||||||
|
particle.style.height = `${size}px`;
|
||||||
|
particle.style.borderRadius = "50%";
|
||||||
|
particle.style.background = colors.mid;
|
||||||
|
particle.style.position = "absolute";
|
||||||
|
particle.style.left = `${this.x}px`;
|
||||||
|
particle.style.top = `${this.y}px`;
|
||||||
|
particle.style.boxShadow = `0 0 ${size * 3}px ${colors.glow}`;
|
||||||
|
particle.style.opacity = "0.7";
|
||||||
|
particle.style.zIndex = "1";
|
||||||
|
particle.style.pointerEvents = "none";
|
||||||
|
|
||||||
|
this.container.appendChild(particle);
|
||||||
|
|
||||||
|
this.particles.push({
|
||||||
|
element: particle,
|
||||||
|
life: 1.0,
|
||||||
|
x: this.x,
|
||||||
|
y: this.y,
|
||||||
|
vx: (Math.random() - 0.5) * 0.5,
|
||||||
|
vy: (Math.random() - 0.5) * 0.5,
|
||||||
|
size: size,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
// Smooth pixel-based movement
|
||||||
|
this.x += this.dx;
|
||||||
|
this.y += this.dy;
|
||||||
|
this.life -= 0.005;
|
||||||
|
|
||||||
|
// Use pixel positioning for smooth movement
|
||||||
|
this.element.style.left = `${this.x}px`;
|
||||||
|
this.element.style.top = `${this.y}px`;
|
||||||
|
this.element.style.opacity = this.life;
|
||||||
|
|
||||||
|
// Update tail direction
|
||||||
|
const tailAngle = Math.atan2(this.dy, this.dx) + Math.PI;
|
||||||
|
const tails = this.element.querySelectorAll("div:not(.particle)");
|
||||||
|
tails.forEach((tail) => {
|
||||||
|
if (tail !== this.head) {
|
||||||
|
tail.style.transform = `translate(0, -50%) rotate(${tailAngle}rad)`;
|
||||||
|
tail.style.opacity = this.life;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add new trail particles periodically
|
||||||
|
if (Math.random() < 0.3) {
|
||||||
|
this.addTrailParticle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update existing particles with pixel positioning
|
||||||
|
for (let i = this.particles.length - 1; i >= 0; i--) {
|
||||||
|
const p = this.particles[i];
|
||||||
|
p.life -= 0.02;
|
||||||
|
p.x += p.vx;
|
||||||
|
p.y += p.vy;
|
||||||
|
|
||||||
|
p.element.style.left = `${p.x}px`;
|
||||||
|
p.element.style.top = `${p.y}px`;
|
||||||
|
p.element.style.opacity = p.life;
|
||||||
|
p.element.style.transform = `scale(${p.life})`;
|
||||||
|
|
||||||
|
if (p.life <= 0) {
|
||||||
|
p.element.remove();
|
||||||
|
this.particles.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced removal condition with fading
|
||||||
|
if (
|
||||||
|
this.x < -50 ||
|
||||||
|
this.x > this.containerRect.width + 50 ||
|
||||||
|
this.y < -50 ||
|
||||||
|
this.y > this.containerRect.height + 50 ||
|
||||||
|
this.life <= 0
|
||||||
|
) {
|
||||||
|
// Fade out particles
|
||||||
|
this.particles.forEach((p) => {
|
||||||
|
p.element.style.transition = "opacity 0.5s";
|
||||||
|
p.element.style.opacity = "0";
|
||||||
|
setTimeout(() => p.element.remove(), 500);
|
||||||
|
});
|
||||||
|
this.remove();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
// Add explosion effect when meteor dies
|
||||||
|
if (this.life > 0.3) {
|
||||||
|
this.createExplosion();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.remove();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
createExplosion() {
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const particle = document.createElement("div");
|
||||||
|
const size = Math.random() * 3 + 2;
|
||||||
|
const colors = this.colors;
|
||||||
|
|
||||||
|
particle.style.width = `${size}px`;
|
||||||
|
particle.style.height = `${size}px`;
|
||||||
|
particle.style.borderRadius = "50%";
|
||||||
|
particle.style.background = colors.core;
|
||||||
|
particle.style.position = "absolute";
|
||||||
|
particle.style.left = `${this.x}px`;
|
||||||
|
particle.style.top = `${this.y}px`;
|
||||||
|
particle.style.boxShadow = `0 0 ${size * 4}px ${colors.glow}`;
|
||||||
|
particle.style.opacity = "0.8";
|
||||||
|
particle.style.zIndex = "2";
|
||||||
|
|
||||||
|
this.container.appendChild(particle);
|
||||||
|
|
||||||
|
// Animate explosion
|
||||||
|
const angle = (i / 8) * Math.PI * 2;
|
||||||
|
const distance = Math.random() * 20 + 10;
|
||||||
|
const duration = Math.random() * 500 + 500;
|
||||||
|
|
||||||
|
particle.animate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
transform: "translate(0, 0) scale(1)",
|
||||||
|
opacity: 0.8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
transform: `translate(${Math.cos(angle) * distance}px, ${
|
||||||
|
Math.sin(angle) * distance
|
||||||
|
}px) scale(0.1)`,
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: duration,
|
||||||
|
easing: "cubic-bezier(0.4, 0, 0.2, 1)",
|
||||||
|
}
|
||||||
|
).onfinish = () => particle.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Meteor;
|
||||||
64
src/js/animation/Star.js
Normal file
64
src/js/animation/Star.js
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
class Star {
|
||||||
|
constructor(container) {
|
||||||
|
this.element = document.createElement("div");
|
||||||
|
this.element.classList.add("star");
|
||||||
|
this.container = container;
|
||||||
|
this.speed = Math.random() * 0.5 + 0.1;
|
||||||
|
|
||||||
|
// Random direction angle (0 to 360 degrees)
|
||||||
|
this.angle = Math.random() * Math.PI * 2;
|
||||||
|
this.dx = Math.cos(this.angle) * this.speed;
|
||||||
|
this.dy = Math.sin(this.angle) * this.speed;
|
||||||
|
|
||||||
|
this.x = Math.random() * 100;
|
||||||
|
this.y = Math.random() * 100;
|
||||||
|
|
||||||
|
// Add color variation
|
||||||
|
this.color = this.getRandomStarColor();
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomStarColor() {
|
||||||
|
const colors = [
|
||||||
|
"rgba(255, 255, 255, 0.9)", // Pure white
|
||||||
|
"rgba(255, 250, 200, 0.9)", // Warm white
|
||||||
|
"rgba(200, 220, 255, 0.9)", // Cool blue-white
|
||||||
|
"rgba(255, 220, 180, 0.9)", // Yellow-white
|
||||||
|
"rgba(180, 200, 255, 0.9)", // Blue-white
|
||||||
|
];
|
||||||
|
return colors[Math.floor(Math.random() * colors.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const size = Math.random() * 3 + 0.5;
|
||||||
|
this.element.style.width = `${size}px`;
|
||||||
|
this.element.style.height = `${size}px`;
|
||||||
|
this.element.style.left = `${this.x}%`;
|
||||||
|
this.element.style.top = `${this.y}%`;
|
||||||
|
this.element.style.background = this.color;
|
||||||
|
this.element.style.boxShadow = `0 0 ${size * 2}px ${this.color}`;
|
||||||
|
this.element.style.animationDelay = `${Math.random() * 5}s`;
|
||||||
|
this.element.style.animationDuration = `${3 + Math.random() * 4}s`;
|
||||||
|
this.container.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.x += this.dx * 0.05;
|
||||||
|
this.y += this.dy * 0.05;
|
||||||
|
|
||||||
|
// Wrap around when star goes off screen
|
||||||
|
if (this.y > 100) this.y = 0;
|
||||||
|
if (this.y < 0) this.y = 100;
|
||||||
|
if (this.x > 100) this.x = 0;
|
||||||
|
if (this.x < 0) this.x = 100;
|
||||||
|
|
||||||
|
this.element.style.left = `${this.x}%`;
|
||||||
|
this.element.style.top = `${this.y}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
this.element.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Star;
|
||||||
92
src/js/animation/starBackground.js
Normal file
92
src/js/animation/starBackground.js
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import Star from "./Star.js";
|
||||||
|
import Meteor from "./Meteor.js";
|
||||||
|
|
||||||
|
// State
|
||||||
|
const starInstances = [];
|
||||||
|
const meteorInstances = [];
|
||||||
|
|
||||||
|
// Enhanced star creation with more stars
|
||||||
|
function createStars() {
|
||||||
|
const stars = document.getElementById("stars");
|
||||||
|
const count = 400; // More stars for richer background
|
||||||
|
stars.innerHTML = "";
|
||||||
|
starInstances.length = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const star = new Star(stars);
|
||||||
|
starInstances.push(star);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject required CSS for star animations
|
||||||
|
function injectStarCSS() {
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.textContent = `
|
||||||
|
.star {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: twinkle ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes twinkle {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.3; }
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
// More frequent meteor spawning with variable rates
|
||||||
|
function trySpawnMeteor() {
|
||||||
|
const spawnChance = 0.12; // Increased spawn rate
|
||||||
|
if (Math.random() < spawnChance) {
|
||||||
|
const stars = document.getElementById("stars");
|
||||||
|
const newMeteor = new Meteor(stars);
|
||||||
|
meteorInstances.push(newMeteor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced animation loop
|
||||||
|
function animateStars() {
|
||||||
|
starInstances.forEach((star) => star.update());
|
||||||
|
|
||||||
|
// Update meteors and remove dead ones
|
||||||
|
for (let i = meteorInstances.length - 1; i >= 0; i--) {
|
||||||
|
if (!meteorInstances[i].update()) {
|
||||||
|
meteorInstances.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(animateStars);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meteor burst effect
|
||||||
|
function createMeteorBurst() {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const stars = document.getElementById("stars");
|
||||||
|
const newMeteor = new Meteor(stars);
|
||||||
|
meteorInstances.push(newMeteor);
|
||||||
|
}, i * 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize everything
|
||||||
|
function init() {
|
||||||
|
injectStarCSS();
|
||||||
|
createStars();
|
||||||
|
animateStars();
|
||||||
|
|
||||||
|
// More frequent meteor spawning
|
||||||
|
setInterval(trySpawnMeteor, 2000);
|
||||||
|
|
||||||
|
// Add occasional meteor bursts
|
||||||
|
setInterval(createMeteorBurst, 15000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start when DOM is ready
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
// Create stellar background
|
|
||||||
function createStars() {
|
|
||||||
const stars = document.getElementById("stars");
|
|
||||||
const count = 250;
|
|
||||||
stars.innerHTML = ""; // Clear any existing stars
|
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
const star = document.createElement("div");
|
|
||||||
star.classList.add("star");
|
|
||||||
|
|
||||||
const size = Math.random() * 3;
|
|
||||||
star.style.width = `${size}px`;
|
|
||||||
star.style.height = `${size}px`;
|
|
||||||
|
|
||||||
star.style.left = `${Math.random() * 100}%`;
|
|
||||||
star.style.top = `${Math.random() * 100}%`;
|
|
||||||
|
|
||||||
star.style.animationDelay = `${Math.random() * 5}s`;
|
|
||||||
|
|
||||||
stars.appendChild(star);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue