Update index.html
Browse files- index.html +413 -518
index.html
CHANGED
@@ -2,568 +2,463 @@
|
|
2 |
<html lang="ru">
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
-
<
|
|
|
6 |
<style>
|
7 |
-
/* Глобальные стили */
|
8 |
body {
|
9 |
-
background: linear-gradient(135deg, #1b2838, #0e1a27);
|
10 |
-
color: #c6d4df;
|
11 |
-
font-family: 'Arial', sans-serif;
|
12 |
margin: 0;
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
}
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
padding: 15px;
|
27 |
-
margin-bottom: 30px;
|
28 |
-
display: flex;
|
29 |
-
gap: 20px;
|
30 |
-
border-bottom: 2px solid #67c1f5;
|
31 |
-
backdrop-filter: blur(10px);
|
32 |
border-radius: 10px;
|
33 |
-
|
34 |
-
}
|
35 |
-
|
36 |
-
.nav-button {
|
37 |
-
background: none;
|
38 |
-
border: none;
|
39 |
-
color: #c6d4df;
|
40 |
-
cursor: pointer;
|
41 |
-
padding: 10px 20px;
|
42 |
-
transition: all 0.3s ease;
|
43 |
-
font-size: 16px;
|
44 |
-
border-radius: 5px;
|
45 |
-
}
|
46 |
-
|
47 |
-
.nav-button:hover {
|
48 |
-
color: #67c1f5;
|
49 |
-
background: rgba(103, 193, 245, 0.1);
|
50 |
-
transform: translateY(-2px);
|
51 |
}
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
margin: 100px auto;
|
57 |
-
padding: 40px;
|
58 |
-
background: rgba(23, 26, 33, 0.9);
|
59 |
-
border-radius: 15px;
|
60 |
-
text-align: center;
|
61 |
-
backdrop-filter: blur(10px);
|
62 |
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
63 |
-
border: 1px solid rgba(103, 193, 245, 0.2);
|
64 |
}
|
65 |
-
|
66 |
-
.login-input {
|
67 |
-
width: 100%;
|
68 |
-
padding: 12px;
|
69 |
-
margin: 10px 0;
|
70 |
-
background: rgba(42, 71, 94, 0.5);
|
71 |
-
border: 1px solid rgba(103, 193, 245, 0.3);
|
72 |
-
color: white;
|
73 |
-
border-radius: 5px;
|
74 |
font-size: 16px;
|
75 |
-
|
76 |
-
}
|
77 |
-
|
78 |
-
.login-input:focus {
|
79 |
-
border-color: #67c1f5;
|
80 |
-
box-shadow: 0 0 8px rgba(103, 193, 245, 0.4);
|
81 |
-
outline: none;
|
82 |
-
}
|
83 |
-
|
84 |
-
.error-message {
|
85 |
-
color: #ff4444;
|
86 |
-
margin: 10px 0;
|
87 |
-
display: none;
|
88 |
-
font-size: 14px;
|
89 |
-
}
|
90 |
-
|
91 |
-
/* Карточки игр */
|
92 |
-
.store-grid {
|
93 |
-
display: grid;
|
94 |
-
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
95 |
-
gap: 20px;
|
96 |
-
margin-top: 30px;
|
97 |
-
}
|
98 |
-
|
99 |
-
.game-card {
|
100 |
-
background: rgba(42, 71, 94, 0.7);
|
101 |
-
border-radius: 10px;
|
102 |
-
overflow: hidden;
|
103 |
-
transition: all 0.3s ease;
|
104 |
-
border: 1px solid transparent;
|
105 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
106 |
-
}
|
107 |
-
|
108 |
-
.game-card:hover {
|
109 |
-
border-color: #67c1f5;
|
110 |
-
transform: translateY(-5px);
|
111 |
-
box-shadow: 0 8px 25px rgba(103, 193, 245, 0.3);
|
112 |
-
}
|
113 |
-
|
114 |
-
.game-image {
|
115 |
-
width: 100%;
|
116 |
-
height: 150px;
|
117 |
-
object-fit: cover;
|
118 |
-
border-bottom: 2px solid rgba(103, 193, 245, 0.2);
|
119 |
-
}
|
120 |
-
|
121 |
-
.game-card h3 {
|
122 |
-
margin: 15px;
|
123 |
-
font-size: 18px;
|
124 |
-
color: #67c1f5;
|
125 |
-
}
|
126 |
-
|
127 |
-
.game-card p {
|
128 |
-
margin: 0 15px 15px;
|
129 |
-
font-size: 14px;
|
130 |
-
color: #a8b5c0;
|
131 |
}
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
background:
|
136 |
-
color:
|
137 |
border: none;
|
138 |
-
padding: 12px 25px;
|
139 |
-
cursor: pointer;
|
140 |
-
font-weight: bold;
|
141 |
border-radius: 5px;
|
142 |
-
|
143 |
-
margin: 15px;
|
144 |
-
width: calc(100% - 30px);
|
145 |
-
box-shadow: 0 4px 15px rgba(103, 193, 245, 0.3);
|
146 |
-
}
|
147 |
-
|
148 |
-
.steam-button:hover {
|
149 |
-
transform: translateY(-2px);
|
150 |
-
box-shadow: 0 6px 20px rgba(103, 193, 245, 0.4);
|
151 |
}
|
152 |
-
|
153 |
-
|
154 |
-
background: #2a475e;
|
155 |
-
color: #677a8a;
|
156 |
-
cursor: not-allowed;
|
157 |
-
box-shadow: none;
|
158 |
}
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
padding: 20px;
|
168 |
-
border-radius: 10px;
|
169 |
-
backdrop-filter: blur(10px);
|
170 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
171 |
}
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
height: 150px;
|
176 |
border-radius: 50%;
|
177 |
-
border: 3px solid #67c1f5;
|
178 |
-
box-shadow: 0 4px 15px rgba(103, 193, 245, 0.3);
|
179 |
}
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
color:
|
185 |
-
}
|
186 |
-
|
187 |
-
.profile-level {
|
188 |
-
background: rgba(42, 71, 94, 0.7);
|
189 |
-
padding: 5px 10px;
|
190 |
-
border-radius: 5px;
|
191 |
-
display: inline-block;
|
192 |
-
margin-top: 5px;
|
193 |
-
font-size: 14px;
|
194 |
-
}
|
195 |
-
|
196 |
-
.profile-progress {
|
197 |
-
background: rgba(23, 26, 33, 0.7);
|
198 |
-
height: 10px;
|
199 |
-
border-radius: 5px;
|
200 |
-
margin: 10px 0;
|
201 |
-
overflow: hidden;
|
202 |
-
}
|
203 |
-
|
204 |
-
.profile-progress-bar {
|
205 |
-
background: linear-gradient(135deg, #67c1f5, #4da8d3);
|
206 |
-
height: 100%;
|
207 |
-
width: 30%;
|
208 |
-
border-radius: 5px;
|
209 |
-
}
|
210 |
-
|
211 |
-
/* Друзья */
|
212 |
-
.friends-grid {
|
213 |
-
display: grid;
|
214 |
-
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
215 |
-
gap: 15px;
|
216 |
-
margin-top: 20px;
|
217 |
-
}
|
218 |
-
|
219 |
-
.friend-card {
|
220 |
-
background: rgba(42, 71, 94, 0.7);
|
221 |
padding: 15px;
|
222 |
border-radius: 10px;
|
223 |
-
|
224 |
-
transition: all 0.3s ease;
|
225 |
-
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
226 |
-
}
|
227 |
-
|
228 |
-
.friend-card:hover {
|
229 |
-
transform: translateY(-3px);
|
230 |
-
box-shadow: 0 6px 20px rgba(103, 193, 245, 0.3);
|
231 |
-
}
|
232 |
-
|
233 |
-
.friend-avatar {
|
234 |
-
width: 50px;
|
235 |
-
height: 50px;
|
236 |
-
border-radius: 50%;
|
237 |
-
margin-bottom: 10px;
|
238 |
-
border: 2px solid #67c1f5;
|
239 |
-
}
|
240 |
-
|
241 |
-
/* Анимации */
|
242 |
-
@keyframes fadeIn {
|
243 |
-
from { opacity: 0; transform: translateY(20px); }
|
244 |
-
to { opacity: 1; transform: translateY(0); }
|
245 |
-
}
|
246 |
-
|
247 |
-
.fade-in {
|
248 |
-
animation: fadeIn 0.5s ease-out;
|
249 |
}
|
250 |
</style>
|
251 |
</head>
|
252 |
<body>
|
253 |
-
|
254 |
-
|
255 |
-
<div
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
|
|
|
|
|
|
|
|
|
|
261 |
</div>
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
<
|
269 |
-
|
270 |
-
|
271 |
-
<button class="nav-button" onclick="showSection('payment')">Пополнить баланс</button>
|
272 |
-
<div style="margin-left: auto; display: flex; align-items: center; gap: 10px">
|
273 |
-
Баланс: <span id="balance">0</span> ₴
|
274 |
-
</div>
|
275 |
-
</div>
|
276 |
-
|
277 |
-
<!-- Профиль -->
|
278 |
-
<div id="profileSection">
|
279 |
-
<div class="profile-header">
|
280 |
-
<img src="https://avatars.fastly.steamstatic.com/f5b6269689db341d0d3a7f9574fcc4714b47b055_full.jpg"
|
281 |
-
alt="Аватар" class="profile-avatar">
|
282 |
-
<div class="profile-info">
|
283 |
-
<div class="profile-name">V-SPAN</div>
|
284 |
-
<div>United States</div>
|
285 |
-
<div class="profile-level">Уровень 19</div>
|
286 |
-
<div class="profile-progress">
|
287 |
-
<div class="profile-progress-bar" style="width: 30%"></div>
|
288 |
-
</div>
|
289 |
-
<div>Rookie Miner</div>
|
290 |
-
<div>100 ед. опыта</div>
|
291 |
-
<button class="steam-button">Редактировать профиль</button>
|
292 |
-
</div>
|
293 |
-
</div>
|
294 |
-
|
295 |
-
<div class="profile-section">
|
296 |
-
<h2>О себе</h2>
|
297 |
-
<p>Для знакомых я просто Джонни. 24 Года Не женатый.<br>
|
298 |
-
Пиши желательно по делу или для обычного приятного разговора.<br>
|
299 |
-
𝐃𝐢𝐬𝐜𝐨𝐫𝐝: johnny_raspberry<br>
|
300 |
-
уʙᴧᴇчᴇния: ᴩиᴄоʙᴀниᴇ, чᴛᴇниᴇ ᴋниᴦ, ᴄоздᴀниᴇ и ᴨᴩодᴀжᴀ ᴋниᴦ<br>
|
301 |
-
инᴛᴇᴩᴇᴄы ʙ иᴦᴩᴀх: нᴀᴄᴛоᴧьныᴇ ᴩоᴧᴇʙыᴇ иᴦᴩы, оᴄобᴇнно ᴅᴜɴɢᴇᴏɴs ᴀɴᴅ ᴅʀᴀɢᴏɴs (ᴅɴᴅ)</p>
|
302 |
-
<p>Соси письку, братан. - zakat</p>
|
303 |
-
</div>
|
304 |
-
|
305 |
-
<div class="profile-section">
|
306 |
-
<h2>Друзья</h2>
|
307 |
-
<div class="friends-grid" id="friendsGrid"></div>
|
308 |
-
</div>
|
309 |
-
|
310 |
-
<div class="profile-section">
|
311 |
-
<h2>Библиотека игр</h2>
|
312 |
-
<div id="userGames"></div>
|
313 |
-
</div>
|
314 |
-
</div>
|
315 |
-
|
316 |
-
<!-- Магазин -->
|
317 |
-
<div id="storeSection" style="display: none">
|
318 |
-
<h2>Магазин ВSteam</h2>
|
319 |
-
<div class="store-grid" id="storeGrid"></div>
|
320 |
-
</div>
|
321 |
-
|
322 |
-
<!-- Пополнение баланса -->
|
323 |
-
<div id="paymentSection" style="display: none">
|
324 |
-
<div class="payment-box">
|
325 |
-
<h2 style="text-align: center">Пополнение баланса</h2>
|
326 |
-
<input type="number" class="payment-input" id="amount" placeholder="Сумма в гривнах">
|
327 |
-
<button class="steam-button" style="width: 100%" id="addFundsButton">
|
328 |
-
Мгновенное пополнение ✨
|
329 |
-
</button>
|
330 |
-
<div style="text-align: center; margin-top: 15px; color: #888">
|
331 |
-
(Функция в бета-тесте — деньги не списываются)
|
332 |
-
</div>
|
333 |
-
</div>
|
334 |
-
</div>
|
335 |
</div>
|
336 |
</div>
|
337 |
|
338 |
<script>
|
339 |
-
//
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
function init() {
|
370 |
-
document.getElementById('loginButton').addEventListener('click', login)
|
371 |
-
document.getElementById('addFundsButton').addEventListener('click', addFunds)
|
372 |
-
}
|
373 |
-
|
374 |
-
// Система входа
|
375 |
-
function login() {
|
376 |
-
const login = document.getElementById('loginInput').value
|
377 |
-
const password = document.getElementById('passwordInput').value
|
378 |
-
|
379 |
-
if(login === account.login && password === account.password) {
|
380 |
-
document.getElementById('loginPage').style.display = 'none'
|
381 |
-
document.getElementById('mainPage').style.display = 'block'
|
382 |
-
initApp()
|
383 |
-
} else {
|
384 |
-
document.getElementById('loginError').style.display = 'block'
|
385 |
}
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
// Обновление баланса
|
399 |
-
function updateBalance() {
|
400 |
-
const balanceElement = document.getElementById('balance')
|
401 |
-
if(balanceElement) {
|
402 |
-
balanceElement.textContent = account.balance
|
403 |
}
|
404 |
}
|
405 |
|
406 |
-
//
|
407 |
-
function
|
408 |
-
const
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
424 |
}
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
account.library.map(game => `
|
433 |
-
<div class="game-card">
|
434 |
-
<img src="${game.image}" class="game-image">
|
435 |
-
<div style="padding: 15px">
|
436 |
-
<h3>${game.title}</h3>
|
437 |
-
<button class="steam-button" disabled>Установить</button>
|
438 |
-
</div>
|
439 |
-
</div>
|
440 |
-
`).join('') :
|
441 |
-
'<p>Ваша библиотека пуста. Купите игры в магазине!</p>'
|
442 |
}
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
<div>${friend.name}</div>
|
452 |
-
<div class="friend-status">${friend.status}</div>
|
453 |
-
</div>
|
454 |
-
`).join('')
|
455 |
}
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
account.library.push(game)
|
466 |
-
updateBalance()
|
467 |
-
renderStore()
|
468 |
-
renderLibrary()
|
469 |
-
alert(`🎉 Вы купили "${game.title}"!`)
|
470 |
-
} else {
|
471 |
-
alert('🚫 Недостаточно средств!')
|
472 |
}
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
alert(`✅ Баланс пополнен на ${amount} ₴!`)
|
482 |
-
} else {
|
483 |
-
alert('⚠ Введите сумму от 1 до 10 000 гривен')
|
484 |
}
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
493 |
}
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
const installButton = document.querySelector(`.install-button[data-game-id="${gameId}"]`);
|
514 |
-
const progressBar = document.querySelector(`.install-progress[data-game-id="${gameId}"] .install-progress-bar`);
|
515 |
-
const message = document.querySelector(`.install-message[data-game-id="${gameId}"]`);
|
516 |
-
|
517 |
-
if (installButton && progressBar && message) {
|
518 |
-
installButton.disabled = true;
|
519 |
-
installButton.textContent = 'Установка...';
|
520 |
-
progressBar.parentElement.style.display = 'block';
|
521 |
-
message.style.display = 'block';
|
522 |
-
progressBar.style.transition = 'width 0.3s ease';
|
523 |
-
|
524 |
-
let progress = 0;
|
525 |
-
function updateProgress() {
|
526 |
-
progress += 5;
|
527 |
-
progressBar.style.width = `${progress}%`;
|
528 |
-
if (progress < 100) {
|
529 |
-
requestAnimationFrame(updateProgress);
|
530 |
} else {
|
531 |
-
|
532 |
-
installButton.onclick = () => playGame(gameId);
|
533 |
-
message.textContent = 'Игра успешно установлена!';
|
534 |
-
installButton.disabled = false;
|
535 |
}
|
|
|
|
|
|
|
|
|
536 |
}
|
537 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
538 |
}
|
539 |
-
} catch (error) {
|
540 |
-
console.error('Ошибка установки:', error.message);
|
541 |
}
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
565 |
}
|
566 |
-
|
567 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
568 |
</body>
|
569 |
</html>
|
|
|
2 |
<html lang="ru">
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Изменение времени по голосу</title>
|
7 |
<style>
|
|
|
8 |
body {
|
|
|
|
|
|
|
9 |
margin: 0;
|
10 |
+
overflow: hidden;
|
11 |
+
font-family: Arial, sans-serif;
|
12 |
+
}
|
13 |
+
#game-container {
|
14 |
+
position: relative;
|
15 |
+
width: 100vw;
|
16 |
+
height: 100vh;
|
17 |
+
transition: background-color 0.5s ease;
|
18 |
+
}
|
19 |
+
#sky {
|
20 |
+
position: absolute;
|
21 |
+
top: 0;
|
22 |
+
left: 0;
|
23 |
+
width: 100%;
|
24 |
+
height: 70%;
|
25 |
+
transition: background-color 0.5s ease;
|
26 |
}
|
27 |
+
#ground {
|
28 |
+
position: absolute;
|
29 |
+
bottom: 0;
|
30 |
+
left: 0;
|
31 |
+
width: 100%;
|
32 |
+
height: 30%;
|
33 |
+
background-color: #4a7c59;
|
34 |
+
transition: background-color 0.5s ease;
|
35 |
+
}
|
36 |
+
#sun-moon {
|
37 |
+
position: absolute;
|
38 |
+
width: 80px;
|
39 |
+
height: 80px;
|
40 |
+
border-radius: 50%;
|
41 |
+
transition: all 0.5s ease;
|
42 |
}
|
43 |
+
#buildings {
|
44 |
+
position: absolute;
|
45 |
+
bottom: 30%;
|
46 |
+
left: 0;
|
47 |
+
width: 100%;
|
48 |
+
height: 20%;
|
49 |
+
}
|
50 |
+
.building {
|
51 |
+
position: absolute;
|
52 |
+
bottom: 0;
|
53 |
+
background-color: #555;
|
54 |
+
transition: background-color 0.5s ease;
|
55 |
+
}
|
56 |
+
.window {
|
57 |
+
position: absolute;
|
58 |
+
background-color: #333;
|
59 |
+
transition: background-color 0.5s ease;
|
60 |
+
}
|
61 |
+
#controls {
|
62 |
+
position: absolute;
|
63 |
+
top: 20px;
|
64 |
+
left: 20px;
|
65 |
+
background-color: rgba(255, 255, 255, 0.8);
|
66 |
padding: 15px;
|
|
|
|
|
|
|
|
|
|
|
67 |
border-radius: 10px;
|
68 |
+
z-index: 100;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
}
|
70 |
+
#time-display {
|
71 |
+
font-size: 24px;
|
72 |
+
font-weight: bold;
|
73 |
+
margin-bottom: 10px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
}
|
75 |
+
#pitch-display, #volume-display {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
font-size: 16px;
|
77 |
+
margin-bottom: 5px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
}
|
79 |
+
button {
|
80 |
+
padding: 10px 15px;
|
81 |
+
margin-right: 5px;
|
82 |
+
background-color: #4CAF50;
|
83 |
+
color: white;
|
84 |
border: none;
|
|
|
|
|
|
|
85 |
border-radius: 5px;
|
86 |
+
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
+
button:hover {
|
89 |
+
background-color: #45a049;
|
|
|
|
|
|
|
|
|
90 |
}
|
91 |
+
#stars {
|
92 |
+
position: absolute;
|
93 |
+
top: 0;
|
94 |
+
left: 0;
|
95 |
+
width: 100%;
|
96 |
+
height: 70%;
|
97 |
+
transition: opacity 0.5s ease;
|
98 |
+
opacity: 0;
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
+
.star {
|
101 |
+
position: absolute;
|
102 |
+
background-color: white;
|
|
|
103 |
border-radius: 50%;
|
|
|
|
|
104 |
}
|
105 |
+
#instructions {
|
106 |
+
position: absolute;
|
107 |
+
bottom: 20px;
|
108 |
+
left: 20px;
|
109 |
+
background-color: rgba(255, 255, 255, 0.8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
padding: 15px;
|
111 |
border-radius: 10px;
|
112 |
+
max-width: 300px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
}
|
114 |
</style>
|
115 |
</head>
|
116 |
<body>
|
117 |
+
<div id="game-container">
|
118 |
+
<div id="sky"></div>
|
119 |
+
<div id="stars"></div>
|
120 |
+
<div id="sun-moon"></div>
|
121 |
+
<div id="buildings"></div>
|
122 |
+
<div id="ground"></div>
|
123 |
+
|
124 |
+
<div id="controls">
|
125 |
+
<div id="time-display">12:00</div>
|
126 |
+
<div id="pitch-display">Тембр: 0</div>
|
127 |
+
<div id="volume-display">Громкость: 0</div>
|
128 |
+
<button id="start-btn">Начать запись голоса</button>
|
129 |
+
<button id="stop-btn" disabled>Остановить</button>
|
130 |
</div>
|
131 |
+
|
132 |
+
<div id="instructions">
|
133 |
+
<h3>Инструкция:</h3>
|
134 |
+
<p>1. Нажмите "Начать запись голоса" и разрешите доступ к микрофону</p>
|
135 |
+
<p>2. Говорите с разным тембром голоса:</p>
|
136 |
+
<p>- Низкий тембр = ночь/раннее утро</p>
|
137 |
+
<p>- Средний тембр = день</p>
|
138 |
+
<p>- Высокий тембр = вечер/закат</p>
|
139 |
+
<p>3. Громкость голоса влияет на яркость сцены</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
</div>
|
141 |
</div>
|
142 |
|
143 |
<script>
|
144 |
+
// Создаем элементы сцены
|
145 |
+
function setupScene() {
|
146 |
+
// Создаем здания
|
147 |
+
const buildingsContainer = document.getElementById('buildings');
|
148 |
+
const buildingCount = 8;
|
149 |
+
for (let i = 0; i < buildingCount; i++) {
|
150 |
+
const building = document.createElement('div');
|
151 |
+
building.classList.add('building');
|
152 |
+
const height = 50 + Math.random() * 100;
|
153 |
+
const width = 40 + Math.random() * 60;
|
154 |
+
building.style.height = height + 'px';
|
155 |
+
building.style.width = width + 'px';
|
156 |
+
building.style.left = (i * (100 / buildingCount)) + '%';
|
157 |
+
|
158 |
+
// Добавляем окна
|
159 |
+
const windowRows = Math.floor(height / 20);
|
160 |
+
const windowCols = Math.floor(width / 15);
|
161 |
+
for (let r = 0; r < windowRows; r++) {
|
162 |
+
for (let c = 0; c < windowCols; c++) {
|
163 |
+
const windowEl = document.createElement('div');
|
164 |
+
windowEl.classList.add('window');
|
165 |
+
windowEl.style.width = '10px';
|
166 |
+
windowEl.style.height = '15px';
|
167 |
+
windowEl.style.left = (c * 15 + 5) + 'px';
|
168 |
+
windowEl.style.top = (r * 20 + 5) + 'px';
|
169 |
+
building.appendChild(windowEl);
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
buildingsContainer.appendChild(building);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
}
|
175 |
+
|
176 |
+
// Создаем звезды
|
177 |
+
const starsContainer = document.getElementById('stars');
|
178 |
+
for (let i = 0; i < 100; i++) {
|
179 |
+
const star = document.createElement('div');
|
180 |
+
star.classList.add('star');
|
181 |
+
const size = 1 + Math.random() * 2;
|
182 |
+
star.style.width = size + 'px';
|
183 |
+
star.style.height = size + 'px';
|
184 |
+
star.style.left = Math.random() * 100 + '%';
|
185 |
+
star.style.top = Math.random() * 100 + '%';
|
186 |
+
starsContainer.appendChild(star);
|
|
|
|
|
|
|
|
|
|
|
187 |
}
|
188 |
}
|
189 |
|
190 |
+
// Изменение времени суток
|
191 |
+
function updateTimeOfDay(hour, minute, pitch, volume) {
|
192 |
+
const gameContainer = document.getElementById('game-container');
|
193 |
+
const sky = document.getElementById('sky');
|
194 |
+
const ground = document.getElementById('ground');
|
195 |
+
const sunMoon = document.getElementById('sun-moon');
|
196 |
+
const buildings = document.querySelectorAll('.building');
|
197 |
+
const windows = document.querySelectorAll('.window');
|
198 |
+
const stars = document.getElementById('stars');
|
199 |
+
|
200 |
+
// Нормализуем время (0-24)
|
201 |
+
const time = hour + minute / 60;
|
202 |
+
|
203 |
+
// Положение солнца/луны
|
204 |
+
const angle = (time / 24) * 2 * Math.PI - Math.PI / 2;
|
205 |
+
const radius = Math.min(window.innerWidth, window.innerHeight) * 0.4;
|
206 |
+
const centerX = window.innerWidth / 2;
|
207 |
+
const centerY = window.innerHeight * 0.7;
|
208 |
+
const x = centerX + radius * Math.cos(angle);
|
209 |
+
const y = centerY + radius * Math.sin(angle);
|
210 |
+
|
211 |
+
sunMoon.style.left = (x - 40) + 'px';
|
212 |
+
sunMoon.style.top = (y - 40) + 'px';
|
213 |
+
|
214 |
+
// Цвета в зависимости от времени суток
|
215 |
+
let skyColor, groundColor, sunMoonColor, buildingColor, windowColor;
|
216 |
+
let starsOpacity = 0;
|
217 |
+
|
218 |
+
// Раннее утро (5-7)
|
219 |
+
if (time >= 5 && time < 7) {
|
220 |
+
skyColor = `rgb(${Math.floor(59 + (158-59) * (time-5)/2)}, ${Math.floor(88 + (206-88) * (time-5)/2)}, ${Math.floor(128 + (235-128) * (time-5)/2)})`;
|
221 |
+
groundColor = '#385c46';
|
222 |
+
sunMoonColor = '#ff9e4f';
|
223 |
+
buildingColor = '#555';
|
224 |
+
windowColor = '#333';
|
225 |
}
|
226 |
+
// День (7-17)
|
227 |
+
else if (time >= 7 && time < 17) {
|
228 |
+
skyColor = '#9eceff';
|
229 |
+
groundColor = '#4a7c59';
|
230 |
+
sunMoonColor = '#ffee00';
|
231 |
+
buildingColor = '#666';
|
232 |
+
windowColor = '#444';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
}
|
234 |
+
// Закат (17-19)
|
235 |
+
else if (time >= 17 && time < 19) {
|
236 |
+
const factor = (time - 17) / 2;
|
237 |
+
skyColor = `rgb(${Math.floor(158 + (255-158) * factor)}, ${Math.floor(206 + (107-206) * factor)}, ${Math.floor(235 + (62-235) * factor)})`;
|
238 |
+
groundColor = '#3d5d49';
|
239 |
+
sunMoonColor = '#ff6700';
|
240 |
+
buildingColor = '#555';
|
241 |
+
windowColor = '#b3721f';
|
|
|
|
|
|
|
|
|
242 |
}
|
243 |
+
// Вечер (19-21)
|
244 |
+
else if (time >= 19 && time < 21) {
|
245 |
+
const factor = (time - 19) / 2;
|
246 |
+
skyColor = `rgb(${Math.floor(255 - (255-20) * factor)}, ${Math.floor(107 - (107-42) * factor)}, ${Math.floor(62 - (62-87) * factor)})`;
|
247 |
+
groundColor = '#2e463a';
|
248 |
+
sunMoonColor = `rgb(${Math.floor(255 - 200 * factor)}, ${Math.floor(103 - 43 * factor)}, ${Math.floor(0 + 230 * factor)})`;
|
249 |
+
buildingColor = '#444';
|
250 |
+
windowColor = '#ffdb70';
|
251 |
+
starsOpacity = factor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
}
|
253 |
+
// Ночь (21-5)
|
254 |
+
else {
|
255 |
+
skyColor = '#14283b';
|
256 |
+
groundColor = '#1e2e26';
|
257 |
+
sunMoonColor = '#e0e0e0';
|
258 |
+
buildingColor = '#333';
|
259 |
+
windowColor = '#ffdb70';
|
260 |
+
starsOpacity = 1;
|
|
|
|
|
|
|
261 |
}
|
262 |
+
|
263 |
+
// Применяем цвета с учетом громкости (яркости)
|
264 |
+
const brightnessMultiplier = 0.7 + volume * 0.3;
|
265 |
+
|
266 |
+
// Функция для увеличения яркости цвета
|
267 |
+
function adjustBrightness(hexOrRgb, multiplier) {
|
268 |
+
// Для RGB формата
|
269 |
+
if (hexOrRgb.startsWith('rgb')) {
|
270 |
+
const rgbValues = hexOrRgb.match(/\d+/g).map(Number);
|
271 |
+
return `rgb(${Math.min(255, Math.floor(rgbValues[0] * multiplier))}, ${Math.min(255, Math.floor(rgbValues[1] * multiplier))}, ${Math.min(255, Math.floor(rgbValues[2] * multiplier))})`;
|
272 |
+
}
|
273 |
+
|
274 |
+
// Для HEX формата
|
275 |
+
const hex = hexOrRgb.replace('#', '');
|
276 |
+
let r = parseInt(hex.substring(0, 2), 16);
|
277 |
+
let g = parseInt(hex.substring(2, 4), 16);
|
278 |
+
let b = parseInt(hex.substring(4, 6), 16);
|
279 |
+
|
280 |
+
r = Math.min(255, Math.floor(r * multiplier));
|
281 |
+
g = Math.min(255, Math.floor(g * multiplier));
|
282 |
+
b = Math.min(255, Math.floor(b * multiplier));
|
283 |
+
|
284 |
+
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
285 |
}
|
286 |
+
|
287 |
+
// Применяем подстроенные цвета
|
288 |
+
sky.style.backgroundColor = skyColor;
|
289 |
+
ground.style.backgroundColor = adjustBrightness(groundColor, brightnessMultiplier);
|
290 |
+
sunMoon.style.backgroundColor = adjustBrightness(sunMoonColor, brightnessMultiplier);
|
291 |
+
|
292 |
+
buildings.forEach(building => {
|
293 |
+
building.style.backgroundColor = adjustBrightness(buildingColor, brightnessMultiplier);
|
294 |
+
});
|
295 |
+
|
296 |
+
windows.forEach(window => {
|
297 |
+
// Ночью окна горят
|
298 |
+
if (time >= 19 || time < 7) {
|
299 |
+
// Случайно определяем, горит ли окно
|
300 |
+
if (window.dataset.lit === undefined) {
|
301 |
+
window.dataset.lit = Math.random() > 0.3 ? 'true' : 'false';
|
302 |
+
}
|
303 |
+
if (window.dataset.lit === 'true') {
|
304 |
+
window.style.backgroundColor = adjustBrightness(windowColor, brightnessMultiplier);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
} else {
|
306 |
+
window.style.backgroundColor = '#333';
|
|
|
|
|
|
|
307 |
}
|
308 |
+
} else {
|
309 |
+
// Днем окна темные
|
310 |
+
window.style.backgroundColor = '#444';
|
311 |
+
delete window.dataset.lit;
|
312 |
}
|
313 |
+
});
|
314 |
+
|
315 |
+
stars.style.opacity = starsOpacity;
|
316 |
+
}
|
317 |
+
|
318 |
+
// Обработка аудио
|
319 |
+
let audioContext;
|
320 |
+
let analyser;
|
321 |
+
let microphone;
|
322 |
+
let javascriptNode;
|
323 |
+
let hours = 12;
|
324 |
+
let minutes = 0;
|
325 |
+
let lastPitch = 0;
|
326 |
+
let lastVolume = 0;
|
327 |
+
|
328 |
+
function startAudioProcessing() {
|
329 |
+
const startBtn = document.getElementById('start-btn');
|
330 |
+
const stopBtn = document.getElementById('stop-btn');
|
331 |
+
|
332 |
+
startBtn.disabled = true;
|
333 |
+
stopBtn.disabled = false;
|
334 |
+
|
335 |
+
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
336 |
+
analyser = audioContext.createAnalyser();
|
337 |
+
analyser.fftSize = 2048;
|
338 |
+
|
339 |
+
// Запрашиваем доступ к микрофону
|
340 |
+
navigator.mediaDevices.getUserMedia({ audio: true })
|
341 |
+
.then(function(stream) {
|
342 |
+
microphone = audioContext.createMediaStreamSource(stream);
|
343 |
+
microphone.connect(analyser);
|
344 |
+
|
345 |
+
// Создаем обработчик для анализа звука
|
346 |
+
javascriptNode = audioContext.createScriptProcessor(2048, 1, 1);
|
347 |
+
analyser.connect(javascriptNode);
|
348 |
+
javascriptNode.connect(audioContext.destination);
|
349 |
+
|
350 |
+
// Устанавливаем обработчик для анализа звука
|
351 |
+
javascriptNode.onaudioprocess = processAudio;
|
352 |
+
})
|
353 |
+
.catch(function(err) {
|
354 |
+
console.error('Ошибка доступа к микрофону:', err);
|
355 |
+
alert('Не удалось получить доступ к микрофону. Проверьте настройки браузера.');
|
356 |
+
startBtn.disabled = false;
|
357 |
+
stopBtn.disabled = true;
|
358 |
+
});
|
359 |
+
}
|
360 |
+
|
361 |
+
function stopAudioProcessing() {
|
362 |
+
const startBtn = document.getElementById('start-btn');
|
363 |
+
const stopBtn = document.getElementById('stop-btn');
|
364 |
+
|
365 |
+
startBtn.disabled = false;
|
366 |
+
stopBtn.disabled = true;
|
367 |
+
|
368 |
+
if (javascriptNode) {
|
369 |
+
javascriptNode.onaudioprocess = null;
|
370 |
+
javascriptNode.disconnect();
|
371 |
+
}
|
372 |
+
|
373 |
+
if (microphone) {
|
374 |
+
microphone.disconnect();
|
375 |
+
}
|
376 |
+
|
377 |
+
if (analyser) {
|
378 |
+
analyser.disconnect();
|
379 |
+
}
|
380 |
+
|
381 |
+
if (audioContext) {
|
382 |
+
audioContext.close();
|
383 |
}
|
|
|
|
|
384 |
}
|
385 |
+
|
386 |
+
function processAudio(event) {
|
387 |
+
const bufferLength = analyser.frequencyBinCount;
|
388 |
+
const dataArray = new Uint8Array(bufferLength);
|
389 |
+
analyser.getByteFrequencyData(dataArray);
|
390 |
+
|
391 |
+
// Вычисляем среднюю частоту (тембр)
|
392 |
+
let sum = 0;
|
393 |
+
let count = 0;
|
394 |
+
|
395 |
+
// Используем только значимую часть спектра
|
396 |
+
for (let i = 5; i < bufferLength / 4; i++) {
|
397 |
+
if (dataArray[i] > 10) { // Игнорируем шум
|
398 |
+
sum += i * dataArray[i];
|
399 |
+
count += dataArray[i];
|
400 |
+
}
|
401 |
+
}
|
402 |
+
|
403 |
+
// Вычисляем среднюю громкость
|
404 |
+
let volumeSum = 0;
|
405 |
+
for (let i = 0; i < bufferLength; i++) {
|
406 |
+
volumeSum += dataArray[i];
|
407 |
+
}
|
408 |
+
let volumeAvg = volumeSum / bufferLength / 255;
|
409 |
+
|
410 |
+
if (count > 0) {
|
411 |
+
const normalizedPitch = sum / count / (bufferLength / 8);
|
412 |
+
|
413 |
+
// Сглаживаем значения для более плавного перехода
|
414 |
+
lastPitch = lastPitch * 0.7 + normalizedPitch * 0.3;
|
415 |
+
lastVolume = lastVolume * 0.7 + volumeAvg * 0.3;
|
416 |
+
|
417 |
+
// Обновляем отображение текущих значений
|
418 |
+
document.getElementById('pitch-display').textContent = `Тембр: ${lastPitch.toFixed(2)}`;
|
419 |
+
document.getElementById('volume-display').textContent = `Громкость: ${lastVolume.toFixed(2)}`;
|
420 |
+
|
421 |
+
// Меняем время суток в зависимости от тембра
|
422 |
+
hours = Math.floor(lastPitch * 24);
|
423 |
+
minutes = Math.floor((lastPitch * 24 - hours) * 60);
|
424 |
+
|
425 |
+
// Обновляем отображение времени
|
426 |
+
document.getElementById('time-display').textContent =
|
427 |
+
`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
428 |
+
|
429 |
+
// Обновляем сцену
|
430 |
+
updateTimeOfDay(hours, minutes, lastPitch, lastVolume);
|
431 |
+
}
|
432 |
}
|
433 |
+
|
434 |
+
// Инициализация
|
435 |
+
window.onload = function() {
|
436 |
+
setupScene();
|
437 |
+
updateTimeOfDay(hours, minutes, 0.5, 0.5);
|
438 |
+
|
439 |
+
// Устанавливаем обработчики событий для кнопок
|
440 |
+
document.getElementById('start-btn').addEventListener('click', startAudioProcessing);
|
441 |
+
document.getElementById('stop-btn').addEventListener('click', stopAudioProcessing);
|
442 |
+
|
443 |
+
// Устанавливаем интервал для обновления времени даже без звука
|
444 |
+
setInterval(function() {
|
445 |
+
if (!audioContext) {
|
446 |
+
minutes++;
|
447 |
+
if (minutes >= 60) {
|
448 |
+
minutes = 0;
|
449 |
+
hours++;
|
450 |
+
if (hours >= 24) {
|
451 |
+
hours = 0;
|
452 |
+
}
|
453 |
+
}
|
454 |
+
|
455 |
+
document.getElementById('time-display').textContent =
|
456 |
+
`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
457 |
+
|
458 |
+
updateTimeOfDay(hours, minutes, hours / 24, 0.5);
|
459 |
+
}
|
460 |
+
}, 1000);
|
461 |
+
};
|
462 |
+
</script>
|
463 |
</body>
|
464 |
</html>
|