Will be awesome one day, I guarantee you
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at DEV 246 lines 6.6 kB view raw
1const VERSION_BASE = '29.04.2026.'; 2const STORAGE_KEY = 'nepastoucherTime'; 3const GAMEOVER_STORAGE_KEY = 'gameoverTime'; 4const WARNING_DURATION_MS = 10 * 60 * 1000; 5 6const versionEl = document.getElementById('compteur'); 7const contentEl = document.getElementById('content'); 8const preventionEl = document.getElementById('prevention'); 9const choiceButtons = document.querySelectorAll('.nepastoucher'); 10const counterButton = document.getElementById('compteurplusun'); 11const buyAutoClickButton = document.getElementById('achatautoclick'); 12const gameOverButton = document.getElementById('gameover'); 13 14const state = { 15 counter: 1, 16 autoClickCount: 0, 17 autoClickAccumulator: 0, 18 versionFlashColor: '', 19 versionFlashExpiry: 0, 20 autoClickInterval: 1000, 21 isGameOver: false, 22 fallingElements: [], 23 baseGravity: 0.0009, 24 bounceDamping: 0.6 25}; 26 27const formatVersion = () => `Version: ${VERSION_BASE}${state.counter}`; 28 29const updateVersionText = () => { 30 versionEl.textContent = formatVersion(); 31}; 32 33const flashVersion = (color, duration = 500) => { 34 state.versionFlashColor = color; 35 state.versionFlashExpiry = performance.now() + duration; 36 versionEl.style.color = color; 37}; 38 39const getAutoClickCost = () => Math.max(1, Math.round(5 * state.autoClickCount)); 40 41const applyWarningEffect = () => { 42 contentEl.classList.add('rotated'); 43 preventionEl.classList.remove('hidden'); 44 choiceButtons.forEach(button => button.classList.add('hidden')); 45}; 46 47const saveWarningTime = () => { 48 localStorage.setItem(STORAGE_KEY, Date.now().toString()); 49}; 50 51const loadWarningState = () => { 52 const storedTime = localStorage.getItem(STORAGE_KEY); 53 if (!storedTime) { 54 return; 55 } 56 57 const elapsed = Date.now() - Number(storedTime); 58 if (elapsed < WARNING_DURATION_MS) { 59 applyWarningEffect(); 60 } else { 61 localStorage.removeItem(STORAGE_KEY); 62 } 63}; 64 65const saveGameOverTime = () => { 66 localStorage.setItem(GAMEOVER_STORAGE_KEY, Date.now().toString()); 67}; 68 69const loadGameOverState = () => { 70 const storedTime = localStorage.getItem(GAMEOVER_STORAGE_KEY); 71 if (!storedTime) { 72 return; 73 } 74 75 const elapsed = Date.now() - Number(storedTime); 76 if (elapsed < WARNING_DURATION_MS) { 77 state.isGameOver = true; 78 const allButtons = document.querySelectorAll('button'); 79 allButtons.forEach(button => { 80 button.disabled = true; 81 }); 82 prepareFallingElements(); 83 // Move all elements to bottom position immediately 84 state.fallingElements.forEach(entry => { 85 entry.settled = true; 86 entry.velocity = 0; 87 const bottomLimit = window.innerHeight - entry.height; 88 entry.top = bottomLimit; 89 entry.node.style.top = `${entry.top}px`; 90 }); 91 } else { 92 localStorage.removeItem(GAMEOVER_STORAGE_KEY); 93 } 94}; 95 96const prepareFallingElements = () => { 97 const elements = Array.from(document.querySelectorAll('p, button, h1, h2')); 98 99 // First pass: capture all positions before any DOM changes 100 const elementData = elements.map(node => { 101 const rect = node.getBoundingClientRect(); 102 return { 103 node, 104 left: rect.left, 105 top: rect.top, 106 width: rect.width, 107 height: rect.height 108 }; 109 }); 110 111 // Second pass: apply positioning and create fall entries 112 elementData.forEach(data => { 113 const { node, left, top, width, height } = data; 114 115 node.style.position = 'fixed'; 116 node.style.left = `${left}px`; 117 node.style.top = `${top}px`; 118 node.style.width = `${width}px`; 119 node.style.height = `${height}px`; 120 node.style.margin = '0'; 121 node.style.padding = node.style.padding || ''; 122 node.style.boxSizing = 'border-box'; 123 node.style.transition = 'none'; 124 125 state.fallingElements.push({ 126 node, 127 top, 128 width, 129 height, 130 velocity: (Math.random() - 0.5) * 0.3, 131 gravity: state.baseGravity * (0.5 + Math.random()), 132 bounceDamping: state.bounceDamping * (0.5 + Math.random() * 0.5), 133 settled: false 134 }); 135 }); 136}; 137 138const startGameOverFall = () => { 139 if (state.isGameOver) { 140 return; 141 } 142 143 state.isGameOver = true; 144 saveGameOverTime(); 145 146 // Disable all buttons 147 const allButtons = document.querySelectorAll('button'); 148 allButtons.forEach(button => { 149 button.disabled = true; 150 }); 151 152 prepareFallingElements(); 153}; 154 155const tick = (delta) => { 156 if (state.autoClickCount > 0) { 157 state.autoClickAccumulator += delta; 158 const clicks = Math.floor(state.autoClickAccumulator / state.autoClickInterval) * state.autoClickCount; 159 if (clicks > 0) { 160 state.autoClickAccumulator %= state.autoClickInterval; 161 state.counter += clicks; 162 updateVersionText(); 163 } 164 } 165 166 if (state.isGameOver) { 167 state.fallingElements.forEach(entry => { 168 // Apply gravity 169 entry.velocity += entry.gravity * delta; 170 entry.top += entry.velocity * delta; 171 172 const bottomLimit = window.innerHeight - entry.height; 173 174 // Bounce collision 175 if (entry.top >= bottomLimit) { 176 entry.top = bottomLimit; 177 entry.velocity *= -entry.bounceDamping; 178 179 // Stop bouncing when velocity is very small 180 if (Math.abs(entry.velocity) < 0.1) { 181 entry.velocity = 0; 182 entry.settled = true; 183 } 184 } 185 186 entry.node.style.top = `${entry.top}px`; 187 }); 188 } 189 190 if (state.versionFlashExpiry && performance.now() >= state.versionFlashExpiry) { 191 state.versionFlashColor = ''; 192 state.versionFlashExpiry = 0; 193 versionEl.style.color = ''; 194 } 195}; 196 197const gameLoop = (timestamp) => { 198 if (!gameLoop.lastTime) { 199 gameLoop.lastTime = timestamp; 200 } 201 202 const delta = timestamp - gameLoop.lastTime; 203 gameLoop.lastTime = timestamp; 204 205 tick(delta); 206 requestAnimationFrame(gameLoop); 207}; 208 209const init = () => { 210 updateVersionText(); 211 loadWarningState(); 212 loadGameOverState(); 213 214 choiceButtons.forEach(button => { 215 button.addEventListener('click', () => { 216 saveWarningTime(); 217 applyWarningEffect(); 218 }); 219 }); 220 221 counterButton.addEventListener('click', () => { 222 state.counter += 1; 223 updateVersionText(); 224 flashVersion('green', 300); 225 }); 226 227 buyAutoClickButton.addEventListener('click', () => { 228 const cost = getAutoClickCost(); 229 if (state.counter >= cost) { 230 state.counter -= cost; 231 state.autoClickCount += 1; 232 updateVersionText(); 233 flashVersion('yellow', 1000); 234 } else { 235 flashVersion('red', 1000); 236 } 237 }); 238 239 gameOverButton.addEventListener('click', () => { 240 startGameOverFall(); 241 }); 242 243 requestAnimationFrame(gameLoop); 244}; 245 246document.addEventListener('DOMContentLoaded', init);