Skip to content

Instantly share code, notes, and snippets.

@aschmelyun
Created August 14, 2025 23:37
Show Gist options
  • Save aschmelyun/949b3d87dd9c8ad579a9a2fd06794f7e to your computer and use it in GitHub Desktop.
Save aschmelyun/949b3d87dd9c8ad579a9a2fd06794f7e to your computer and use it in GitHub Desktop.
lizard.click source code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#ffffff">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="Lizard">
<title>Lizard</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 60vh;
display: flex;
justify-content: center;
align-items: center;
background: #f0f0f0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
}
.button-3d {
width: 200px;
height: 200px;
background: #ffffff;
border: none;
border-radius: 50%;
cursor: pointer;
font-size: 80px;
display: flex;
justify-content: center;
align-items: center;
touch-action: manipulation;
box-shadow:
0 10px 20px rgba(0, 0, 0, 0.2),
0 6px 10px rgba(0, 0, 0, 0.15),
inset 0 -3px 0 rgba(0, 0, 0, 0.1);
}
.button-3d:hover {
box-shadow:
0 12px 24px rgba(0, 0, 0, 0.2),
0 8px 12px rgba(0, 0, 0, 0.15),
inset 0 -3px 0 rgba(0, 0, 0, 0.1);
}
.button-3d:active {
transform: translateY(4px);
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.2),
0 2px 4px rgba(0, 0, 0, 0.15),
inset 0 -1px 0 rgba(0, 0, 0, 0.1);
}
.emoji {
user-select: none;
}
.animated-emoji {
position: fixed;
font-size: 40px;
pointer-events: none;
z-index: 1000;
opacity: 0;
user-select: none;
}
@keyframes emojiPop {
0% {
opacity: 0;
transform: translateY(100px) scale(0.5);
}
20% {
opacity: 1;
transform: translateY(0) scale(1.2);
}
40% {
transform: translateY(-20px) translateX(10px) scale(1);
}
60% {
transform: translateY(-10px) translateX(-15px) scale(1.1);
}
80% {
transform: translateY(-30px) translateX(20px) scale(0.9);
}
100% {
opacity: 0;
transform: translateY(-50px) translateX(0) scale(0.5);
}
}
.animated-emoji.show {
animation: emojiPop 2s ease-out forwards;
}
.counter {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
padding: 8px 12px;
border-radius: 20px;
font-size: 15px;
font-weight: bold;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
user-select: none;
}
.personal-counter {
position: absolute;
top: 20px;
right: 220px;
background: rgba(255, 255, 255, 0.9);
padding: 8px 12px;
border-radius: 20px;
font-size: 15px;
font-weight: bold;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
user-select: none;
}
@media (prefers-color-scheme: dark) {
body {
background: #1a1a1a;
}
.button-3d {
background: #2d2d2d;
box-shadow:
0 10px 20px rgba(0, 0, 0, 0.4),
0 6px 10px rgba(0, 0, 0, 0.3),
inset 0 -3px 0 rgba(0, 0, 0, 0.2);
}
.button-3d:hover {
box-shadow:
0 12px 24px rgba(0, 0, 0, 0.4),
0 8px 12px rgba(0, 0, 0, 0.3),
inset 0 -3px 0 rgba(0, 0, 0, 0.2);
}
.button-3d:active {
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.4),
0 2px 4px rgba(0, 0, 0, 0.3),
inset 0 -1px 0 rgba(0, 0, 0, 0.2);
}
.counter, .personal-counter {
background: rgba(45, 45, 45, 0.9);
color: white;
}
.unmute-notification {
background: rgba(45, 45, 45, 0.9);
color: white;
}
}
.unmute-notification {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(255, 255, 255, 0.9);
padding: 8px 16px;
border-radius: 16px;
font-size: 14px;
color: #333;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
user-select: none;
z-index: 1000;
white-space: nowrap;
max-width: 90vw;
text-align: center;
}
@media (max-width: 480px) {
.unmute-notification {
font-size: 12px;
padding: 6px 12px;
}
}
</style>
</head>
<body>
<div class="personal-counter" id="personalCounter">My Clicks: 0</div>
<button class="button-3d" id="emojiButton">
<span class="emoji">🦎</span>
</button>
<div class="unmute-notification">Unmute your phone if you don't hear sound 🔊</div>
<script>
const button = document.getElementById('emojiButton');
const personalCounter = document.getElementById('personalCounter');
let personalClickCount = 0;
const audioPool = [];
const poolSize = 5;
let currentAudioIndex = 0;
let audioBuffer = null;
let audioContext = null;
function initializeAudioContext() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
return audioContext;
}
async function loadAudioBuffer() {
if (audioBuffer) return audioBuffer;
try {
const audioCtx = initializeAudioContext();
const response = await fetch('lizard.wav');
const arrayBuffer = await response.arrayBuffer();
audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
return audioBuffer;
} catch (error) {
console.log('Failed to load audio buffer, falling back to HTML Audio:', error);
return null;
}
}
for (let i = 0; i < poolSize; i++) {
const audio = new Audio('lizard.wav');
audio.preload = 'auto';
audio.volume = 1.0;
audioPool.push(audio);
}
function loadPersonalClickCount() {
const saved = localStorage.getItem('personalClickCount');
personalClickCount = saved ? parseInt(saved, 10) : 0;
updatePersonalCounterDisplay();
}
function savePersonalClickCount() {
localStorage.setItem('personalClickCount', personalClickCount.toString());
}
function updatePersonalCounterDisplay() {
const formatter = new Intl.NumberFormat('en-US');
personalCounter.textContent = `My Clicks: ${formatter.format(personalClickCount)}`;
}
function createAnimatedEmoji() {
const emoji = document.createElement('div');
emoji.className = 'animated-emoji';
emoji.textContent = '🦎';
const x = Math.random() * (window.innerWidth - 100);
const y = Math.random() * (window.innerHeight * 0.6) + (window.innerHeight * 0.2);
emoji.style.left = x + 'px';
emoji.style.top = y + 'px';
document.body.appendChild(emoji);
setTimeout(() => emoji.classList.add('show'), 10);
setTimeout(() => {
if (emoji.parentNode) {
document.body.removeChild(emoji);
}
}, 2000);
}
async function playSound() {
// Try Web Audio API first for better performance
if (audioBuffer && audioContext) {
try {
const audioCtx = audioContext;
if (audioCtx.state === 'suspended') {
await audioCtx.resume();
}
const source = audioCtx.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioCtx.destination);
source.start(0);
createAnimatedEmoji();
return;
} catch (error) {
console.log('Web Audio API failed, falling back to HTML Audio:', error);
}
}
const audio = audioPool[currentAudioIndex];
if (!audio.paused) {
audio.pause();
}
audio.currentTime = 0;
try {
await audio.play();
} catch (error) {
currentAudioIndex = (currentAudioIndex + 1) % poolSize;
}
createAnimatedEmoji();
currentAudioIndex = (currentAudioIndex + 1) % poolSize;
}
button.addEventListener('click', () => {
// Always play sound immediately - highest priority
playSound();
// Update personal counter immediately
personalClickCount++;
updatePersonalCounterDisplay();
savePersonalClickCount();
});
// Initialize audio system and preload files when page loads
window.addEventListener('load', async () => {
// Initialize Web Audio API and load buffer
try {
await loadAudioBuffer();
} catch (error) {
console.log('Web Audio initialization failed, using HTML Audio fallback');
}
// Preload HTML Audio fallback files
audioPool.forEach(audio => {
audio.load();
});
// Load personal click count from localStorage
loadPersonalClickCount();
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment