first commit

This commit is contained in:
Ronnie 2025-05-26 21:25:19 -04:00
commit dac234a142
4 changed files with 600 additions and 0 deletions

37
README.md Normal file
View file

@ -0,0 +1,37 @@
# HoldThisButton
A fun, interactive web game: see how long you can hold the button. Challenge yourself and share your best time!
## Features
- Sleek dark-themed design
- Animated particle background
- Live timer while holding the button
- Random snarky messages
- Modern, clean UI
- Fully responsive design
## How to Use
1. Open `index.html` in your web browser
2. Press and hold the "Hold Me" button
3. Release to see your time and a snarky comment!
## Technologies Used
- HTML5
- CSS3
- JavaScript
- Particles.js for the animated background
## Local Development
Simply clone the repository and open `index.html` in your browser. No build process or dependencies required!
```bash
git clone https://github.com/Ronniie/HoldThisButton.git
cd HoldThisButton
```
## License
MIT License - feel free to use this project for whatever you want!

79
index.html Normal file
View file

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HoldThisButton | How long can you hold it?</title>
<!-- Favicon -->
<link rel="icon" type="image/png" sizes="32x32" href="https://upload.wikimedia.org/wikipedia/commons/c/c0/Perspective-Button-Search-icon.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://upload.wikimedia.org/wikipedia/commons/c/c0/Perspective-Button-Search-icon.png">
<link rel="apple-touch-icon" href="https://upload.wikimedia.org/wikipedia/commons/c/c0/Perspective-Button-Search-icon.png">
<!-- Theme Colors -->
<meta name="theme-color" content="#0f172a">
<meta name="msapplication-TileColor" content="#0f172a">
<meta name="msapplication-navbutton-color" content="#0f172a">
<meta name="apple-mobile-web-app-status-bar-style" content="#0f172a">
<!-- Primary Meta Tags -->
<meta name="title" content="HoldThisButton | How long can you hold it?">
<meta name="description" content="Test your patience and endurance with our button-holding challenge. How long can you hold the button?">
<meta name="keywords" content="button challenge, hold button, patience test, endurance test">
<meta name="author" content="Ronniie">
<meta name="robots" content="index, follow">
<meta name="language" content="English">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:title" content="HoldThisButton | How long can you hold it?">
<meta property="og:description" content="Test your patience and endurance with our button-holding challenge. How long can you hold the button?">
<meta property="og:image" content="https://upload.wikimedia.org/wikipedia/commons/c/c0/Perspective-Button-Search-icon.png">
<meta property="og:site_name" content="HoldThisButton">
<!-- Twitter -->
<meta property="twitter:card" content="summary">
<meta property="twitter:title" content="HoldThisButton | How long can you hold it?">
<meta property="twitter:description" content="Test your patience and endurance with our button-holding challenge. How long can you hold the button?">
<meta property="twitter:image" content="https://upload.wikimedia.org/wikipedia/commons/c/c0/Perspective-Button-Search-icon.png">
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<!-- styles -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- particles container -->
<div id="particles-js"></div>
<div class="container">
<h1 class="title">HoldThisButton</h1>
<div class="message-container">
<span id="message" class="message">Ready to test your patience?</span>
</div>
<div class="timer-container">
<span id="timer" class="timer">0.00s</span>
</div>
<button id="holdButton" class="hold-button">
<span>Hold Me</span>
</button>
<div class="result-container" id="resultContainer">
<span id="result" class="result"></span>
</div>
<div class="footer">
<span class="website">whatsthatbutton.ronniie.dev</span>
</div>
</div>
<!-- scripts -->
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script src="script.js"></script>
</body>
</html>

270
script.js Normal file
View file

@ -0,0 +1,270 @@
// Initialize particles.js
particlesJS('particles-js', {
particles: {
number: {
value: 80,
density: {
enable: true,
value_area: 800
}
},
color: {
value: '#ffffff'
},
shape: {
type: 'circle'
},
opacity: {
value: 0.5,
random: false
},
size: {
value: 3,
random: true
},
line_linked: {
enable: true,
distance: 150,
color: '#ffffff',
opacity: 0.4,
width: 1
},
move: {
enable: true,
speed: 2,
direction: 'none',
random: false,
straight: false,
out_mode: 'out',
bounce: false
}
},
interactivity: {
detect_on: 'canvas',
events: {
onhover: {
enable: true,
mode: 'grab'
},
onclick: {
enable: true,
mode: 'push'
},
resize: true
}
},
retina_detect: true
});
// DOM elements
const holdButton = document.getElementById('holdButton');
const timer = document.getElementById('timer');
const message = document.getElementById('message');
const resultContainer = document.getElementById('resultContainer');
const result = document.getElementById('result');
// Variables
let startTime;
let timerInterval;
let isHolding = false;
let buttonText = holdButton.querySelector('span');
// Random messages while holding
const holdingMessages = [
"Time is just a construct, right?",
"You're transcending reality.",
"The universe is watching you.",
"Is your arm okay?",
"Do you do this for sport?",
"You're redefining persistence.",
"You're officially holding reality together.",
"Just you and the void now.",
"What are you trying to prove?",
"I hope you're charging rent for your dedication.",
"This is borderline mythological.",
"Even statues blink eventually.",
"Are you trying to summon something?",
"You're writing history with your finger.",
"Blink twice if you're stuck.",
"You might be stuck in a time loop.",
"Legends start just like this.",
"Have you considered letting go... just kidding!",
"Still? I'm out of things to say!",
"I should be charging for this show.",
"You're more committed than some relationships.",
"Your screen is going to imprint your fingerprint.",
"Can we get a slow clap going?",
"You're raising the bar and then some.",
"I'm starting to believe you're a machine.",
"Even the code is impressed.",
"Reality might bend soon.",
"You're a digital monk now.",
"Still holding? Your screen says hi.",
"This is what dedication smells like... probably.",
"If effort was money, you'd be a billionaire.",
"Time is melting around you.",
"Every second, you enter deeper legend.",
"You may be achieving enlightenment.",
"This is your legacy now.",
"You clearly dont fear cramps.",
"Heroes don't always wear capes.",
"I'm speechless... you're not.",
"You're holding like the Wi-Fi signal depends on it.",
"I think you unlocked ultra-hold mode.",
"Even gravity is impressed.",
"You're ignoring the laws of boredom.",
"This isn't even your final form.",
"The simulation is glitching just watching you.",
"You're becoming folklore.",
"Youve reached the point of no return.",
"You broke the give-up meter.",
"You outlasted my motivational quotes.",
"Are you aiming for the Guinness World Record?",
"At this point, I'm emotionally invested.",
"You're becoming legend in real time.",
"All of this for what? Oh right—immortality.",
"Hold level: Ascended.",
"You're now an honorary statue.",
"Existential crises start here.",
"You're challenging the laws of patience.",
"Your willpower could power a small town.",
"You're so deep in, I cant let you stop.",
"This is how digital devotion looks.",
"Youll need a recovery arc after this.",
"Even Im nervous for you.",
"Youve reached overachiever mode.",
"You're passing into the mythos now.",
"The button might be scared of you.",
"I think you just invented a new sport.",
"This is your endurance saga.",
"Still holding. The stars are aligning.",
"Youre one hold away from godhood.",
"Your thumb deserves its own biography.",
"There are monks less dedicated than this.",
"Youre holding onto greatness—literally.",
"Youve entered the Matrix hold level.",
"Reality checks in... still holding.",
"Are your bones okay?",
"You're breaking records in another dimension.",
"You're now holding the universe together.",
"Your phone might evolve from this.",
"NASA might want to study you.",
"You're showing the world what's possible.",
"The screen is probably sweating now.",
"Who needs sleep when you have this?",
"I bet the device is questioning its purpose.",
"You're entering final form: Hold God.",
"Still? I'm writing a song about you.",
"This isn't holding—it's art.",
"I can feel the strain through the code.",
"You're distorting time with your will.",
"You're holding like a black hole grips light.",
"You may have just glitched reality.",
"Youre now part of the code.",
"A statue couldnt keep up with you.",
"Youre outperforming machines.",
"Your name shall echo through holding halls.",
"Still here? Youre writing digital lore.",
"This is holdvana. Welcome.",
"If there was a throne, you'd sit on it.",
"Youve held longer than most people dream.",
"Reality salutes your grip.",
"You're in another timeline now.",
"I hope this gets written in history books.",
"You're unshakable. Literally.",
"I stopped counting. You're still holding.",
"A galaxy was born during this hold."
];
// Snarky result messages
const resultMessages = [
"You should screenshot this as no one will believe you",
"That's... actually pretty impressive",
"Did you use tape or something?",
"Your finger must be numb by now",
"That's a new world record... probably",
"Are you okay? That's a long time",
"Your patience is... concerning",
"Did you fall asleep?",
"That's dedication right there",
"Your finger deserves a medal"
];
// Format time
function formatTime(ms) {
return (ms / 1000).toFixed(2) + 's';
}
// Update timer display
function updateTimer() {
const currentTime = Date.now();
const elapsedTime = currentTime - startTime;
timer.textContent = formatTime(elapsedTime);
}
// Get random message from array
function getRandomMessage(array) {
return array[Math.floor(Math.random() * array.length)];
}
// Change message with animation
function changeMessage(newMessage) {
message.classList.remove('changed');
void message.offsetWidth; // Trigger reflow
message.textContent = newMessage;
message.classList.add('changed');
}
// Start holding
holdButton.addEventListener('mousedown', () => {
if (!isHolding) {
isHolding = true;
startTime = Date.now();
timerInterval = setInterval(updateTimer, 10);
resultContainer.classList.remove('show');
buttonText.textContent = "Holding...";
// Start random messages
const messageInterval = setInterval(() => {
if (isHolding) {
changeMessage(getRandomMessage(holdingMessages));
} else {
clearInterval(messageInterval);
}
}, 3000);
}
});
// Stop holding
holdButton.addEventListener('mouseup', () => {
if (isHolding) {
isHolding = false;
clearInterval(timerInterval);
const finalTime = Date.now() - startTime;
// Show result
result.textContent = `${formatTime(finalTime)} - ${getRandomMessage(resultMessages)}`;
resultContainer.classList.add('show');
// Reset message and button text
message.textContent = "Ready to try again?";
buttonText.textContent = "Hold Me";
}
});
// Prevent context menu on long press
holdButton.addEventListener('contextmenu', (e) => {
e.preventDefault();
});
// Handle touch events for mobile
holdButton.addEventListener('touchstart', (e) => {
e.preventDefault();
holdButton.dispatchEvent(new MouseEvent('mousedown'));
});
holdButton.addEventListener('touchend', (e) => {
e.preventDefault();
holdButton.dispatchEvent(new MouseEvent('mouseup'));
});

