first commit

This commit is contained in:
Ronnie 2025-05-29 21:30:12 -04:00
commit 792fbfa5bb
5 changed files with 329 additions and 0 deletions

1
CNAME Normal file
View file

@ -0,0 +1 @@
catchthedot.ronniie.dev

25
README.md Normal file
View file

@ -0,0 +1,25 @@
# Catch the Dot
A fun web-based game where you try to catch elusive dots that multiply and move around the screen. The dots are designed to be challenging to catch, with smooth movement patterns and smart mouse avoidance.
## Features
- Smooth dot movement with physics-based motion
- Dots multiply over time
- Smart mouse avoidance behavior
- Modern UI with glass-morphism effects
- Fullscreen gameplay
- Pacman-style screen wrapping
## How to Play
1. Open `index.html` in a web browser
2. Move your mouse to interact with the dots
3. Watch as the dots multiply and try to catch them
4. The counter shows how many dots are currently on screen
## Technologies Used
- HTML5
- CSS3
- JavaScript (Vanilla)

24
index.html Normal file
View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Catch the Dot</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="game-area">
<div class="game-header">
<h1>Catch the Dot</h1>
<div class="score-container">
<span>Dots: </span>
<span id="dotCount">1</span>
</div>
</div>
<div class="game-footer">
<p class="message">Watch them multiply!</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

157
script.js Normal file
View file

@ -0,0 +1,157 @@
const gameArea = document.querySelector('.game-area');
const dotCountDisplay = document.getElementById('dotCount');
const message = document.querySelector('.message');
let dots = [];
let lastMouseX = 0;
let lastMouseY = 0;
let lastMouseTime = 0;
let mouseVelocityX = 0;
let mouseVelocityY = 0;
class Dot {
constructor(x, y) {
this.element = document.createElement('div');
this.element.className = 'dot';
this.x = x;
this.y = y;
this.velocityX = (Math.random() - 0.5) * 200;
this.velocityY = (Math.random() - 0.5) * 200;
this.lastDuplication = Date.now();
this.acceleration = 0;
gameArea.appendChild(this.element);
this.updatePosition();
}
updatePosition() {
this.element.style.left = `${this.x}px`;
this.element.style.top = `${this.y}px`;
}
move() {
this.velocityX += (Math.random() - 0.5) * 20;
this.velocityY += (Math.random() - 0.5) * 20;
this.x += this.velocityX * 0.016;
this.y += this.velocityY * 0.016;
if (this.x < 0) {
this.x = window.innerWidth;
} else if (this.x > window.innerWidth) {
this.x = 0;
}
if (this.y < 0) {
this.y = window.innerHeight;
} else if (this.y > window.innerHeight) {
this.y = 0;
}
this.velocityX *= 0.98;
this.velocityY *= 0.98;
const currentSpeed = Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
if (currentSpeed < 100) {
const angle = Math.atan2(this.velocityY, this.velocityX);
this.velocityX = Math.cos(angle) * 100;
this.velocityY = Math.sin(angle) * 100;
}
if (currentSpeed > 400) {
const angle = Math.atan2(this.velocityY, this.velocityX);
this.velocityX = Math.cos(angle) * 400;
this.velocityY = Math.sin(angle) * 400;
}
this.updatePosition();
const now = Date.now();
if (now - this.lastDuplication > 3000 && Math.random() < 0.002) {
this.duplicate();
this.lastDuplication = now;
}
}
duplicate() {
if (dots.length < 8) {
const newDot = new Dot(this.x, this.y);
newDot.velocityX = this.velocityX * 1.2;
newDot.velocityY = this.velocityY * 1.2;
dots.push(newDot);
updateDotCount();
}
}
avoidMouse(mouseX, mouseY, mouseVelX, mouseVelY) {
const dx = this.x - mouseX;
const dy = this.y - mouseY;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
const speed = 300;
const mouseSpeed = Math.sqrt(mouseVelX * mouseVelX + mouseVelY * mouseVelY);
const dotToMouseAngle = Math.atan2(dy, dx);
const mouseMovementAngle = Math.atan2(mouseVelY, mouseVelX);
const angleDiff = Math.abs(dotToMouseAngle - mouseMovementAngle);
const distanceFactor = Math.min(1, (300 - distance) / 300);
if (angleDiff < Math.PI / 2) {
const targetSpeed = speed + mouseSpeed * 800 * distanceFactor;
const currentSpeed = Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
const acceleration = Math.min(0.2, (targetSpeed - currentSpeed) / 1000);
this.velocityX = this.velocityX * (1 - acceleration) + Math.cos(dotToMouseAngle) * targetSpeed * acceleration;
this.velocityY = this.velocityY * (1 - acceleration) + Math.sin(dotToMouseAngle) * targetSpeed * acceleration;
}
}
}
}
function updateDotCount() {
dotCountDisplay.textContent = dots.length;
}
function initializeGame() {
const firstDot = new Dot(
Math.random() * window.innerWidth,
Math.random() * window.innerHeight
);
dots.push(firstDot);
updateDotCount();
}
function moveDot(event) {
const currentTime = Date.now();
const timeDiff = currentTime - lastMouseTime;
if (lastMouseTime !== 0) {
mouseVelocityX = (event.clientX - lastMouseX) / timeDiff;
mouseVelocityY = (event.clientY - lastMouseY) / timeDiff;
}
lastMouseX = event.clientX;
lastMouseY = event.clientY;
lastMouseTime = currentTime;
dots.forEach(dot => dot.avoidMouse(event.clientX, event.clientY, mouseVelocityX, mouseVelocityY));
}
function updateDots() {
dots.forEach(dot => dot.move());
requestAnimationFrame(updateDots);
}
gameArea.addEventListener('mousemove', moveDot);
initializeGame();
updateDots();
window.addEventListener('resize', () => {
dots.forEach(dot => {
dot.x = Math.min(dot.x, window.innerWidth);
dot.y = Math.min(dot.y, window.innerHeight);
dot.updatePosition();
});
});

122
styles.css Normal file
View file

@ -0,0 +1,122 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #0f0f0f;
min-height: 100vh;
overflow: hidden;
color: #ffffff;
}
.game-container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
width: 90%;
max-width: 800px;
}
.game-header {
position: fixed;
top: 2rem;
left: 50%;
transform: translateX(-50%);
text-align: center;
z-index: 100;
background: rgba(255, 255, 255, 0.05);
padding: 1.5rem 3rem;
border-radius: 20px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 0.5rem;
background: linear-gradient(45deg, #ff3366, #ff6b6b);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
letter-spacing: -1px;
}
.score-container {
font-size: 1.4rem;
color: #ff3366;
font-weight: 600;
text-shadow: 0 0 20px rgba(255, 51, 102, 0.3);
}
.game-area {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: radial-gradient(circle at center, #1a1a1a 0%, #0f0f0f 100%);
cursor: pointer;
}
.dot {
position: absolute;
width: 24px;
height: 24px;
background: #ff3366;
border-radius: 50%;
transform: translate(-50%, -50%);
transition: transform 0.1s ease-out;
box-shadow: 0 0 30px rgba(255, 51, 102, 0.5);
z-index: 1000;
}
.dot::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
background: rgba(255, 51, 102, 0.3);
border-radius: 50%;
animation: ripple 2s ease-out infinite;
}
.game-footer {
position: fixed;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
text-align: center;
font-size: 1.2rem;
color: #ffffff;
background: rgba(255, 255, 255, 0.05);
padding: 1rem 2rem;
border-radius: 15px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.message {
font-weight: 500;
color: #ff3366;
text-shadow: 0 0 20px rgba(255, 51, 102, 0.3);
}
@keyframes ripple {
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.5; }
100% { transform: translate(-50%, -50%) scale(2); opacity: 0; }
}
@keyframes float {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-10px); }
}