MatteoScript commited on
Commit
90149fa
·
verified ·
1 Parent(s): 8bca7fc

Create play.html

Browse files
Files changed (1) hide show
  1. play.html +599 -0
play.html ADDED
@@ -0,0 +1,599 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="it">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+ <title>INNOVATION RUN - Matteo Bergamelli</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700;800&display=swap" rel="stylesheet">
9
+ <style>
10
+ :root { --neon-green: #00ff41; --legacy-gold: #ffb700; --error-red: #ff0055; --bg-dark: #0a0a0a; }
11
+ body { background: #0a0a0a; color: #e0e0e0; font-family: 'JetBrains Mono', monospace; overflow: hidden; user-select: none; }
12
+ canvas { display: block; width: 100%; height: 100%; }
13
+
14
+ .scanlines { background: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0) 50%, rgba(0,0,0,0.1) 50%, rgba(0,0,0,0.1)); background-size: 100% 4px; position: absolute; top: 0; left: 0; right: 0; bottom: 0; pointer-events: none; z-index: 10; }
15
+ .ui-panel { backdrop-filter: blur(5px); background: rgba(20, 20, 20, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); transition: all 0.2s; }
16
+
17
+ .btn { background: var(--neon-green); color: #000; padding: 15px 40px; font-size: 1.2rem; font-weight: 800; text-transform: uppercase; cursor: pointer; border-radius: 4px; box-shadow: 0 0 20px rgba(0, 255, 65, 0.4); transition: 0.2s; border: none; }
18
+ .btn:hover { transform: scale(1.05); background: #fff; box-shadow: 0 0 40px rgba(0, 255, 65, 0.6); }
19
+
20
+ .flow-container { width: 200px; height: 12px; background: #333; border-radius: 6px; overflow: hidden; position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); z-index: 20; border: 2px solid #555; }
21
+ .flow-bar { height: 100%; width: 0%; background: linear-gradient(90deg, #ffb700, #00ff41); transition: width 0.1s linear; }
22
+ .flow-text { position: absolute; bottom: 48px; left: 50%; transform: translateX(-50%); font-size: 0.8rem; color: #fff; text-transform: uppercase; font-weight: bold; text-shadow: 0 2px 4px #000; width: 100%; text-align: center; }
23
+
24
+ /* MODIFICATO: Animazione più lenta e posizione iniziale spostata */
25
+ .floating-message {
26
+ position: absolute;
27
+ font-weight: 800;
28
+ font-size: 1.2rem; /* Leggermente più grande */
29
+ text-align: left;
30
+ pointer-events: none;
31
+ text-shadow: 2px 2px 0px #000;
32
+ z-index: 50;
33
+ white-space: nowrap;
34
+ animation: floatRightUp 3.5s cubic-bezier(0.23, 1, 0.32, 1) forwards;
35
+ }
36
+
37
+ @keyframes floatRightUp {
38
+ 0% { opacity: 0; transform: translate(0, 20px) scale(0.5); }
39
+ 10% { opacity: 1; transform: translate(20px, -20px) scale(1.2); }
40
+ 70% { opacity: 1; transform: translate(40px, -80px) scale(1); }
41
+ 100% { opacity: 0; transform: translate(60px, -120px) scale(0.9); }
42
+ }
43
+
44
+ .motivational-banner { position: absolute; top: 20%; width: 100%; text-align: center; font-size: 2.5rem; font-weight: 800; color: #fff; text-shadow: 0 0 20px var(--neon-green); pointer-events: none; z-index: 40; opacity: 0; transition: all 0.5s; letter-spacing: 2px; }
45
+
46
+ .combo-display { position: absolute; top: 45%; right: 8%; font-size: 3rem; font-weight: 900; color: #fff; text-shadow: 4px 4px 0px #ff0055; opacity: 0; transition: all 0.3s; z-index: 45; transform: rotate(-10deg); text-align: right; pointer-events: none; font-style: italic; }
47
+
48
+ .hidden { display: none !important; }
49
+ </style>
50
+ </head>
51
+ <body>
52
+
53
+ <div id="game-container" style="position: relative; width: 100vw; height: 100vh; background: radial-gradient(circle at center, #1a1a1a 0%, #000 100%); overflow: hidden;">
54
+ <div class="scanlines"></div>
55
+ <canvas id="gameCanvas"></canvas>
56
+
57
+ <div id="motivator" class="motivational-banner"></div>
58
+ <div id="combo" class="combo-display"></div>
59
+
60
+ <div style="position: absolute; top: 0; left: 0; width: 100%; padding: 1rem; display: flex; justify-content: space-between; z-index: 20; pointer-events: none;">
61
+ <div class="ui-panel" style="padding: 0.5rem 1rem; border-radius: 0.25rem;">
62
+ <div style="font-size: 10px; color: #999;" id="lbl-phase">FASE PROGETTO</div>
63
+ <div id="phase-display" style="color: #00ff41; font-weight: bold; font-size: 1.125rem;"></div>
64
+ </div>
65
+ <div class="ui-panel" style="padding: 0.5rem 1rem; border-radius: 0.25rem; text-align: right;">
66
+ <div style="font-size: 10px; color: #999;" id="lbl-metrics">KPI</div>
67
+ <div style="color: white; font-size: 0.875rem;">
68
+ <span id="lbl-score">PUNTI</span>: <span id="score-display" style="color: #00ff41; font-weight: bold;">0</span> |
69
+ <span id="lbl-legacy">LEGACY</span>: <span id="legacy-display" style="color: #ffb700; font-weight: bold;">0</span>%
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="flow-text" id="flow-label"></div>
75
+ <div class="flow-container"><div id="flow-bar" class="flow-bar"></div></div>
76
+
77
+ <div id="start-screen" style="position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 30; background: rgba(0,0,0,0.92); backdrop-filter: blur(8px); padding: 1rem;">
78
+ <h1 id="title-main" style="font-size: 3.5rem; font-weight: bold; color: white; margin-bottom: 0.5rem; text-align: center; text-shadow: 0 0 20px #00ff41; line-height: 1.1;"></h1>
79
+ <h2 id="subtitle-main" style="color: #00ff41; font-size: 1rem; margin-bottom: 2rem; font-weight: bold; text-align: center; max-width: 600px;"></h2>
80
+
81
+ <div style="background: #111; border: 1px solid #444; padding: 1.5rem; border-radius: 0.5rem; max-width: 30rem; width: 100%; margin-bottom: 2rem; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.5);">
82
+ <div style="display: flex; flex-direction: column; gap: 1rem; font-size: 0.875rem;">
83
+ <div style="display: flex; align-items: center;">
84
+ <span id="icon-legacy" style="font-size: 2rem; margin-right: 0.75rem;"></span>
85
+ <div><span id="title-legacy" style="color: #ffb700; font-weight: bold;"></span><p id="desc-legacy" style="color: #999; font-size: 0.75rem; margin: 0;"></p></div>
86
+ </div>
87
+ <div style="display: flex; align-items: center;">
88
+ <span id="icon-ai" style="font-size: 2rem; margin-right: 0.75rem;"></span>
89
+ <div><span id="title-ai" style="color: #00ff41; font-weight: bold;"></span><p id="desc-ai" style="color: #999; font-size: 0.75rem; margin: 0;"></p></div>
90
+ </div>
91
+ <div style="display: flex; align-items: center;">
92
+ <span id="icon-obs" style="font-size: 2rem; margin-right: 0.75rem;"></span>
93
+ <div><span id="title-obs" style="color: #ff0055; font-weight: bold;"></span><p id="desc-obs" style="color: #999; font-size: 0.75rem; margin: 0;"></p></div>
94
+ </div>
95
+ <div style="display: flex; align-items: center;">
96
+ <span style="font-size: 2rem; margin-right: 0.75rem;">⚡</span>
97
+ <div><span id="title-bar" style="color: white; font-weight: bold;"></span><p id="desc-bar" style="color: #999; font-size: 0.75rem; margin: 0;"></p></div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+
102
+ <button id="btn-start" class="btn" onclick="initGame()"></button>
103
+ <p id="controls-hint" style="margin-top: 1rem; font-size: 0.75rem; color: #ccc; animation: pulse 2s infinite;"></p>
104
+ </div>
105
+
106
+ <div id="game-over" class="hidden" style="position: absolute; inset: 0; flex-direction: column; align-items: center; justify-content: center; z-index: 40; background: rgba(0,0,0,0.95);">
107
+ <h2 id="go-title" style="font-size: 2.5rem; font-weight: bold; color: white; margin-bottom: 1rem; text-align: center;"></h2>
108
+ <div style="text-align: center; font-size: 0.875rem; color: #ccc; margin-bottom: 2rem; background: #1a1a1a; padding: 1.5rem; border: 1px solid #444; border-radius: 0.5rem; max-width: 24rem; width: 100%;">
109
+ <p id="go-reason" style="color: #ff0055; font-weight: bold; margin-bottom: 1rem;"></p>
110
+ <div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;"><span>MVP Score:</span><span id="final-score" style="color: #00ff41; font-weight: bold;">0</span></div>
111
+ <div style="display: flex; justify-content: space-between; margin-bottom: 1rem;"><span>Modernizzazione:</span><span id="final-legacy" style="color: #ffb700; font-weight: bold;">0%</span></div>
112
+ <hr style="border-color: #444; margin: 1rem 0;">
113
+ <p id="death-quote" style="font-style: italic; color: #999; font-size: 0.75rem;"></p>
114
+ </div>
115
+ <button id="btn-restart" class="btn" onclick="initGame()"></button>
116
+ </div>
117
+ </div>
118
+
119
+ <script>
120
+ /**
121
+ * ==========================================================================================
122
+ * ⚙️ CONFIGURAZIONE DI GIOCO - MATTEO INNOVATION LAB EDITION
123
+ * ==========================================================================================
124
+ */
125
+ const GAME_CONFIG = {
126
+ SPEED: {
127
+ INITIAL: 5.8,
128
+ MAX: 14.0,
129
+ ACCELERATION: 0.0007,
130
+ BOOST: 3.5
131
+ },
132
+ GRAVITY: 0.45,
133
+ JUMP_FORCE: -10.8,
134
+
135
+ TEXTS: {
136
+ TITLE: "Innovation Run",
137
+ SUBTITLE: "// Missione: Crea un PoC visionario OMNICANALE",
138
+ LBL_PHASE: "STATUS MENTALE",
139
+ LBL_METRICS: "LIVELLO HYPE",
140
+ LBL_SCORE: "STIMA DEL CAPO",
141
+ LBL_LEGACY: "BUG RISOLTI",
142
+ START_BTN: "Corri verso l'innovazione",
143
+ RESTART_BTN: "CTRL+Z E RIPROVA",
144
+ CONTROLS: "Premi SPAZIO per saltare i problemi | GIÙ per schivare le riunioni",
145
+ BAR_EMPTY: "CERCA ISPIRAZIONE...",
146
+ BAR_FULL: "🔥 MODALITÀ GENIO ATTIVA! 🔥"
147
+ },
148
+
149
+ // ORA CON LISTE DI MESSAGGI RANDOM!
150
+ ENTITIES: {
151
+ LEGACY: {
152
+ CHAR: '☕',
153
+ COLOR: '#FFC107', // Giallo Oro
154
+ TITLE: "CAFFÈ DOPPIO",
155
+ DESC: "Senza questo non si compila. [+10 Punti]",
156
+ MSG: [
157
+ "CAFFÈ DOPPIO!",
158
+ "ENERGIA PURA!",
159
+ "COMPILAZIONE OK!",
160
+ "BUGIORNO!",
161
+ "FOCUS ON!"
162
+ ]
163
+ },
164
+ AI: {
165
+ CHAR: '🤖',
166
+ COLOR: '#00D4FF', // Azzurro Ciano
167
+ TITLE: "VERTEX AI",
168
+ DESC: "Non ti sostituisce, ti AMPLIFICA. [GOD MODE]",
169
+ MSG: [
170
+ "GEMINI MI AMPLIFICA!",
171
+ "COPILOT ATTIVO!",
172
+ "INTELLIGENZA++",
173
+ "SALTO NEL FUTURO!",
174
+ "HYPE BOOST!"
175
+ ]
176
+ },
177
+ OBSTACLE: {
178
+ CHAR: '🧱',
179
+ COLOR: '#FF3D00', // Rosso Arancio
180
+ TITLE: "OLD STYLE",
181
+ DESC: "'Si è sempre fatto così', 'Costa troppo'. SALTALA!",
182
+ MSG: [
183
+ "NON TI SENTO!",
184
+ "BYE BYE SILOS!",
185
+ "SALTO IL MEETING!",
186
+ "INNOVAZIONE VERA!",
187
+ "BUROCRAZIA KO!"
188
+ ]
189
+ },
190
+ BAR: {
191
+ TITLE: "BARRA DELL'INNOVAZIONE",
192
+ DESC: "Riempi la barra per far approvare il budget."
193
+ }
194
+ },
195
+
196
+ MOTIVATIONAL: [
197
+ "MA SUL MIO PC FUNZIONA!",
198
+ "È COLPA DELLA CACHE!",
199
+ "CHI HA TOCCATO IL SERVER?!",
200
+ "PUSHATO IN PRODUZIONE!",
201
+ "NON È UN BUG, È UNA FEATURE!",
202
+ "HO COMMENTATO IL CODICE (MENTI!)",
203
+ "STACCA E RIATTACCA!",
204
+ "PIÙ PYTHON, MENO PPTX!",
205
+ "OMNICHANNEL A VITA!",
206
+ "DOSSOBUONO CAPUT MUNDI!"
207
+ ],
208
+
209
+ COMBO_PHRASES: [
210
+ "DAJE DEV!",
211
+ "CODICE POETICO!",
212
+ "MIRACOLO TECNICO!",
213
+ "SENIOR DEV AURA!",
214
+ "ANGULAR GOAL!",
215
+ "ZERO CONFLITTI GIT!",
216
+ "MVP LEGGENDARIO!",
217
+ "AUMENTO SUBITO!",
218
+ "FERMATEMI!",
219
+ "QUESTO È IL FUTURO!",
220
+ "BRIVIDO AI!",
221
+ "DOSSOBUONO POWER!"
222
+ ],
223
+
224
+ GAME_OVER_TITLES: [
225
+ "SCHERMATA BLU",
226
+ "TI HANNO MESSO IN UN'ALTRA CALL",
227
+ "HAI CANCELLATO IL DATABASE",
228
+ "IL WI-FI TI HA TRADITO"
229
+ ],
230
+ GAME_OVER_REASONS: [
231
+ "Sei finito in un tunnel di burocrazia.",
232
+ "Hai accettato una riunione venerdì alle 17:30.",
233
+ "Il Legacy Code ha avuto la meglio.",
234
+ "Ti sei dimenticato la WHERE nel DELETE * FROM..."
235
+ ],
236
+ DEATH_QUOTES: [
237
+ "\"Tranquillo, il backup è... aspetta, c'era un backup vero?\"",
238
+ "\"Vabbè, diciamo che era solo un test di carico.\"",
239
+ "\"Se nessuno se ne è accorto, non è successo niente.\"",
240
+ "\"Prova a dare la colpa allo stagista.\"",
241
+ "\"Riavvia il router e prega.\""
242
+ ],
243
+
244
+ PHASES: [
245
+ { score: 0, name: "ULTIMO ARRIVATO" },
246
+ { score: 150, name: "QUELLO BRAVO COL PC" },
247
+ { score: 400, name: "HACKER DI PROVINCIA" },
248
+ { score: 700, name: "VISIONARIO TECH" },
249
+ { score: 1200, name: "RE DELL'INNOVATION LAB 👑" }
250
+ ]
251
+ };
252
+
253
+ /* ================= ENGINE START ================= */
254
+ const canvas = document.getElementById('gameCanvas');
255
+ const ctx = canvas.getContext('2d');
256
+ const GRAVITY = GAME_CONFIG.GRAVITY;
257
+ const JUMP = GAME_CONFIG.JUMP_FORCE;
258
+ const DOUBLE_JUMP = GAME_CONFIG.JUMP_FORCE * 0.9;
259
+ const GROUND_H = 80;
260
+
261
+ let state = { playing: false, speed: GAME_CONFIG.SPEED.INITIAL, score: 0, legacy: 0, flow: 50, frame: 0, phaseIdx: 0, shake: 0, combo: 0 };
262
+ let player = { x: 80, y: 0, w: 35, h: 35, dy: 0, grounded: false, canDouble: false, amplified: 0, stretch: 1 };
263
+ let entities = [], particles = [], bgStars = [];
264
+
265
+ const dom = {
266
+ start: document.getElementById('start-screen'),
267
+ over: document.getElementById('game-over'),
268
+ score: document.getElementById('score-display'),
269
+ legacy: document.getElementById('legacy-display'),
270
+ phase: document.getElementById('phase-display'),
271
+ bar: document.getElementById('flow-bar'),
272
+ barLabel: document.getElementById('flow-label'),
273
+ finalScore: document.getElementById('final-score'),
274
+ finalLegacy: document.getElementById('final-legacy'),
275
+ deathQuote: document.getElementById('death-quote'),
276
+ motivator: document.getElementById('motivator'),
277
+ combo: document.getElementById('combo'),
278
+ goTitle: document.getElementById('go-title'),
279
+ goReason: document.getElementById('go-reason')
280
+ };
281
+
282
+ function setupUI() {
283
+ //document.getElementById('title-main').innerText = GAME_CONFIG.TEXTS.TITLE;
284
+ //document.getElementById('subtitle-main').innerText = GAME_CONFIG.TEXTS.SUBTITLE;
285
+ document.getElementById('lbl-phase').innerText = GAME_CONFIG.TEXTS.LBL_PHASE;
286
+ document.getElementById('lbl-metrics').innerText = GAME_CONFIG.TEXTS.LBL_METRICS;
287
+ document.getElementById('lbl-score').innerText = GAME_CONFIG.TEXTS.LBL_SCORE;
288
+ document.getElementById('lbl-legacy').innerText = GAME_CONFIG.TEXTS.LBL_LEGACY;
289
+ document.getElementById('btn-start').innerText = GAME_CONFIG.TEXTS.START_BTN;
290
+ document.getElementById('btn-restart').innerText = GAME_CONFIG.TEXTS.RESTART_BTN;
291
+ document.getElementById('controls-hint').innerText = GAME_CONFIG.TEXTS.CONTROLS;
292
+
293
+ // Use first element of array for description preview if needed, or just static text
294
+ document.getElementById('icon-legacy').innerText = GAME_CONFIG.ENTITIES.LEGACY.CHAR;
295
+ document.getElementById('title-legacy').innerText = GAME_CONFIG.ENTITIES.LEGACY.TITLE;
296
+ document.getElementById('desc-legacy').innerText = GAME_CONFIG.ENTITIES.LEGACY.DESC;
297
+
298
+ document.getElementById('icon-ai').innerText = GAME_CONFIG.ENTITIES.AI.CHAR;
299
+ document.getElementById('title-ai').innerText = GAME_CONFIG.ENTITIES.AI.TITLE;
300
+ document.getElementById('desc-ai').innerText = GAME_CONFIG.ENTITIES.AI.DESC;
301
+
302
+ document.getElementById('icon-obs').innerText = GAME_CONFIG.ENTITIES.OBSTACLE.CHAR;
303
+ document.getElementById('title-obs').innerText = GAME_CONFIG.ENTITIES.OBSTACLE.TITLE;
304
+ document.getElementById('desc-obs').innerText = GAME_CONFIG.ENTITIES.OBSTACLE.DESC;
305
+
306
+ document.getElementById('title-bar').innerText = GAME_CONFIG.ENTITIES.BAR.TITLE;
307
+ document.getElementById('desc-bar').innerText = GAME_CONFIG.ENTITIES.BAR.DESC;
308
+ }
309
+
310
+ function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; state.groundY = canvas.height - GROUND_H; }
311
+ window.addEventListener('resize', resize);
312
+ setupUI();
313
+ resize();
314
+
315
+ for(let i=0; i<80; i++) bgStars.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, size: Math.random() * 2 });
316
+
317
+ function initGame() {
318
+ Object.assign(state, { playing: true, speed: GAME_CONFIG.SPEED.INITIAL, score: 0, legacy: 0, flow: 50, frame: 0, phaseIdx: 0, shake: 0, combo: 0 });
319
+ Object.assign(player, { y: state.groundY - player.h, dy: 0, grounded: true, amplified: 0, stretch: 1 });
320
+ entities = []; particles = [];
321
+
322
+ dom.start.style.display = 'none';
323
+ dom.over.classList.add('hidden');
324
+ dom.over.style.display = 'none';
325
+ dom.motivator.style.opacity = 0;
326
+ dom.combo.style.opacity = 0;
327
+
328
+ dom.phase.innerText = GAME_CONFIG.PHASES[0].name;
329
+
330
+ updateHUD();
331
+ requestAnimationFrame(loop);
332
+ }
333
+
334
+ function jump() {
335
+ if (!state.playing) return;
336
+ if (player.grounded) {
337
+ player.dy = JUMP;
338
+ player.grounded = false;
339
+ player.stretch = 1.3;
340
+ player.canDouble = state.flow >= 25;
341
+ explosion(player.x + player.w/2, player.y + player.h, 5, '#fff');
342
+ }
343
+ else if (player.canDouble) {
344
+ player.dy = DOUBLE_JUMP;
345
+ player.canDouble = false;
346
+ player.stretch = 1.2;
347
+ state.flow = Math.max(0, state.flow - 25);
348
+ explosion(player.x + player.w/2, player.y + player.h, 15, '#00ff41');
349
+ floatText("ELEVAZIONE", player.x + 40, player.y - 40, '#00ff41'); // Offset right
350
+ }
351
+ updateHUD();
352
+ }
353
+
354
+ window.addEventListener('keydown', e => {
355
+ if (e.code === 'Space' || e.code === 'ArrowUp') { e.preventDefault(); jump(); }
356
+ if (e.code === 'ArrowDown' && !player.grounded) { player.dy += 6; player.stretch = 0.7; }
357
+ });
358
+ window.addEventListener('touchstart', e => { e.preventDefault(); jump(); }, {passive: false});
359
+ window.addEventListener('mousedown', jump);
360
+
361
+ function loop() {
362
+ if (!state.playing) return;
363
+
364
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
365
+ if (state.shake > 0) {
366
+ ctx.translate((Math.random()-0.5)*state.shake, (Math.random()-0.5)*state.shake);
367
+ state.shake *= 0.9;
368
+ if(state.shake < 0.5) state.shake = 0;
369
+ }
370
+
371
+ ctx.fillStyle = '#0a0a0a'; ctx.fillRect(0, 0, canvas.width, canvas.height);
372
+
373
+ if (state.speed < GAME_CONFIG.SPEED.MAX) state.speed += GAME_CONFIG.SPEED.ACCELERATION;
374
+ let currentSpd = state.speed + (player.amplified > 0 ? GAME_CONFIG.SPEED.BOOST : 0);
375
+
376
+ ctx.fillStyle = '#fff';
377
+ bgStars.forEach(s => {
378
+ s.x -= currentSpd * 0.15;
379
+ if(s.x < 0) s.x = canvas.width;
380
+ ctx.globalAlpha = 0.4;
381
+ ctx.fillRect(s.x, s.y, s.size, s.size);
382
+ });
383
+ ctx.globalAlpha = 1;
384
+
385
+ ctx.strokeStyle = '#222'; ctx.lineWidth = 1; ctx.beginPath();
386
+ let offset = (state.frame * currentSpd * 0.4) % 100;
387
+ for (let i = 0; i < canvas.width + 100; i += 100) {
388
+ ctx.moveTo(i - offset, state.groundY);
389
+ ctx.lineTo(i - offset - 150, canvas.height);
390
+ }
391
+ ctx.stroke();
392
+
393
+ updatePlayer();
394
+ manageEntities(currentSpd);
395
+ drawParticles();
396
+
397
+ ctx.shadowBlur = 10; ctx.shadowColor = player.amplified > 0 ? '#00ff41' : '#444';
398
+ ctx.fillStyle = '#111'; ctx.fillRect(0, state.groundY, canvas.width, canvas.height - state.groundY);
399
+ ctx.strokeStyle = '#00ff41'; ctx.lineWidth = 4; ctx.beginPath();
400
+ ctx.moveTo(0, state.groundY); ctx.lineTo(canvas.width, state.groundY); ctx.stroke(); ctx.shadowBlur = 0;
401
+
402
+ if (state.frame % 600 === 0 && state.frame > 100) showMotivation();
403
+
404
+ if (player.amplified > 0) {
405
+ player.amplified--;
406
+ if (player.amplified === 0) floatText("GOD MODE OFF", player.x + 40, player.y - 50, '#aaa');
407
+ }
408
+
409
+ state.frame++;
410
+ requestAnimationFrame(loop);
411
+ }
412
+
413
+ function updatePlayer() {
414
+ player.dy += GRAVITY; player.y += player.dy;
415
+
416
+ if (player.y + player.h > state.groundY) {
417
+ if (!player.grounded) {
418
+ player.stretch = 0.7;
419
+ explosion(player.x + player.w/2, state.groundY, 8, '#aaa');
420
+ }
421
+ player.y = state.groundY - player.h; player.dy = 0; player.grounded = true;
422
+ }
423
+ player.stretch += (1 - player.stretch) * 0.1;
424
+
425
+ let drawH = player.h * player.stretch, drawW = player.w * (1/player.stretch);
426
+ let drawX = player.x + (player.w - drawW)/2, drawY = player.y + (player.h - drawH);
427
+
428
+ ctx.fillStyle = player.amplified > 0 ? ((state.frame % 4 < 2) ? '#fff' : '#00ff41') : '#00ff41';
429
+
430
+ if (state.frame % 3 === 0) particles.push({ x: drawX, y: drawY, w: drawW, h: drawH, life: 0.6, type: 'trail', color: ctx.fillStyle });
431
+
432
+ ctx.shadowColor = ctx.fillStyle; ctx.shadowBlur = 20;
433
+ ctx.fillRect(drawX, drawY, drawW, drawH);
434
+ ctx.fillStyle = '#000'; ctx.fillRect(drawX + drawW*0.6, drawY + drawH*0.2, drawW*0.3, 5); ctx.shadowBlur = 0;
435
+ }
436
+
437
+ function manageEntities(spd) {
438
+ let minGap = 500 - (spd * 8);
439
+ let last = entities[entities.length-1];
440
+
441
+ if (!last || (canvas.width - last.x > minGap)) {
442
+ if (Math.random() > 0.97) return;
443
+
444
+ let typeKey = 'OBSTACLE';
445
+ let rand = Math.random();
446
+ if (rand > 0.6) typeKey = 'LEGACY';
447
+ if (rand > 0.92) typeKey = 'AI';
448
+
449
+ let conf = GAME_CONFIG.ENTITIES[typeKey];
450
+ let h = typeKey === 'OBSTACLE' ? 50 : 40, y = state.groundY - h;
451
+ if (typeKey === 'AI') y -= Math.random() * 80;
452
+
453
+ entities.push({ type: typeKey, conf: conf, x: canvas.width, y: y, w: 40, h: h, active: true });
454
+ }
455
+
456
+ for (let i = entities.length - 1; i >= 0; i--) {
457
+ let e = entities[i];
458
+ e.x -= spd;
459
+ if (e.type !== 'OBSTACLE') e.y += Math.sin(state.frame * 0.08) * 0.7;
460
+
461
+ if (e.active) {
462
+ ctx.strokeStyle = e.conf.COLOR; ctx.lineWidth = 3;
463
+ if (e.type === 'LEGACY') ctx.setLineDash([5,5]); else ctx.setLineDash([]);
464
+ ctx.strokeRect(e.x, e.y, e.w, e.h);
465
+ ctx.font = "28px Arial"; ctx.textAlign = "center";
466
+ ctx.fillText(e.conf.CHAR, e.x + e.w/2, e.y + e.h/2 + 10);
467
+
468
+ if (rectHit(player.x, player.y, player.w, player.h, e.x, e.y, e.w, e.h)) handleHit(e);
469
+ }
470
+ if (e.x + e.w < 0) entities.splice(i, 1);
471
+ }
472
+ }
473
+
474
+ function rectHit(x1, y1, w1, h1, x2, y2, w2, h2) { return x2 < x1 + w1 && x2 + w2 > x1 && y2 < y1 + h1 && y2 + h2 > y1; }
475
+
476
+ function handleHit(e) {
477
+ e.active = false;
478
+
479
+ // Pick RANDOM Message
480
+ let msgList = e.conf.MSG;
481
+ let randomMsg = Array.isArray(msgList) ? msgList[Math.floor(Math.random() * msgList.length)] : msgList;
482
+
483
+ if (e.type === 'OBSTACLE') {
484
+ if (player.amplified > 0) {
485
+ state.shake = 20;
486
+ explosion(e.x + e.w/2, e.y + e.h/2, 25, '#ff0055');
487
+ floatText(randomMsg, e.x + 80, e.y - 20, '#fff'); // White text for destruction
488
+ state.score += 15; state.combo++;
489
+ showCombo();
490
+ } else {
491
+ gameOver();
492
+ }
493
+ } else {
494
+ explosion(e.x + e.w/2, e.y + e.h/2, 12, e.conf.COLOR);
495
+ // Colore del testo uguale all'entità raccolta
496
+ floatText(randomMsg, e.x + 80, e.y - 40, e.conf.COLOR);
497
+
498
+ if (e.type === 'LEGACY') {
499
+ state.legacy += 10; state.score += 10;
500
+ state.flow = Math.min(100, state.flow + 25);
501
+ state.combo++;
502
+ }
503
+ if (e.type === 'AI') {
504
+ player.amplified = 600;
505
+ state.score += 50; state.shake = 8;
506
+ showMotivation();
507
+ state.combo += 3;
508
+ }
509
+ showCombo(); updateHUD();
510
+ }
511
+ }
512
+
513
+ function explosion(x, y, count, color) {
514
+ for(let i=0; i<count; i++) particles.push({ x, y, vx: (Math.random() - 0.5) * 10, vy: (Math.random() - 0.5) * 10, life: 1.0, color, type: 'spark' });
515
+ }
516
+
517
+ function drawParticles() {
518
+ for(let i=particles.length-1; i>=0; i--) {
519
+ let p = particles[i];
520
+ if (p.type === 'trail') {
521
+ ctx.fillStyle = p.color; ctx.globalAlpha = p.life * 0.5;
522
+ ctx.fillRect(p.x, p.y, p.w, p.h);
523
+ ctx.globalAlpha = 1; p.life -= 0.04;
524
+ } else {
525
+ p.x += p.vx; p.y += p.vy; p.vy += 0.3; p.life -= 0.015;
526
+ ctx.fillStyle = p.color; ctx.globalAlpha = p.life;
527
+ ctx.fillRect(p.x, p.y, 5, 5); ctx.globalAlpha = 1;
528
+ }
529
+ if (p.life <= 0) particles.splice(i, 1);
530
+ }
531
+ }
532
+
533
+ // Function modified to shift text right and use new CSS class
534
+ function floatText(txt, x, y, col) {
535
+ let el = document.createElement('div');
536
+ el.className = 'floating-message';
537
+ el.innerText = txt;
538
+ // Spostamento a destra di base (+100px) per evitare il bordo sinistro
539
+ el.style.left = (x + 60) + 'px';
540
+ el.style.top = y + 'px';
541
+ el.style.color = col;
542
+ document.body.appendChild(el);
543
+ // Timeout aumentato per matchare l'animazione CSS
544
+ setTimeout(() => el.remove(), 4000);
545
+ }
546
+
547
+ function showMotivation() {
548
+ let txt = GAME_CONFIG.MOTIVATIONAL[Math.floor(Math.random() * GAME_CONFIG.MOTIVATIONAL.length)];
549
+ dom.motivator.innerText = txt;
550
+ dom.motivator.style.opacity = 1; dom.motivator.style.transform = "scale(1.15)";
551
+ setTimeout(() => { dom.motivator.style.opacity = 0; dom.motivator.style.transform = "scale(1)"; }, 3500);
552
+ }
553
+
554
+ function showCombo() {
555
+ if (state.combo > 1) {
556
+ let phrase = GAME_CONFIG.COMBO_PHRASES[Math.floor(Math.random() * GAME_CONFIG.COMBO_PHRASES.length)];
557
+ dom.combo.innerText = phrase;
558
+ dom.combo.style.opacity = 1; dom.combo.style.transform = 'scale(1.2) rotate(-10deg)';
559
+ setTimeout(() => { dom.combo.style.opacity = 0; dom.combo.style.transform = 'scale(1) rotate(-10deg)'; }, 2000);
560
+ }
561
+ }
562
+
563
+ function updateHUD() {
564
+ dom.score.innerText = state.score;
565
+ dom.legacy.innerText = state.legacy;
566
+ dom.bar.style.width = state.flow + '%';
567
+
568
+ if (state.flow >= 25) {
569
+ dom.bar.style.boxShadow = '0 0 15px #00ff41';
570
+ dom.barLabel.innerText = GAME_CONFIG.TEXTS.BAR_FULL;
571
+ dom.barLabel.style.color = "#00ff41";
572
+ } else {
573
+ dom.bar.style.boxShadow = 'none';
574
+ dom.barLabel.innerText = GAME_CONFIG.TEXTS.BAR_EMPTY;
575
+ dom.barLabel.style.color = "#aaa";
576
+ }
577
+
578
+ let currentPhaseObj = GAME_CONFIG.PHASES.slice().reverse().find(p => state.score >= p.score);
579
+ if (currentPhaseObj && currentPhaseObj.name !== dom.phase.innerText) {
580
+ dom.phase.innerText = currentPhaseObj.name;
581
+ floatText("FASE: " + currentPhaseObj.name, canvas.width/2, canvas.height/2, '#fff');
582
+ }
583
+ }
584
+
585
+ function gameOver() {
586
+ state.playing = false;
587
+ dom.finalScore.innerText = state.score;
588
+ dom.finalLegacy.innerText = state.legacy + "%";
589
+
590
+ dom.goTitle.innerText = GAME_CONFIG.GAME_OVER_TITLES[Math.floor(Math.random() * GAME_CONFIG.GAME_OVER_TITLES.length)];
591
+ dom.goReason.innerText = GAME_CONFIG.GAME_OVER_REASONS[Math.floor(Math.random() * GAME_CONFIG.GAME_OVER_REASONS.length)];
592
+ dom.deathQuote.innerText = GAME_CONFIG.DEATH_QUOTES[Math.floor(Math.random() * GAME_CONFIG.DEATH_QUOTES.length)];
593
+
594
+ dom.over.classList.remove('hidden');
595
+ dom.over.style.display = 'flex';
596
+ }
597
+ </script>
598
+ </body>
599
+ </html>