Download index.html from mrwhy06/test: direct link, hf CLI and curl.
- Browser
- Download file 16.1 kB
-
https://huggingface.co/spaces/mrwhy06/test/resolve/main/index.html
- Command line
-
hf download hf://spaces/mrwhy06/test/index.html
-
curl -L -o index.html https://huggingface.co/spaces/mrwhy06/test/resolve/main/index.html
16.1 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Ball Sort Puzzle</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Arial', sans-serif; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); | |
| height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| overflow: hidden; | |
| } | |
| .game-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| width: 100%; | |
| max-width: 800px; | |
| padding: 20px; | |
| } | |
| h1 { | |
| margin-bottom: 20px; | |
| font-size: 2.5rem; | |
| text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); | |
| text-align: center; | |
| } | |
| .tubes-container { | |
| display: flex; | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| gap: 20px; | |
| width: 100%; | |
| margin: 30px 0; | |
| } | |
| .tube { | |
| width: 60px; | |
| height: 200px; | |
| background-color: rgba(255, 255, 255, 0.1); | |
| border-radius: 5px 5px 0 0; | |
| position: relative; | |
| cursor: pointer; | |
| border: 2px solid rgba(255, 255, 255, 0.3); | |
| display: flex; | |
| flex-direction: column-reverse; | |
| align-items: center; | |
| transition: transform 0.2s; | |
| margin-bottom: 40px; | |
| } | |
| .tube::after { | |
| content: ''; | |
| position: absolute; | |
| bottom: -20px; | |
| left: -2px; | |
| right: -2px; | |
| height: 20px; | |
| background-color: rgba(255, 255, 255, 0.1); | |
| border-radius: 0 0 5px 5px; | |
| border: 2px solid rgba(255, 255, 255, 0.3); | |
| } | |
| .tube:hover { | |
| transform: translateY(-5px); | |
| } | |
| .tube.selected { | |
| transform: scale(1.05); | |
| box-shadow: 0 0 15px rgba(255, 255, 255, 0.7); | |
| } | |
| .ball { | |
| width: 50px; | |
| height: 50px; | |
| border-radius: 50%; | |
| margin-top: 5px; | |
| transition: all 0.3s ease; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-weight: bold; | |
| color: rgba(0, 0, 0, 0.5); | |
| box-shadow: inset -5px -5px 10px rgba(0, 0, 0, 0.2); | |
| } | |
| .ball::after { | |
| content: ''; | |
| position: absolute; | |
| top: 10px; | |
| left: 10px; | |
| width: 15px; | |
| height: 15px; | |
| border-radius: 50%; | |
| background-color: rgba(255, 255, 255, 0.4); | |
| } | |
| .controls { | |
| display: flex; | |
| gap: 20px; | |
| margin-top: 20px; | |
| } | |
| button { | |
| padding: 10px 20px; | |
| font-size: 1rem; | |
| background-color: rgba(255, 255, 255, 0.2); | |
| color: white; | |
| border: 2px solid white; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| font-weight: bold; | |
| } | |
| button:hover { | |
| background-color: rgba(255, 255, 255, 0.4); | |
| transform: translateY(-2px); | |
| } | |
| .level-info { | |
| margin-top: 20px; | |
| font-size: 1.2rem; | |
| text-align: center; | |
| } | |
| .message { | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background-color: rgba(0, 0, 0, 0.8); | |
| color: white; | |
| padding: 30px 50px; | |
| border-radius: 10px; | |
| font-size: 2rem; | |
| display: none; | |
| z-index: 100; | |
| text-align: center; | |
| box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); | |
| } | |
| .message button { | |
| margin-top: 20px; | |
| display: block; | |
| width: 100%; | |
| } | |
| .move-counter { | |
| font-size: 1.2rem; | |
| margin-bottom: 20px; | |
| background-color: rgba(0, 0, 0, 0.3); | |
| padding: 10px 20px; | |
| border-radius: 5px; | |
| } | |
| @media (max-width: 600px) { | |
| .tube { | |
| width: 50px; | |
| height: 180px; | |
| } | |
| .ball { | |
| width: 45px; | |
| height: 45px; | |
| } | |
| h1 { | |
| font-size: 1.8rem; | |
| } | |
| } | |
| .floating-balls { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| pointer-events: none; | |
| z-index: -1; | |
| } | |
| .floating-ball { | |
| position: absolute; | |
| border-radius: 50%; | |
| opacity: 0.3; | |
| animation: float 15s infinite linear; | |
| } | |
| @keyframes float { | |
| 0% { | |
| transform: translate(0, 0) rotate(0deg); | |
| } | |
| 25% { | |
| transform: translate(100px, 50px) rotate(90deg); | |
| } | |
| 50% { | |
| transform: translate(200px, -50px) rotate(180deg); | |
| } | |
| 75% { | |
| transform: translate(100px, 50px) rotate(270deg); | |
| } | |
| 100% { | |
| transform: translate(0, 0) rotate(360deg); | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="floating-balls" id="floatingBalls"></div> | |
| <div class="game-container"> | |
| <h1>Ball Sort Puzzle</h1> | |
| <div class="move-counter">Moves: <span id="moves">0</span></div> | |
| <div class="tubes-container" id="tubes"></div> | |
| <div class="level-info">Level: <span id="level">1</span></div> | |
| <div class="controls"> | |
| <button id="btnNewGame">New Game</button> | |
| <button id="btnUndo">Undo</button> | |
| </div> | |
| </div> | |
| <div class="message" id="winMessage"> | |
| Level Complete! | |
| <button id="btnNextLevel">Next Level</button> | |
| </div> | |
| <script> | |
| // Game state | |
| const gameState = { | |
| tubes: [], | |
| selectedTube: null, | |
| moves: 0, | |
| level: 1, | |
| moveHistory: [] | |
| }; | |
| // Colors | |
| const colors = [ | |
| '#FF5252', '#FF4081', '#E040FB', '#7C4DFF', | |
| '#536DFE', '#448AFF', '#40C4FF', '#18FFFF', | |
| '#64FFDA', '#69F0AE', '#B2FF59', '#EEFF41', | |
| '#FFFF00', '#FFD740', '#FFAB40', '#FF6E40' | |
| ]; | |
| // DOM elements | |
| const tubesContainer = document.getElementById('tubes'); | |
| const movesDisplay = document.getElementById('moves'); | |
| const levelDisplay = document.getElementById('level'); | |
| const btnNewGame = document.getElementById('btnNewGame'); | |
| const btnUndo = document.getElementById('btnUndo'); | |
| const winMessage = document.getElementById('winMessage'); | |
| const btnNextLevel = document.getElementById('btnNextLevel'); | |
| const floatingBalls = document.getElementById('floatingBalls'); | |
| // Initialize floating background balls | |
| function createFloatingBalls() { | |
| floatingBalls.innerHTML = ''; | |
| for (let i = 0; i < 20; i++) { | |
| const ball = document.createElement('div'); | |
| ball.className = 'floating-ball'; | |
| const size = Math.random() * 100 + 50; | |
| ball.style.width = `${size}px`; | |
| ball.style.height = `${size}px`; | |
| ball.style.background = colors[Math.floor(Math.random() * colors.length)]; | |
| ball.style.left = `${Math.random() * 100}%`; | |
| ball.style.top = `${Math.random() * 100}%`; | |
| ball.style.animationDuration = `${Math.random() * 20 + 10}s`; | |
| floatingBalls.appendChild(ball); | |
| } | |
| } | |
| // Initialize game | |
| function initGame() { | |
| gameState.tubes = []; | |
| gameState.selectedTube = null; | |
| gameState.moves = 0; | |
| gameState.moveHistory = []; | |
| movesDisplay.textContent = gameState.moves; | |
| levelDisplay.textContent = gameState.level; | |
| tubesContainer.innerHTML = ''; | |
| const tubeCount = Math.min(3 + gameState.level, 8); | |
| const colorCount = Math.min(tubeCount - 2, colors.length); | |
| // Create color set | |
| const selectedColors = colors.slice(0, colorCount); | |
| const allBalls = []; | |
| // Create 4 balls for each color | |
| selectedColors.forEach(color => { | |
| for (let i = 0; i < 4; i++) { | |
| allBalls.push(color); | |
| } | |
| }); | |
| // Shuffle balls | |
| shuffleArray(allBalls); | |
| // Distribute balls to tubes (first tubeCount - 2 tubes) | |
| const ballsPerTube = allBalls.length / (tubeCount - 2); | |
| for (let i = 0; i < tubeCount - 2; i++) { | |
| const tubeBalls = []; | |
| for (let j = 0; j < ballsPerTube; j++) { | |
| tubeBalls.push(allBalls[i * ballsPerTube + j]); | |
| } | |
| gameState.tubes.push(tubeBalls); | |
| } | |
| // Add empty tubes (2) | |
| for (let i = 0; i < 2; i++) { | |
| gameState.tubes.push([]); | |
| } | |
| renderTubes(); | |
| } | |
| // Helper function to shuffle an array | |
| function shuffleArray(array) { | |
| for (let i = array.length - 1; i > 0; i--) { | |
| const j = Math.floor(Math.random() * (i + 1)); | |
| [array[i], array[j]] = [array[j], array[i]]; | |
| } | |
| } | |
| // Render tubes and balls | |
| function renderTubes() { | |
| tubesContainer.innerHTML = ''; | |
| gameState.tubes.forEach((tubeBalls, index) => { | |
| const tubeElement = document.createElement('div'); | |
| tubeElement.className = 'tube'; | |
| if (gameState.selectedTube === index) { | |
| tubeElement.classList.add('selected'); | |
| } | |
| tubeElement.addEventListener('click', () => handleTubeClick(index)); | |
| tubeBalls.forEach((ballColor, ballIndex) => { | |
| const ballElement = document.createElement('div'); | |
| ballElement.className = 'ball'; | |
| ballElement.style.backgroundColor = ballColor; | |
| tubeElement.appendChild(ballElement); | |
| }); | |
| tubesContainer.appendChild(tubeElement); | |
| }); | |
| } | |
| // Handle tube click | |
| function handleTubeClick(tubeIndex) { | |
| if (gameState.selectedTube === null) { | |
| // Select a tube if it has balls | |
| if (gameState.tubes[tubeIndex].length > 0) { | |
| gameState.selectedTube = tubeIndex; | |
| renderTubes(); | |
| } | |
| } else { | |
| // Try to move ball from selected tube to clicked tube | |
| if (gameState.selectedTube === tubeIndex) { | |
| // Deselect if same tube clicked | |
| gameState.selectedTube = null; | |
| renderTubes(); | |
| } else { | |
| moveBall(gameState.selectedTube, tubeIndex); | |
| } | |
| } | |
| } | |
| // Move ball from one tube to another | |
| function moveBall(fromTubeIndex, toTubeIndex) { | |
| const fromTube = gameState.tubes[fromTubeIndex]; | |
| const toTube = gameState.tubes[toTubeIndex]; | |
| if (fromTube.length === 0) { | |
| gameState.selectedTube = null; | |
| renderTubes(); | |
| return; | |
| } | |
| // Check if move is valid | |
| const topBallColor = fromTube[fromTube.length - 1]; | |
| // Can move if: | |
| // 1. Destination tube is empty, OR | |
| // 2. Destination tube's top ball is same color and has space | |
| if (toTube.length === 0 || | |
| (toTube[toTube.length - 1] === topBallColor && toTube.length < 4)) { | |
| // Store move in history | |
| const prevState = JSON.parse(JSON.stringify(gameState.tubes)); | |
| gameState.moveHistory.push(prevState); | |
| // Move the ball(s) of the same color from top | |
| let ballsToMove = 0; | |
| for (let i = fromTube.length - 1; i >= 0; i--) { | |
| if (fromTube[i] === topBallColor && (toTube.length + ballsToMove) < 4) { | |
| ballsToMove++; | |
| } else { | |
| break; | |
| } | |
| } | |
| // Move the balls | |
| const movedBalls = fromTube.splice(fromTube.length - ballsToMove, ballsToMove); | |
| toTube.push(...movedBalls); | |
| gameState.moves++; | |
| movesDisplay.textContent = gameState.moves; | |
| // Check for win condition | |
| if (checkWin()) { | |
| showWinMessage(); | |
| } | |
| gameState.selectedTube = null; | |
| renderTubes(); | |
| } else { | |
| gameState.selectedTube = null; | |
| renderTubes(); | |
| } | |
| } | |
| // Check if all tubes are complete (all balls of same color or empty) | |
| function checkWin() { | |
| return gameState.tubes.every(tube => { | |
| if (tube.length === 0) return true; | |
| if (tube.length < 4) return false; | |
| const firstColor = tube[0]; | |
| return tube.every(ball => ball === firstColor); | |
| }); | |
| } | |
| // Show win message | |
| function showWinMessage() { | |
| winMessage.style.display = 'block'; | |
| } | |
| // Undo last move | |
| function undoMove() { | |
| if (gameState.moveHistory.length > 0) { | |
| gameState.tubes = gameState.moveHistory.pop(); | |
| gameState.moves++; | |
| movesDisplay.textContent = gameState.moves; | |
| gameState.selectedTube = null; | |
| renderTubes(); | |
| } | |
| } | |
| // Next level | |
| function nextLevel() { | |
| gameState.level++; | |
| winMessage.style.display = 'none'; | |
| initGame(); | |
| } | |
| // Event listeners | |
| btnNewGame.addEventListener('click', initGame); | |
| btnUndo.addEventListener('click', undoMove); | |
| btnNextLevel.addEventListener('click', nextLevel); | |
| // Initialize | |
| createFloatingBalls(); | |
| initGame(); | |
| // Add keyboard controls | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'Escape') { | |
| gameState.selectedTube = null; | |
| renderTubes(); | |
| } else if (e.key === 'z' && (e.ctrlKey || e.metaKey)) { | |
| undoMove(); | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
| </html> |