/
DOLOR3SS
/
loveees
Обзор
Документация
Войти
/
DOLOR3SS
/
loveees
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
736 строк
28 KB
DOLOR3SS
Update: index.html
28 июн 2026, 14:43
Верифицирован
28 июн 2026, 14:43
1f523e7
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <title>открыточкаавв!!</title> <style> /* ========== ОБЩИЕ СТИЛИ ========== */ * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; } body { background: #1a1a2e; display: flex; justify-content: center; align-items: center; min-height: 100vh; font-family: 'Press Start 2P', 'Courier New', monospace; margin: 0; padding: 10px; } @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); #gameWrapper { position: relative; width: 900px; max-width: 100%; aspect-ratio: 16 / 9; background: #87CEEB; border: 6px solid #2d2d2d; box-shadow: 0 0 0 4px #5a5a5a, 0 10px 30px rgba(0,0,0,0.7); image-rendering: pixelated; overflow: hidden; touch-action: none; } canvas { display: block; width: 100%; height: 100%; image-rendering: pixelated; background: transparent; touch-action: none; } .screen-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; background: rgba(0, 0, 0, 0.75); backdrop-filter: blur(3px); color: #fff; text-align: center; padding: 20px; z-index: 20; transition: opacity 0.3s; image-rendering: pixelated; } .screen-overlay.hidden { display: none; } .screen-overlay h1 { font-size: clamp(18px, 5vw, 48px); text-shadow: 4px 4px 0 #000, 6px 6px 0 #ff4d4d; margin-bottom: 20px; letter-spacing: 2px; line-height: 1.4; } .pixel-btn { font-family: 'Press Start 2P', monospace; background: #f0c040; border: none; padding: 14px 36px; font-size: clamp(14px, 2.5vw, 28px); color: #2d2d2d; box-shadow: 0 6px 0 #b87c2a, 0 8px 12px rgba(0,0,0,0.3); cursor: pointer; transition: 0.05s linear; text-transform: uppercase; image-rendering: pixelated; letter-spacing: 2px; } .pixel-btn:active { transform: translateY(6px); box-shadow: 0 2px 0 #b87c2a; } .pixel-btn:hover { background: #ffd966; } #cardOverlay { background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(6px); justify-content: center; align-items: center; z-index: 30; } .card-content { background: #fff5f0; padding: 20px 25px; max-width: 500px; width: 90%; border-radius: 20px; border: 4px solid #2d2d2d; box-shadow: 0 0 0 4px #888, 0 10px 30px black; max-height: 90vh; overflow-y: auto; font-family: 'Segoe UI', Roboto, sans-serif; text-align: center; color: #1a1a1a; } .card-content .title { color: #7f8c8d; font-size: 12px; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 8px; font-family: 'Press Start 2P', monospace; } .card-content h2 { font-size: 20px; margin-bottom: 12px; color: #000; } .card-content .text-letter { font-size: 15px; line-height: 1.7; text-align: left; max-height: 200px; overflow-y: auto; padding-right: 6px; margin: 10px 0; color: #222; } .card-content .text-letter p { margin-bottom: 12px; } .card-buttons { display: flex; gap: 16px; justify-content: center; margin: 16px 0 8px; flex-wrap: wrap; } .card-buttons .btn { padding: 10px 28px; border: none; border-radius: 40px; font-weight: bold; font-size: 16px; cursor: pointer; box-shadow: 0 4px 0 rgba(0,0,0,0.2); transition: 0.05s linear; font-family: 'Segoe UI', sans-serif; } .card-buttons .btn:active { transform: translateY(4px); box-shadow: 0 1px 0 rgba(0,0,0,0.2); } #yesBtnCard { background: #ff6b81; color: white; } #noBtnCard { background: #a4b0be; color: white; } .card-continue-btn { font-family: 'Press Start 2P', monospace; background: #48a0d0; border: none; padding: 12px 30px; font-size: 16px; color: white; box-shadow: 0 5px 0 #1f5a7a; cursor: pointer; margin-top: 12px; transition: 0.05s linear; } .card-continue-btn:active { transform: translateY(5px); box-shadow: 0 1px 0 #1f5a7a; } #finalScreen { background: #0a0a0a; z-index: 40; justify-content: center; align-items: center; cursor: default; } #finalHeartContainer { position: relative; width: 70%; max-width: 500px; aspect-ratio: 1/1; display: flex; justify-content: center; align-items: center; flex-wrap: wrap; gap: 0; filter: drop-shadow(0 0 20px #8b0000); } .heart-word { font-family: 'Press Start 2P', monospace; font-size: clamp(12px, 2.8vw, 32px); color: #8b0000; text-shadow: 0 0 8px #ff2222, 0 0 20px #aa0000; font-weight: bold; transition: all 0.08s ease; cursor: default; line-height: 1.1; text-align: center; margin: 0 2px; } #centerLove { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: clamp(24px, 5vw, 56px); color: #8b0000; text-shadow: 0 0 15px #ff3333, 0 0 40px #aa0000; font-family: 'Press Start 2P', monospace; text-align: center; pointer-events: none; z-index: 2; } @media (max-width: 700px) { .card-content { padding: 15px; } .card-content .text-letter { font-size: 13px; } } </style> </head> <body> <div id="gameWrapper"> <canvas id="gameCanvas" width="900" height="506"></canvas> <div id="startScreen" class="screen-overlay"> <h1>ЛЮБИМОМУУ!! σ(≧ε≦σ) ♡</h1> <button class="pixel-btn" id="startGameBtn">НАЧАТЬ!!! (≧◡≦)</button> </div> <div id="cardOverlay" class="screen-overlay hidden"> <div class="card-content" id="cardContent"></div> </div> <div id="finalScreen" class="screen-overlay hidden"> <div id="finalHeartContainer"></div> <div id="centerLove">I LOVE YOU</div> </div> </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const W = 900, H = 506; const player = { x: 60, y: 350, w: 32, h: 48, vx: 0, vy: 0, speed: 3.2, jumpPower: -10, gravity: 0.45, onGround: false, frame: 0, frameTimer: 0, facing: 1 }; let platforms = []; let heartItems = []; let gameOver = false; let collectedHearts = 0; const TOTAL_HEARTS = 3; let animationId = null; let keys = {}; const GROUND_Y = 440; const PLATFORM_H = 24; const HEART_SIZE = 32; let cardActive = false; let pendingHeartIndex = -1; // ============================================================ // 2. ПОСТРОЕНИЕ УРОВНЯ // ============================================================ function buildLevel() { platforms = []; heartItems = []; platforms.push({ x: 0, y: GROUND_Y, w: 300, h: PLATFORM_H }); platforms.push({ x: 380, y: GROUND_Y, w: 300, h: PLATFORM_H }); platforms.push({ x: 720, y: GROUND_Y, w: 180, h: PLATFORM_H }); platforms.push({ x: 160, y: 360, w: 80, h: 20 }); platforms.push({ x: 300, y: 300, w: 70, h: 20 }); platforms.push({ x: 460, y: 340, w: 80, h: 20 }); platforms.push({ x: 580, y: 280, w: 70, h: 20 }); platforms.push({ x: 730, y: 350, w: 70, h: 20 }); platforms.push({ x: 810, y: 290, w: 60, h: 20 }); const heartPositions = [ { x: 180, y: 320 }, { x: 480, y: 300 }, { x: 750, y: 310 } ]; heartPositions.forEach((pos, i) => { heartItems.push({ x: pos.x, y: pos.y, w: HEART_SIZE, h: HEART_SIZE, collected: false, index: i }); }); } // ============================================================ // 3. ОТРИСОВКА // ============================================================ function drawPixelRect(x, y, w, h, fillColor, strokeColor = '#1a1a1a', lineW = 2) { ctx.fillStyle = fillColor; ctx.fillRect(x, y, w, h); ctx.strokeStyle = strokeColor; ctx.lineWidth = lineW; ctx.strokeRect(x, y, w, h); } function drawBackground() { const grad = ctx.createLinearGradient(0, 0, 0, H); grad.addColorStop(0, '#7EC8E3'); grad.addColorStop(0.6, '#B5DEE8'); grad.addColorStop(1, '#D4E9F0'); ctx.fillStyle = grad; ctx.fillRect(0, 0, W, H); ctx.strokeStyle = '#2d2d2d'; ctx.lineWidth = 2; ctx.strokeRect(0, 0, W, H); drawCloud(80, 60, 60, 30); drawCloud(300, 90, 80, 35); drawCloud(600, 50, 70, 30); drawCloud(780, 100, 50, 25); drawBush(50, GROUND_Y - 10, 60, 20); drawBush(400, GROUND_Y - 10, 70, 22); drawBush(750, GROUND_Y - 10, 50, 18); } function drawCloud(x, y, w, h) { ctx.fillStyle = '#f0f8ff'; ctx.fillRect(x, y, w, h); ctx.fillRect(x + 12, y - 14, w - 24, 18); ctx.fillRect(x + 6, y - 8, w - 12, 12); ctx.strokeStyle = '#2d2d2d'; ctx.lineWidth = 2; ctx.strokeRect(x, y, w, h); ctx.strokeRect(x + 12, y - 14, w - 24, 18); ctx.strokeRect(x + 6, y - 8, w - 12, 12); } function drawBush(x, y, w, h) { ctx.fillStyle = '#4caf50'; ctx.fillRect(x, y, w, h); ctx.fillRect(x + 8, y - 10, w - 16, 14); ctx.fillRect(x + 4, y - 6, w - 8, 10); ctx.strokeStyle = '#1a3a1a'; ctx.lineWidth = 2; ctx.strokeRect(x, y, w, h); ctx.strokeRect(x + 8, y - 10, w - 16, 14); ctx.strokeRect(x + 4, y - 6, w - 8, 10); } function drawPlatforms() { platforms.forEach(p => { drawPixelRect(p.x, p.y, p.w, p.h, '#d4a373', '#4a2f1a', 2.5); ctx.strokeStyle = '#7a5a3a'; ctx.lineWidth = 1.5; for (let i = 0; i < p.w; i += 20) { ctx.beginPath(); ctx.moveTo(p.x + i, p.y); ctx.lineTo(p.x + i, p.y + p.h); ctx.stroke(); } }); } function drawHearts() { heartItems.forEach(h => { if (h.collected) return; const cx = h.x + h.w/2, cy = h.y + h.h/2; ctx.fillStyle = '#e63946'; ctx.shadowColor = '#ff6b81'; ctx.shadowBlur = 8; const s = 6; const offsets = [ [-1,-1], [0,-1], [1,-1], [-2,0], [-1,0], [0,0], [1,0], [2,0], [-2,1], [-1,1], [0,1], [1,1], [2,1], [-1,2], [0,2], [1,2], [0,3] ]; offsets.forEach(([dx, dy]) => { ctx.fillRect(cx + dx*s - s/2, cy + dy*s - s/2, s, s); }); ctx.shadowBlur = 0; ctx.strokeStyle = '#4a0a0a'; ctx.lineWidth = 1.5; ctx.strokeRect(cx - 14, cy - 14, 28, 28); }); } function drawPlayer() { const p = player; // Если картинки не загрузились — рисуем пиксельного человечка ctx.fillStyle = '#da3e3eff'; ctx.fillRect(p.x + 4, p.y + 8, 24, 32); ctx.fillStyle = '#e41818ff'; ctx.fillRect(p.x + 8, p.y, 16, 16); ctx.fillStyle = '#222'; ctx.fillRect(p.x + 8, p.y + 4, 4, 4); ctx.fillRect(p.x + 20, p.y + 4, 4, 4); ctx.strokeStyle = '#1a1a1a'; ctx.lineWidth = 2; ctx.strokeRect(p.x + 4, p.y + 8, 24, 32); ctx.strokeRect(p.x + 8, p.y, 16, 16); } // ============================================================ // 4. ФИЗИКА // ============================================================ function updatePlayer() { if (gameOver || cardActive) return; const p = player; p.vx = 0; if (keys['ArrowLeft'] || keys['KeyA']) { p.vx = -p.speed; p.facing = -1; } if (keys['ArrowRight'] || keys['KeyD']) { p.vx = p.speed; p.facing = 1; } if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && p.onGround) { p.vy = p.jumpPower; p.onGround = false; } p.vy += p.gravity; if (p.vy > 12) p.vy = 12; p.x += p.vx; platforms.forEach(plat => { if (p.x < plat.x + plat.w && p.x + p.w > plat.x && p.y < plat.y + plat.h && p.y + p.h > plat.y) { if (p.vx > 0) p.x = plat.x - p.w; else if (p.vx < 0) p.x = plat.x + plat.w; } }); p.y += p.vy; p.onGround = false; platforms.forEach(plat => { if (p.x < plat.x + plat.w && p.x + p.w > plat.x && p.y < plat.y + plat.h && p.y + p.h > plat.y) { if (p.vy > 0) { p.y = plat.y - p.h; p.vy = 0; p.onGround = true; } else if (p.vy < 0) { p.y = plat.y + plat.h; p.vy = 0; } } }); if (p.x < 0) p.x = 0; if (p.x + p.w > W) p.x = W - p.w; if (p.y > H + 50) { gameOver = true; resetPlayer(); } heartItems.forEach(h => { if (h.collected) return; if (p.x < h.x + h.w && p.x + p.w > h.x && p.y < h.y + h.h && p.y + p.h > h.y) { h.collected = true; collectedHearts++; showCard(h.index); } }); if (collectedHearts >= TOTAL_HEARTS && !cardActive) { showFinalScreen(); } } function resetPlayer() { player.x = 60; player.y = 350; player.vx = 0; player.vy = 0; player.onGround = false; gameOver = false; collectedHearts = 0; heartItems.forEach(h => h.collected = false); document.getElementById('cardOverlay').classList.add('hidden'); cardActive = false; document.getElementById('finalScreen').classList.add('hidden'); } // ============================================================ // 5. ОТКРЫТКА // ============================================================ function showCard(heartIndex) { if (cardActive) return; cardActive = true; pendingHeartIndex = heartIndex; const overlay = document.getElementById('cardOverlay'); const container = document.getElementById('cardContent'); const cardTexts = [ { title: 'Первое сердечкаа (´。• ω •。`) ♡', text: `<p>Ты стал для меня по-настоящему близким человеком, и это настоящее чудо. С самого начала нашего общения ты показался мне весёлым, родным и понимающим — и с каждым днём это только укрепляется.</p> <p>С тобой легко и спокойно: я могу быть собой, делиться сокровенным, смеяться до слёз или говорить о серьёзном — и знать, что меня услышат и не осудят. Ты показал мне, какой может быть настоящая любовь и забота — и я это очень ценю.</p>` }, { title: 'Второе сердечкаа (〃^▽^〃)', text: `<p>Спасибо за твоё терпение, доброту и поддержку. За то, что всегда готов выслушать, подбодрить и заставить улыбнуться в хмурый день. Благодаря тебе я знаю, каково это — общаться с человеком, которому можно доверять безоговорочно.</p> <p>Береги себя, пожалуйста. Знай, что я рядом — и всегда готова поддержать, выслушать и порадоваться твоим успехам.</p> <p>Я тебя очень люблю, ты добрый, весёлый, чуткий, надёжный — и при этом остаёшься самим собой. С тобой можно и повеселиться от души, и поговорить по душам спасибо тебее.</p>` }, { title: 'Третье сердечкаа ❤️', text: `<p>Мне оочень нравится то, что ты проявляешь внимание ко мне, ты пишешь комплименты, и в тгк и в лс, а ещё прозвища вот эти вот там "кис" "милая" И вот это всë Я ТЕКУ ЕМАЕЕЕЕЕ</p> <p>За всë время нашего общения, ты мне прям в сердце запал, ты запомнился мне больше всего из моих знакомств, поверь, с тобой очень комфортно, приятно, весело и интересно общаться, да и сам ты довольно красивый, милый, пиздатый и ахуенный, очень дорожу тобой, таких людей как ты еще поискать нужно, люблю тебя очеееньь!!</p>` } ]; const data = cardTexts[heartIndex] || cardTexts[0]; container.innerHTML = ` <div class="title">${data.title}</div> <h2>Откроешь???</h2> <div class="text-letter hidden" id="cardLetter">${data.text}</div> <div class="card-buttons" id="cardButtons"> <button class="btn" id="yesBtnCard">ДАПП!! (≧◡≦)</button> <button class="btn" id="noBtnCard">НЕТ.</button> </div> <div id="cardContinueArea"></div> `; overlay.classList.remove('hidden'); document.getElementById('yesBtnCard').addEventListener('click', function() { document.getElementById('cardLetter').classList.remove('hidden'); document.getElementById('cardButtons').style.display = 'none'; const area = document.getElementById('cardContinueArea'); if (heartIndex === TOTAL_HEARTS - 1) { area.innerHTML = `<button class="card-continue-btn" id="continueBtn">КОНЕЦ!</button>`; } else { area.innerHTML = `<button class="card-continue-btn" id="continueBtn">ПРОДОЛЖИТЬ</button>`; } document.getElementById('continueBtn').addEventListener('click', function() { closeCard(); }); }); document.getElementById('noBtnCard').addEventListener('click', function() { document.getElementById('cardLetter').innerHTML = `<p style="text-align:center;font-size:22px;color:#d63031;">эй... (>﹏<) ну ты и мразь... ((╬◣﹏◢))</p>`; document.getElementById('cardLetter').classList.remove('hidden'); document.getElementById('cardButtons').style.display = 'none'; const area = document.getElementById('cardContinueArea'); if (heartIndex === TOTAL_HEARTS - 1) { area.innerHTML = `<button class="card-continue-btn" id="continueBtn">КОНЕЦ!</button>`; } else { area.innerHTML = `<button class="card-continue-btn" id="continueBtn">ПРОДОЛЖИТЬ</button>`; } document.getElementById('continueBtn').addEventListener('click', function() { closeCard(); }); }); } function closeCard() { document.getElementById('cardOverlay').classList.add('hidden'); cardActive = false; if (collectedHearts >= TOTAL_HEARTS) { showFinalScreen(); } } // ============================================================ // 6. ФИНАЛЬНЫЙ ЭКРАН // ============================================================ function showFinalScreen() { const finalScreen = document.getElementById('finalScreen'); finalScreen.classList.remove('hidden'); const container = document.getElementById('finalHeartContainer'); container.innerHTML = ''; const positions = [ {x: 0.5, y: 0.1}, {x: 0.3, y: 0.2}, {x: 0.7, y: 0.2}, {x: 0.2, y: 0.4}, {x: 0.8, y: 0.4}, {x: 0.15, y: 0.6}, {x: 0.85, y: 0.6}, {x: 0.3, y: 0.8}, {x: 0.7, y: 0.8}, {x: 0.5, y: 0.95} ]; const allWords = ['I','L','O','V','E','Y','O','U','❤️','❤️']; positions.forEach((pos, i) => { const span = document.createElement('span'); span.className = 'heart-word'; span.textContent = allWords[i % allWords.length]; span.style.position = 'absolute'; span.style.left = (pos.x * 100 - 5) + '%'; span.style.top = (pos.y * 100 - 5) + '%'; span.style.transform = 'translate(-50%, -50%)'; span.dataset.origX = pos.x; span.dataset.origY = pos.y; container.appendChild(span); }); const wordsElements = container.querySelectorAll('.heart-word'); wordsElements.forEach(el => { el.addEventListener('mousemove', (e) => { const rect = el.getBoundingClientRect(); const cx = rect.left + rect.width/2; const cy = rect.top + rect.height/2; const dx = (e.clientX - cx) / 30; const dy = (e.clientY - cy) / 30; el.style.transform = `translate(calc(-50% + ${dx}px), calc(-50% + ${dy}px)) scale(1.2)`; el.style.color = '#ff4d4d'; el.style.textShadow = '0 0 25px #ff0000, 0 0 50px #aa0000'; }); el.addEventListener('mouseleave', () => { el.style.transform = 'translate(-50%, -50%) scale(1)'; el.style.color = '#8b0000'; el.style.textShadow = '0 0 8px #ff2222, 0 0 20px #aa0000'; }); el.addEventListener('touchmove', (e) => { const touch = e.touches[0]; const rect = el.getBoundingClientRect(); const cx = rect.left + rect.width/2; const cy = rect.top + rect.height/2; const dx = (touch.clientX - cx) / 25; const dy = (touch.clientY - cy) / 25; el.style.transform = `translate(calc(-50% + ${dx}px), calc(-50% + ${dy}px)) scale(1.2)`; el.style.color = '#ff4d4d'; }, {passive: true}); el.addEventListener('touchend', () => { el.style.transform = 'translate(-50%, -50%) scale(1)'; el.style.color = '#8b0000'; }); }); } // ============================================================ // 7. ИГРОВОЙ ЦИКЛ // ============================================================ function gameLoop() { if (!document.getElementById('startScreen').classList.contains('hidden')) { animationId = requestAnimationFrame(gameLoop); return; } if (!cardActive && !gameOver) { updatePlayer(); } ctx.clearRect(0, 0, W, H); drawBackground(); drawPlatforms(); drawHearts(); drawPlayer(); if (gameOver) { ctx.fillStyle = 'rgba(0,0,0,0.5)'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = 'white'; ctx.font = '20px "Press Start 2P", monospace'; ctx.textAlign = 'center'; ctx.fillText('ПАДЕНИЕ!', W/2, H/2 - 10); ctx.font = '14px "Press Start 2P", monospace'; ctx.fillText('Перезапуск...', W/2, H/2 + 30); } animationId = requestAnimationFrame(gameLoop); } // ============================================================ // 8. ЗАПУСК // ============================================================ function init() { buildLevel(); resetPlayer(); document.getElementById('startGameBtn').addEventListener('click', function() { document.getElementById('startScreen').classList.add('hidden'); resetPlayer(); buildLevel(); collectedHearts = 0; heartItems.forEach(h => h.collected = false); document.getElementById('cardOverlay').classList.add('hidden'); document.getElementById('finalScreen').classList.add('hidden'); cardActive = false; }); document.addEventListener('keydown', (e) => { keys[e.code] = true; if (e.code === 'Space') e.preventDefault(); }); document.addEventListener('keyup', (e) => { keys[e.code] = false; }); canvas.addEventListener('touchstart', (e) => { e.preventDefault(); if (!cardActive && !gameOver) { if (player.onGround) { player.vy = player.jumpPower; player.onGround = false; } } }, {passive: false}); gameLoop(); } window.onload = init; </script> </body> </html>