214
styles.css Normal file
View file

@ -0,0 +1,214 @@
/* reset some default browser styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* main page styles */
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #0f172a;
position: relative;
overflow: hidden;
}
/* particles container */
#particles-js {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
opacity: 0.3;
}
/* center everything */
.container {
text-align: center;
padding: 2rem;
position: relative;
z-index: 2;
max-width: 800px;
width: 90%;
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(20px);
border-radius: 24px;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
/* make the title look nice and fade in */
.title {
font-size: 4rem;
margin-bottom: 2rem;
color: #fff;
font-weight: 800;
background: linear-gradient(135deg, #60a5fa, #c084fc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
opacity: 0;
animation: fadeIn 1s ease forwards;
letter-spacing: -0.02em;
}
/* message container styling */
.message-container {
background: rgba(255, 255, 255, 0.05);
padding: 1.5rem;
border-radius: 16px;
margin-bottom: 2rem;
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.message {
font-size: 1.5rem;
color: #e2e8f0;
display: inline-block;
transition: all 0.3s ease;
font-weight: 500;
}
/* timer container styling */
.timer-container {
margin-bottom: 2rem;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.timer {
font-size: 4rem;
font-weight: 700;
color: #60a5fa;
text-shadow: 0 0 20px rgba(96, 165, 250, 0.3);
font-variant-numeric: tabular-nums;
}
/* hold button styling */
.hold-button {
background: linear-gradient(135deg, #60a5fa, #c084fc);
border: none;
padding: 2rem 4rem;
font-size: 2rem;
color: white;
border-radius: 16px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 600;
box-shadow: 0 0 30px rgba(96, 165, 250, 0.3);
margin-bottom: 2rem;
width: 100%;
max-width: 400px;
position: relative;
overflow: hidden;
}
.hold-button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #c084fc, #60a5fa);
opacity: 0;
transition: opacity 0.3s ease;
z-index: 1;
}
.hold-button:hover::before {
opacity: 1;
}
.hold-button:hover {
transform: translateY(-2px);
box-shadow: 0 0 40px rgba(96, 165, 250, 0.4);
}
.hold-button:active {
transform: translateY(0);
box-shadow: 0 0 20px rgba(96, 165, 250, 0.2);
}
.hold-button span {
position: relative;
z-index: 2;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* result container styling */
.result-container {
background: rgba(255, 255, 255, 0.05);
padding: 1.5rem;
border-radius: 16px;
margin-bottom: 2rem;
opacity: 0;
transform: translateY(20px);
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.result-container.show {
opacity: 1;
transform: translateY(0);
}
.result {
font-size: 1.5rem;
color: #e2e8f0;
font-weight: 500;
}
/* footer styling */
.footer {
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.website {
color: #94a3b8;
font-size: 1rem;
font-weight: 500;
}
/* fade in animation for the title */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* message change animation */
@keyframes messageChange {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.5;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.message.changed {
animation: messageChange 0.3s ease;
}