Веблет для вашего досуга. Простой сайт для игры в Пазл

Веблет для вашего досуга. Простой сайт для игры в Пазл

Простой код html. Кидаете в любой текстовый редактор, сохраняете в формате html. Запускаете, выбираете любую картинку и играете. Работает со смартфона

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Пазл</title> <style> body { margin: 0; padding: 20px; display: flex; flex-direction: column; align-items: center; background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Segoe UI', Arial, sans-serif; min-height: 100vh; } #controls { background: rgba(255, 255, 255, 0.9); padding: 15px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; gap: 10px; max-width: 320px; width: 100%; margin-bottom: 20px; } #imageInput, #difficulty, button { padding: 10px; border: none; border-radius: 8px; font-size: 14px; cursor: pointer; transition: all 0.3s ease; } #imageInput { background: #f5f5f5; } #imageInput:hover { background: #e0e0e0; } #difficulty { background: #fff; appearance: none; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); } button { background: #6b7280; color: white; } button:hover { background: #4b5563; } #imagePreview { max-width: 100%; height: auto; border-radius: 8px; margin-top: 10px; display: none; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); } #gameContainer { position: relative; border-radius: 12px; overflow: hidden; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); } .puzzle-piece { position: absolute; border: 1px solid rgba(255, 255, 255, 0.2); box-sizing: border-box; cursor: move; user-select: none; touch-action: none; transition: transform 0.2s ease; } .puzzle-piece:hover { transform: scale(1.02); } .puzzle-piece.movable { z-index: 10; } .puzzle-piece.fixed { z-index: 1; } #winMessage { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(255, 255, 255, 0.95); padding: 20px 40px; border-radius: 12px; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); text-align: center; font-size: 20px; color: #333; z-index: 100; /* Устанавливаем высокий z-index */ } #winMessage button { margin-top: 15px; background: #10b981; } #winMessage button:hover { background: #059669; } </style> </head> <body> <div id="controls"> <input type="file" id="imageInput" accept="image/*"> <select id="difficulty"> <option value="3">Легко (3x3)</option> <option value="4">Средне (4x4)</option> <option value="5">Сложно (5x5)</option> </select> <button onclick="startGame()">Начать</button> <img id="imagePreview"> </div> <div id="gameContainer"></div> <div id="winMessage"> <p>Пазл собран! Поздравляем!</p> <button onclick="resetGame()">Сыграть снова</button> </div> <script> let img = new Image(); let pieces = []; let gridSize; let pieceWidth, pieceHeight; let container = document.getElementById('gameContainer'); let winMessage = document.getElementById('winMessage'); document.getElementById('imageInput').addEventListener('change', function(e) { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(event) { img.src = event.target.result; img.onload = function() { document.getElementById('imagePreview').src = img.src; document.getElementById('imagePreview').style.display = 'block'; } } reader.readAsDataURL(file); } }); function startGame() { if (!img.src) { alert('Загрузите изображение!'); return; } gridSize = parseInt(document.getElementById('difficulty').value); container.innerHTML = ''; winMessage.style.display = 'none'; const maxWidth = Math.min(window.innerWidth * 0.9, img.width); const maxHeight = Math.min(window.innerHeight * 0.7, img.height); const aspectRatio = img.width / img.height; let width = maxWidth; let height = width / aspectRatio; if (height > maxHeight) { height = maxHeight; width = height * aspectRatio; } container.style.width = width + 'px'; container.style.height = height + 'px'; pieceWidth = width / gridSize; pieceHeight = height / gridSize; createPuzzlePieces(); shufflePieces(); } function createPuzzlePieces() { pieces = []; for (let y = 0; y < gridSize; y++) { for (let x = 0; x < gridSize; x++) { const piece = document.createElement('div'); piece.className = 'puzzle-piece movable'; piece.style.width = pieceWidth + 'px'; piece.style.height = pieceHeight + 'px'; piece.style.backgroundImage = `url(${img.src})`; piece.style.backgroundSize = `${container.offsetWidth}px ${container.offsetHeight}px`; piece.style.backgroundPosition = `${-x * pieceWidth}px ${-y * pieceHeight}px`; piece.dataset.correctX = x; piece.dataset.correctY = y; makeDraggable(piece); container.appendChild(piece); pieces.push(piece); } } } function shufflePieces() { pieces.forEach(piece => { const randomX = Math.random() * (container.offsetWidth - pieceWidth); const randomY = Math.random() * (container.offsetHeight - pieceHeight); piece.style.left = randomX + 'px'; piece.style.top = randomY + 'px'; }); } function makeDraggable(element) { let posX = 0, posY = 0, startX = 0, startY = 0; element.onmousedown = dragMouseDown; element.ontouchstart = dragTouchStart; function dragMouseDown(e) { e.preventDefault(); startX = e.clientX; startY = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function dragTouchStart(e) { e.preventDefault(); startX = e.touches[0].clientX; startY = e.touches[0].clientY; document.ontouchend = closeDragElement; document.ontouchmove = elementDragTouch; } function elementDrag(e) { e.preventDefault(); posX = startX - e.clientX; posY = startY - e.clientY; startX = e.clientX; startY = e.clientY; moveElement(); } function elementDragTouch(e) { posX = startX - e.touches[0].clientX; posY = startY - e.touches[0].clientY; startX = e.touches[0].clientX; startY = e.touches[0].clientY; moveElement(); } function moveElement() { element.style.top = Math.max(0, Math.min(element.offsetTop - posY, container.offsetHeight - pieceHeight)) + 'px'; element.style.left = Math.max(0, Math.min(element.offsetLeft - posX, container.offsetWidth - pieceWidth)) + 'px'; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; document.ontouchend = null; document.ontouchmove = null; checkSnap(element); checkWin(); } } function checkSnap(piece) { const correctX = piece.dataset.correctX * pieceWidth; const correctY = piece.dataset.correctY * pieceHeight; const currentX = parseFloat(piece.style.left); const currentY = parseFloat(piece.style.top); if (Math.abs(currentX - correctX) < 20 && Math.abs(currentY - correctY) < 20) { piece.style.left = correctX + 'px'; piece.style.top = correctY + 'px'; piece.style.cursor = 'default'; piece.onmousedown = null; piece.ontouchstart = null; piece.classList.remove('movable'); piece.classList.add('fixed'); } } function checkWin() { const allPiecesCorrect = pieces.every(piece => Math.abs(parseFloat(piece.style.left) - (piece.dataset.correctX * pieceWidth)) < 1 && Math.abs(parseFloat(piece.style.top) - (piece.dataset.correctY * pieceHeight)) < 1 ); if (allPiecesCorrect) { winMessage.style.display = 'block'; } } function resetGame() { winMessage.style.display = 'none'; startGame(); } window.onresize = () => { if (pieces.length > 0) startGame(); }; </script> </body> </html>
5
2
1
1
5 комментариев
\n\n","lang":""}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":5,"favorites":1,"reposts":0,"views":1120,"hits":147,"reads":null,"online":0},"dateFavorite":0,"hitsCount":147,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":null,"url":"https://dtf.ru/id3270/3643827-veblet-dlya-vashego-dosuga-prostoi-sait-dlya-igry-v-pazl","author":{"id":3270,"name":"Геральт из России","nickname":null,"description":"Добро пожаловать в steam : https://steamcommunity.com/id/geralt_of_Japan/","uri":"","avatar":{"type":"image","data":{"uuid":"a5019fc0-0316-5f52-8558-9007c00c26d1","width":1024,"height":1024,"size":947202,"type":"png","color":"bf9464","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUHCP/EACIQAAICAQMEAwAAAAAAAAAAAAECAwQRAAYSBQchMRQjkf/EABgBAAIDAAAAAAAAAAAAAAAAAAIEAAMF/8QAHREAAgICAwEAAAAAAAAAAAAAAAIDEQExEnGBBP/aAAwDAQACEQMRAD8AxlsnYtbq3bDcXXTSqTfCz9z3GiMJUcpMxhCGypHHLDJ8DWLPPIk6ouut+2XwQo/zuzb715RLVpuFAD5AHg40+IUPLNqzDQsVYbEqQytGZI1chXOD7Ho6Csc7DvPGgnBB4CL+aMh//9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"2630336b-7347-50d2-a28f-1f861469bf0d","width":1920,"height":1080,"size":2777295,"type":"gif","color":"4d3f26","hash":"","external_service":[],"duration":4.36,"has_audio":true}},"cover_y":9},"achievements":[{"title":"Стрик 10 дней","code":"activity_10_days_streak","description":"10 дней активного участия в жизни DTF. Ачивка получена 5 раз. Последний — 5 ноября 2025.","previewUuid":"ee94db6d-7ec2-500e-aa2b-7e5ea5a36fea","formats":{"glb":"https://static.dtf.ru/achievements/spiral-02.glb","usdz":"https://static.dtf.ru/achievements/spiral-02.usdz"},"viewData":{"contentColor":"#525556","textMaxWidth":0.8046875,"textX":0.5,"textY":0.4677734375,"logoX":0.5,"logoY":0.591796875,"logoXNoText":0.5,"logoYNoText":0.5048828125},"id":2423732,"userId":3270,"count":0,"shareImage":"https://api.dtf.ru/achievements/share/2423732"},{"title":"Год на DTF","code":"registration_1_year","description":"Первый год с DTF. Получена 2 июня 2025.","previewUuid":"d6655520-3ebc-52c3-8b92-696b019b5788","formats":{"glb":"https://static.dtf.ru/achievements/egg-01.glb","usdz":"https://static.dtf.ru/achievements/egg-01.usdz"},"viewData":{"contentColor":"#1F97D4","textMaxWidth":0.62890625,"textX":0.5,"textY":0.6943359375,"logoX":0.5,"logoY":0.818359375,"logoXNoText":0.5,"logoYNoText":0.6865234375},"id":1853961,"userId":3270,"count":0,"shareImage":"https://api.dtf.ru/achievements/share/1853961"},{"title":"Стрик 5 дней","code":"activity_5_days_streak","description":"5 дней активного участия в жизни DTF. Ачивка получена 8 раз. Последний — 31 октября 2025.","previewUuid":"e8ed197d-404d-5dc4-8fd1-1e437822b31d","formats":{"glb":"https://static.dtf.ru/achievements/spiral-01.glb","usdz":"https://static.dtf.ru/achievements/spiral-01.usdz"},"viewData":{"contentColor":"#7C7C7C","textMaxWidth":0.8046875,"textX":0.5,"textY":0.4677734375,"logoX":0.5,"logoY":0.591796875,"logoXNoText":0.5,"logoYNoText":0.5048828125},"id":2417845,"userId":3270,"count":0,"shareImage":"https://api.dtf.ru/achievements/share/2417845"}],"lastModificationDate":1763199453,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":true,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":3270,"name":"Геральт из России","nickname":null,"description":"Добро пожаловать в steam : https://steamcommunity.com/id/geralt_of_Japan/","uri":"","avatar":{"type":"image","data":{"uuid":"a5019fc0-0316-5f52-8558-9007c00c26d1","width":1024,"height":1024,"size":947202,"type":"png","color":"bf9464","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUHCP/EACIQAAICAQMEAwAAAAAAAAAAAAECAwQRAAYSBQchMRQjkf/EABgBAAIDAAAAAAAAAAAAAAAAAAIEAAMF/8QAHREAAgICAwEAAAAAAAAAAAAAAAIDEQExEnGBBP/aAAwDAQACEQMRAD8AxlsnYtbq3bDcXXTSqTfCz9z3GiMJUcpMxhCGypHHLDJ8DWLPPIk6ouut+2XwQo/zuzb715RLVpuFAD5AHg40+IUPLNqzDQsVYbEqQytGZI1chXOD7Ho6Csc7DvPGgnBB4CL+aMh//9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"2630336b-7347-50d2-a28f-1f861469bf0d","width":1920,"height":1080,"size":2777295,"type":"gif","color":"4d3f26","hash":"","external_service":[],"duration":4.36,"has_audio":true}},"cover_y":9},"achievements":[{"title":"Стрик 10 дней","code":"activity_10_days_streak","description":"10 дней активного участия в жизни DTF. Ачивка получена 5 раз. Последний — 5 ноября 2025.","previewUuid":"ee94db6d-7ec2-500e-aa2b-7e5ea5a36fea","formats":{"glb":"https://static.dtf.ru/achievements/spiral-02.glb","usdz":"https://static.dtf.ru/achievements/spiral-02.usdz"},"viewData":{"contentColor":"#525556","textMaxWidth":0.8046875,"textX":0.5,"textY":0.4677734375,"logoX":0.5,"logoY":0.591796875,"logoXNoText":0.5,"logoYNoText":0.5048828125},"id":2423732,"userId":3270,"count":0,"shareImage":"https://api.dtf.ru/achievements/share/2423732"},{"title":"Год на DTF","code":"registration_1_year","description":"Первый год с DTF. Получена 2 июня 2025.","previewUuid":"d6655520-3ebc-52c3-8b92-696b019b5788","formats":{"glb":"https://static.dtf.ru/achievements/egg-01.glb","usdz":"https://static.dtf.ru/achievements/egg-01.usdz"},"viewData":{"contentColor":"#1F97D4","textMaxWidth":0.62890625,"textX":0.5,"textY":0.6943359375,"logoX":0.5,"logoY":0.818359375,"logoXNoText":0.5,"logoYNoText":0.6865234375},"id":1853961,"userId":3270,"count":0,"shareImage":"https://api.dtf.ru/achievements/share/1853961"},{"title":"Стрик 5 дней","code":"activity_5_days_streak","description":"5 дней активного участия в жизни DTF. Ачивка получена 8 раз. Последний — 31 октября 2025.","previewUuid":"e8ed197d-404d-5dc4-8fd1-1e437822b31d","formats":{"glb":"https://static.dtf.ru/achievements/spiral-01.glb","usdz":"https://static.dtf.ru/achievements/spiral-01.usdz"},"viewData":{"contentColor":"#7C7C7C","textMaxWidth":0.8046875,"textX":0.5,"textY":0.4677734375,"logoX":0.5,"logoY":0.591796875,"logoXNoText":0.5,"logoYNoText":0.5048828125},"id":2417845,"userId":3270,"count":0,"shareImage":"https://api.dtf.ru/achievements/share/2417845"}],"lastModificationDate":1763199453,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":true,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"reactions":{"counters":[{"id":2,"count":5},{"id":1,"count":2},{"id":24,"count":1},{"id":31,"count":1}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null,"keywords":[],"media":{"type":"image","data":{"uuid":"6a9e07fb-76e6-5695-9244-adaa57d784fc","width":672,"height":888,"size":87221,"type":"png","color":"e4eef9","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAUI/8QAIRAAAgIBBAIDAAAAAAAAAAAAAQMCBQQAERJBBiEzYXL/xAAVAQEBAAAAAAAAAAAAAAAAAAAEBf/EABsRAAICAwEAAAAAAAAAAAAAAAABAgMRITEE/9oADAMBAAIRAxEAPwDfNnbU9b5HR19l5FlYbLRTylQciGIZL29NMxz5SLAAAffHruhc8W5YKG4i5S4yMT0dtUFsMPFDRWZwH2VLgZbFNXJc340GShITEgQZA7EEAj7AOp3p3ITXwnN+Wf6OqUeIOz//2Q=="}},"customCover":null,"robotsTag":null,"categories":[10],"isAnonymized":true}};