Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Вода — Симуляция</title> | |
| <style> | |
| html, body { | |
| margin: 0; | |
| padding: 0; | |
| overflow: hidden; | |
| background: #0e0f1b; | |
| } | |
| canvas { | |
| display: block; | |
| background: linear-gradient(#0f2027, #203a43, #2c5364); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="water"></canvas> | |
| <script> | |
| const canvas = document.getElementById('water'); | |
| const ctx = canvas.getContext('2d'); | |
| let width = window.innerWidth; | |
| let height = window.innerHeight; | |
| canvas.width = width; | |
| canvas.height = height; | |
| const waveCount = 200; | |
| const damping = 0.03; | |
| const tension = 0.025; | |
| const waves = []; | |
| for (let i = 0; i < waveCount; i++) { | |
| waves[i] = { | |
| x: (i / (waveCount - 1)) * width, | |
| y: height / 2, | |
| vy: 0, | |
| targetY: height / 2 | |
| }; | |
| } | |
| function update() { | |
| for (let i = 0; i < waveCount; i++) { | |
| const point = waves[i]; | |
| const dy = point.y - point.targetY; | |
| point.vy -= dy * tension; | |
| point.vy *= 1 - damping; | |
| point.y += point.vy; | |
| } | |
| // propagate waves | |
| const leftDeltas = [], rightDeltas = []; | |
| for (let j = 0; j < 8; j++) { | |
| for (let i = 0; i < waveCount; i++) { | |
| if (i > 0) { | |
| leftDeltas[i] = 0.25 * (waves[i].y - waves[i - 1].y); | |
| waves[i - 1].vy += leftDeltas[i]; | |
| } | |
| if (i < waveCount - 1) { | |
| rightDeltas[i] = 0.25 * (waves[i].y - waves[i + 1].y); | |
| waves[i + 1].vy += rightDeltas[i]; | |
| } | |
| } | |
| } | |
| } | |
| function draw() { | |
| ctx.clearRect(0, 0, width, height); | |
| ctx.beginPath(); | |
| ctx.moveTo(0, height); | |
| ctx.lineTo(waves[0].x, waves[0].y); | |
| for (let i = 1; i < waveCount; i++) { | |
| ctx.lineTo(waves[i].x, waves[i].y); | |
| } | |
| ctx.lineTo(width, height); | |
| ctx.closePath(); | |
| const gradient = ctx.createLinearGradient(0, height / 2, 0, height); | |
| gradient.addColorStop(0, '#4facfe'); | |
| gradient.addColorStop(1, '#00f2fe'); | |
| ctx.fillStyle = gradient; | |
| ctx.fill(); | |
| } | |
| function loop() { | |
| update(); | |
| draw(); | |
| requestAnimationFrame(loop); | |
| } | |
| loop(); | |
| canvas.addEventListener('mousemove', (e) => { | |
| const mouseX = e.clientX; | |
| const index = Math.floor((mouseX / width) * waveCount); | |
| if (index >= 0 && index < waveCount) { | |
| waves[index].vy = -5; | |
| } | |
| }); | |
| window.addEventListener('resize', () => { | |
| width = window.innerWidth; | |
| height = window.innerHeight; | |
| canvas.width = width; | |
| canvas.height = height; | |
| for (let i = 0; i < waveCount; i++) { | |
| waves[i].x = (i / (waveCount - 1)) * width; | |
| waves[i].y = height / 2; | |
| waves[i].targetY = height / 2; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |