dfg
+317
-49
Diff
round #0
+75
-31
style.css
+75
-31
style.css
···
1
-
2
-
3
-
4
-
}
5
-
h1{
6
-
font-weight: 200;
7
-
letter-spacing: 4px;
8
-
font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
1
+
body {
2
+
font-family: monospace;
3
+
margin: 0 20px 20px;
9
4
}
10
-
header {
11
-
display: flex;
12
-
justify-content: space-between;
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
5
6
+
h1 {
7
+
font-weight: 200;
8
+
font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif;
9
+
}
24
10
11
+
h2 {
12
+
display: inline-block;
13
+
}
25
14
15
+
header {
16
+
display: flex;
17
+
justify-content: space-between;
18
+
align-items: center;
19
+
gap: 1rem;
20
+
}
26
21
22
+
header .meta {
23
+
display: flex;
24
+
flex-direction: column;
25
+
}
27
26
27
+
header p {
28
+
margin: 2px;
29
+
position:sticky;
30
+
}
28
31
32
+
@media (max-width: 600px) {
33
+
header {
34
+
flex-direction: column;
35
+
align-items: flex-start;
36
+
}
37
+
38
+
h1 {
39
+
font-size: 1.2em;
40
+
}
41
+
}
29
42
43
+
#content {
44
+
transition: transform 0.3s ease;
45
+
}
30
46
47
+
#content.rotated {
48
+
transform: rotate(180deg);
49
+
}
31
50
51
+
.hidden {
52
+
display: none;
53
+
}
32
54
55
+
#prevention {
56
+
color: red;
57
+
margin: 15px 0;
58
+
}
33
59
60
+
.btns {
61
+
margin: 0 -20px;
62
+
display: flex;
63
+
flex-wrap: wrap;
64
+
gap: 8px;
65
+
width: calc(100% + 40px);
66
+
}
34
67
68
+
.btns button {
69
+
margin: 0;
70
+
padding: 10px 20px;
71
+
font-size: 1em;
72
+
cursor: pointer;
73
+
background-color: black;
74
+
color: white;
75
+
border: 0;
76
+
border-radius: 0;
77
+
outline: none;
78
+
}
35
79
36
-
display: none;
37
-
color: red;
80
+
.btns button:hover {
81
+
background-color: #333;
38
82
}
39
83
40
-
h1::after, h2::after {
41
-
content: '';
42
-
display: block;
43
-
height: 2px;
44
-
background-color: blue;
45
-
margin-top: 5px;
46
-
border-radius: 5px;
84
+
.highlight {
85
+
background-color: rgb(132, 0, 0);
86
+
color: white;
87
+
padding: 0 0.25rem;
88
+
}
47
89
48
-
}
90
+
.btns button.danger-button {
91
+
background-color: red;
92
+
}
+242
-18
script.js
+242
-18
script.js
···
1
-
function applyEffect() {
2
-
document.getElementById('content').style.transform = 'rotate(0.5turn)';
3
-
document.getElementById('nepastoucher').style.display = 'none';
4
-
document.getElementById('prevention').style.display = 'block';
5
-
}
6
-
7
-
window.addEventListener('load', function() {
8
-
const storedTime = localStorage.getItem('nepastoucherTime');
9
-
if (storedTime) {
10
-
const elapsed = Date.now() - parseInt(storedTime);
11
-
12
-
1
+
const VERSION_BASE = '29.04.2026.';
2
+
const STORAGE_KEY = 'nepastoucherTime';
3
+
const GAMEOVER_STORAGE_KEY = 'gameoverTime';
4
+
const WARNING_DURATION_MS = 10 * 60 * 1000;
5
+
6
+
const versionEl = document.getElementById('compteur');
7
+
const contentEl = document.getElementById('content');
8
+
const preventionEl = document.getElementById('prevention');
9
+
const choiceButtons = document.querySelectorAll('.nepastoucher');
10
+
const counterButton = document.getElementById('compteurplusun');
11
+
const buyAutoClickButton = document.getElementById('achatautoclick');
12
+
const gameOverButton = document.getElementById('gameover');
13
+
14
+
const 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
+
27
+
const formatVersion = () => `Version: ${VERSION_BASE}${state.counter}`;
28
+
29
+
const updateVersionText = () => {
30
+
versionEl.textContent = formatVersion();
31
+
};
32
+
33
+
const flashVersion = (color, duration = 500) => {
34
+
state.versionFlashColor = color;
35
+
state.versionFlashExpiry = performance.now() + duration;
36
+
versionEl.style.color = color;
37
+
};
38
+
39
+
const getAutoClickCost = () => Math.max(1, Math.round(5 * state.autoClickCount));
40
+
41
+
const applyWarningEffect = () => {
42
+
contentEl.classList.add('rotated');
43
+
preventionEl.classList.remove('hidden');
44
+
choiceButtons.forEach(button => button.classList.add('hidden'));
45
+
};
46
+
47
+
const saveWarningTime = () => {
48
+
localStorage.setItem(STORAGE_KEY, Date.now().toString());
49
+
};
50
+
51
+
const 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
+
65
+
const saveGameOverTime = () => {
66
+
localStorage.setItem(GAMEOVER_STORAGE_KEY, Date.now().toString());
67
+
};
68
+
69
+
const 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
+
96
+
const 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
+
138
+
const 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
+
155
+
const 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
+
}
13
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
+
197
+
const 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
+
209
+
const 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
+
});
14
238
239
+
gameOverButton.addEventListener('click', () => {
240
+
startGameOverFall();
241
+
});
15
242
16
-
}
17
-
});
243
+
requestAnimationFrame(gameLoop);
244
+
};
18
245
19
-
document.getElementById('nepastoucher').addEventListener('click', function() {
20
-
localStorage.setItem('nepastoucherTime', Date.now());
21
-
applyEffect();
22
-
});
246
+
document.addEventListener('DOMContentLoaded', init);