Download index.html from openfree/testhtml: direct link, hf CLI and curl.
- Browser
- Download file 10.8 kB
-
https://huggingface.co/spaces/openfree/testhtml/resolve/main/index.html
- Command line
-
hf download hf://spaces/openfree/testhtml/index.html
-
curl -L -o index.html https://huggingface.co/spaces/openfree/testhtml/resolve/main/index.html
10.8 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Memory Match Game</title> | |
| <style> | |
| :root { | |
| --card-width: 120px; | |
| --card-height: 150px; | |
| --primary-color: #2c3e50; | |
| --secondary-color: #3498db; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| min-height: 100vh; | |
| background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| color: white; | |
| } | |
| .game-container { | |
| margin-top: 2rem; | |
| text-align: center; | |
| } | |
| .controls { | |
| margin: 1rem 0; | |
| display: flex; | |
| gap: 1rem; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .btn { | |
| padding: 0.5rem 1rem; | |
| border: none; | |
| border-radius: 5px; | |
| background: rgba(255, 255, 255, 0.2); | |
| color: white; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .btn:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| } | |
| .stats { | |
| display: flex; | |
| gap: 2rem; | |
| margin: 1rem; | |
| font-size: 1.2rem; | |
| } | |
| .board { | |
| display: grid; | |
| gap: 10px; | |
| padding: 20px; | |
| perspective: 1000px; | |
| } | |
| .card { | |
| width: var(--card-width); | |
| height: var(--card-height); | |
| position: relative; | |
| transform-style: preserve-3d; | |
| transition: transform 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| cursor: pointer; | |
| } | |
| .card.flipped { | |
| transform: rotateY(180deg); | |
| } | |
| .card.matched { | |
| transform: rotateY(180deg) scale(0.95); | |
| opacity: 0.8; | |
| } | |
| .card-face { | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| backface-visibility: hidden; | |
| border-radius: 10px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 2rem; | |
| box-shadow: 0 4px 8px rgba(0,0,0,0.1); | |
| } | |
| .card-front { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| transform: rotateY(180deg); | |
| } | |
| .card-back { | |
| background: linear-gradient(135deg, #2c3e50 0%, #3498db 100%); | |
| } | |
| .modal { | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(0, 0, 0, 0.9); | |
| padding: 2rem; | |
| border-radius: 10px; | |
| text-align: center; | |
| display: none; | |
| } | |
| @keyframes match { | |
| 0%, 100% { transform: rotateY(180deg) scale(1); } | |
| 50% { transform: rotateY(180deg) scale(1.1); } | |
| } | |
| @keyframes mismatch { | |
| 0%, 100% { transform: rotateY(180deg); } | |
| 20%, 40%, 60%, 80% { transform: rotateY(180deg) translateX(-10px); } | |
| 30%, 50%, 70%, 90% { transform: rotateY(180deg) translateX(10px); } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="game-container"> | |
| <h1>Memory Match</h1> | |
| <div class="controls"> | |
| <select id="difficulty" class="btn"> | |
| <option value="8">Easy (4x4)</option> | |
| <option value="18">Medium (6x6)</option> | |
| <option value="32">Hard (8x8)</option> | |
| </select> | |
| <button class="btn" id="start">New Game</button> | |
| </div> | |
| <div class="stats"> | |
| <div>Moves: <span id="moves">0</span></div> | |
| <div>Time: <span id="timer">0:00</span></div> | |
| <div>Score: <span id="score">0</span></div> | |
| </div> | |
| <div class="board" id="board"></div> | |
| </div> | |
| <div class="modal" id="win-modal"> | |
| <h2>Congratulations!</h2> | |
| <p>You completed the game in <span id="final-time"></span></p> | |
| <p>Final Score: <span id="final-score"></span></p> | |
| <button class="btn" onclick="startGame()">Play Again</button> | |
| </div> | |
| <script> | |
| const audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
| let gameState = { | |
| flippedCards: [], | |
| matches: 0, | |
| moves: 0, | |
| score: 0, | |
| timer: 0, | |
| gameStarted: false, | |
| timerInterval: null | |
| }; | |
| const emojis = ['๐ฎ', '๐ฒ', '๐ฏ', '๐จ', '๐ญ', '๐ช', '๐ซ', '๐ฌ', | |
| '๐ค', '๐ง', '๐ท', '๐ธ', '๐น', '๐บ', '๐ป', '๐ฅ', | |
| 'โฝ๏ธ', '๐', '๐', 'โพ๏ธ', '๐พ', '๐', '๐', '๐ฑ', | |
| '๐', '๐ธ', '๐ฅ', '๐ฅ', '๐ฃ', 'โณ๏ธ', '๐น', '๐ฝ']; | |
| function createAudioBuffer(frequency, duration) { | |
| const sampleRate = audioContext.sampleRate; | |
| const buffer = audioContext.createBuffer(1, duration * sampleRate, sampleRate); | |
| const data = buffer.getChannelData(0); | |
| for (let i = 0; i < buffer.length; i++) { | |
| data[i] = Math.sin(2 * Math.PI * frequency * i / sampleRate) * | |
| Math.exp(-5 * i / buffer.length); | |
| } | |
| return buffer; | |
| } | |
| const matchSound = createAudioBuffer(440, 0.1); | |
| const mismatchSound = createAudioBuffer(220, 0.1); | |
| function playSound(buffer) { | |
| const source = audioContext.createBufferSource(); | |
| source.buffer = buffer; | |
| source.connect(audioContext.destination); | |
| source.start(); | |
| } | |
| function createBoard() { | |
| const board = document.getElementById('board'); | |
| const difficulty = parseInt(document.getElementById('difficulty').value); | |
| const pairs = difficulty; | |
| const size = Math.sqrt(pairs * 2); | |
| board.style.gridTemplateColumns = `repeat(${size}, var(--card-width))`; | |
| board.innerHTML = ''; | |
| const selectedEmojis = emojis.slice(0, pairs); | |
| const cards = [...selectedEmojis, ...selectedEmojis] | |
| .sort(() => Math.random() - 0.5); | |
| cards.forEach((emoji, index) => { | |
| const card = document.createElement('div'); | |
| card.className = 'card'; | |
| card.dataset.value = emoji; | |
| card.dataset.index = index; | |
| card.innerHTML = ` | |
| <div class="card-face card-front">${emoji}</div> | |
| <div class="card-face card-back">?</div> | |
| `; | |
| card.addEventListener('click', flipCard); | |
| board.appendChild(card); | |
| }); | |
| } | |
| function flipCard() { | |
| if (!gameState.gameStarted) { | |
| startTimer(); | |
| gameState.gameStarted = true; | |
| } | |
| const card = this; | |
| if (card.classList.contains('flipped') || | |
| gameState.flippedCards.length >= 2) return; | |
| card.classList.add('flipped'); | |
| gameState.flippedCards.push(card); | |
| if (gameState.flippedCards.length === 2) { | |
| gameState.moves++; | |
| document.getElementById('moves').textContent = gameState.moves; | |
| checkMatch(); | |
| } | |
| } | |
| function checkMatch() { | |
| const [card1, card2] = gameState.flippedCards; | |
| const match = card1.dataset.value === card2.dataset.value; | |
| if (match) { | |
| playSound(matchSound); | |
| card1.classList.add('matched'); | |
| card2.classList.add('matched'); | |
| gameState.matches++; | |
| gameState.score += 100; | |
| card1.style.animation = card2.style.animation = 'match 0.5s ease'; | |
| if (gameState.matches === parseInt(document.getElementById('difficulty').value)) { | |
| endGame(); | |
| } | |
| } else { | |
| playSound(mismatchSound); | |
| card1.style.animation = card2.style.animation = 'mismatch 0.5s ease'; | |
| gameState.score = Math.max(0, gameState.score - 20); | |
| setTimeout(() => { | |
| card1.classList.remove('flipped'); | |
| card2.classList.remove('flipped'); | |
| }, 1000); | |
| } | |
| setTimeout(() => { | |
| card1.style.animation = card2.style.animation = ''; | |
| }, 500); | |
| document.getElementById('score').textContent = gameState.score; | |
| gameState.flippedCards = []; | |
| } | |
| function startTimer() { | |
| gameState.timerInterval = setInterval(() => { | |
| gameState.timer++; | |
| const minutes = Math.floor(gameState.timer / 60); | |
| const seconds = gameState.timer % 60; | |
| document.getElementById('timer').textContent = | |
| `${minutes}:${seconds.toString().padStart(2, '0')}`; | |
| }, 1000); | |
| } | |
| function endGame() { | |
| clearInterval(gameState.timerInterval); | |
| const modal = document.getElementById('win-modal'); | |
| document.getElementById('final-time').textContent = | |
| document.getElementById('timer').textContent; | |
| document.getElementById('final-score').textContent = gameState.score; | |
| modal.style.display = 'block'; | |
| } | |
| function startGame() { | |
| gameState = { | |
| flippedCards: [], | |
| matches: 0, | |
| moves: 0, | |
| score: 0, | |
| timer: 0, | |
| gameStarted: false, | |
| timerInterval: null | |
| }; | |
| document.getElementById('moves').textContent = '0'; | |
| document.getElementById('timer').textContent = '0:00'; | |
| document.getElementById('score').textContent = '0'; | |
| document.getElementById('win-modal').style.display = 'none'; | |
| createBoard(); | |
| clearInterval(gameState.timerInterval); | |
| } | |
| document.getElementById('start').addEventListener('click', startGame); | |
| document.getElementById('difficulty').addEventListener('change', startGame); | |
| // Initial game setup | |
| startGame(); | |
| </script> | |
| </body> | |
| </html> |