[{"id":2,"app_id":1,"version":2,"html":"<html><body>Yo World!</body></html>","created_at":"2025-02-04T17:15:22.108Z","url":"https://quickhtml.app/myapp"},{"id":3,"app_id":2,"version":1,"html":"html","created_at":"2025-02-04T17:26:39.165Z","url":"https://quickhtml.app/test"},{"id":4,"app_id":3,"version":1,"html":"html","created_at":"2025-02-04T17:27:26.811Z","url":"https://quickhtml.app/testo"},{"id":5,"app_id":4,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Test HTML App</title>\n  <style>\n    body {\n      font-family: Arial, sans-serif;\n      margin: 20px;\n      text-align: center;\n      background-color: #f5f5f5;\n    }\n    h1 {\n      color: #333;\n    }\n    p {\n      color: #666;\n    }\n  </style>\n</head>\n<body>\n  <h1>Welcome to Your Test HTML App!</h1>\n  <p>This is a sample page for testing purposes.</p>\n</body>\n</html>","created_at":"2025-02-04T17:27:39.060Z","url":"https://quickhtml.app/mine"},{"id":6,"app_id":5,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Test HTML App</title>\n  <style>\n    body {\n      font-family: Arial, sans-serif;\n      margin: 20px;\n      text-align: center;\n      background-color: #f5f5f5;\n    }\n    h1 {\n      color: #333;\n    }\n    p {\n      color: #666;\n    }\n  </style>\n</head>\n<body>\n  <h1>Welcome to Your Test HTML App!</h1>\n  <p>This is a sample page for testing purposes.</p>\n</body>\n</html>","created_at":"2025-02-04T17:34:36.326Z","url":"https://quickhtml.app/testoi"},{"id":7,"app_id":6,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <title>Accelerometer Rolling Ball Game</title>\n  <style>\n    html, body {\n      margin: 0;\n      padding: 0;\n      background: #222;\n      overflow: hidden;\n      height: 100%;\n    }\n    canvas {\n      display: block;\n      background: #eee;\n    }\n    #permissionButton {\n      position: absolute;\n      top: 20px;\n      left: 20px;\n      padding: 10px 20px;\n      font-size: 16px;\n      z-index: 10;\n      display: none;\n    }\n  </style>\n</head>\n<body>\n  <!-- Button to request device orientation permission (iOS 13+ requirement) -->\n  <button id=\"permissionButton\">Enable Motion Control</button>\n  <canvas id=\"gameCanvas\"></canvas>\n\n  <script>\n    const canvas = document.getElementById('gameCanvas');\n    const ctx = canvas.getContext('2d');\n\n    // Resize canvas to fill the screen\n    function resizeCanvas() {\n      canvas.width = window.innerWidth;\n      canvas.height = window.innerHeight;\n    }\n    window.addEventListener('resize', resizeCanvas);\n    resizeCanvas();\n\n    // Define the ball object\n    let ball = {\n      x: canvas.width / 2,\n      y: canvas.height / 2,\n      radius: 20,\n      vx: 0,\n      vy: 0,\n      ax: 0,\n      ay: 0\n    };\n\n    const friction = 0.98;      // Friction to slow down the ball\n    const accelFactor = 0.1;    // Multiplier for the acceleration\n\n    // Update ball physics\n    function updateBall() {\n      // Update velocity with current acceleration\n      ball.vx += ball.ax * accelFactor;\n      ball.vy += ball.ay * accelFactor;\n\n      // Apply friction to velocities\n      ball.vx *= friction;\n      ball.vy *= friction;\n\n      // Update position\n      ball.x += ball.vx;\n      ball.y += ball.vy;\n\n      // Bounce off the edges\n      if (ball.x + ball.radius > canvas.width) {\n        ball.x = canvas.width - ball.radius;\n        ball.vx *= -0.5;\n      }\n      if (ball.x - ball.radius < 0) {\n        ball.x = ball.radius;\n        ball.vx *= -0.5;\n      }\n      if (ball.y + ball.radius > canvas.height) {\n        ball.y = canvas.height - ball.radius;\n        ball.vy *= -0.5;\n      }\n      if (ball.y - ball.radius < 0) {\n        ball.y = ball.radius;\n        ball.vy *= -0.5;\n      }\n    }\n\n    // Draw the ball on the canvas\n    function drawBall() {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      ctx.beginPath();\n      ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);\n      ctx.fillStyle = \"#0077ff\";\n      ctx.fill();\n      ctx.closePath();\n    }\n\n    // The game loop\n    function gameLoop() {\n      updateBall();\n      drawBall();\n      requestAnimationFrame(gameLoop);\n    }\n\n    // Start the game loop\n    gameLoop();\n\n    // Handle device orientation events to control the ball\n    function handleOrientation(event) {\n      // Use gamma (left-to-right tilt) for horizontal acceleration\n      // and beta (front-to-back tilt) for vertical acceleration.\n      // Adjust these if needed based on your device's behavior.\n      ball.ax = event.gamma || 0;\n      ball.ay = event.beta || 0;\n    }\n\n    // Check if we need to request permission for motion events (iOS 13+)\n    if (typeof DeviceOrientationEvent !== 'undefined' &&\n        typeof DeviceOrientationEvent.requestPermission === 'function') {\n      const permissionButton = document.getElementById('permissionButton');\n      permissionButton.style.display = 'block';\n      permissionButton.addEventListener('click', function() {\n        DeviceOrientationEvent.requestPermission()\n          .then(permissionState => {\n            if (permissionState === 'granted') {\n              window.addEventListener('deviceorientation', handleOrientation, true);\n              permissionButton.style.display = 'none';\n            }\n          })\n          .catch(console.error);\n      });\n    } else {\n      // For devices that don't require permission\n      window.addEventListener('deviceorientation', handleOrientation, true);\n    }\n  </script>\n</body>\n</html>","created_at":"2025-02-04T17:35:30.243Z","url":"https://quickhtml.app/ball"},{"id":10,"app_id":7,"version":3,"html":"<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>Test Tone</title>\n</head>\n<body style=\"display:flex; justify-content:center; align-items:center; height:100vh; background:#222;\">\n  <button id=\"playButton\" style=\"padding:20px;font-size:1.5em;\">Play Tone</button>\n  <script>\n    const audioContext = new (window.AudioContext || window.webkitAudioContext)();\n\n    // Ensure AudioContext resumes on touch\n    document.body.addEventListener('touchstart', () => {\n      if (audioContext.state === 'suspended') {\n        audioContext.resume();\n      }\n    }, { once: true });\n\n    document.getElementById('playButton').addEventListener('click', () => {\n      if (audioContext.state === 'suspended') {\n        audioContext.resume();\n      }\n      const osc = audioContext.createOscillator();\n      const gain = audioContext.createGain();\n      osc.type = 'sine';\n      osc.frequency.value = 440;  // A4 note\n      osc.connect(gain);\n      gain.connect(audioContext.destination);\n      osc.start();\n      setTimeout(() => {\n        osc.stop();\n      }, 500);\n    });\n  </script>\n</body>\n</html>","created_at":"2025-02-04T17:39:23.172Z","url":"https://quickhtml.app/keyboard"},{"id":72,"app_id":8,"version":4,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Tilt Ball Game</title>\n    <style>\n        body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; }\n        canvas { display: block; background: #ddd; }\n        #error-log {\n            position: fixed; top: 10px; left: 50%; transform: translateX(-50%);\n            background: rgba(255, 0, 0, 0.8); color: white;\n            padding: 10px; border-radius: 5px; display: none;\n        }\n    </style>\n</head>\n<body>\n    <div id=\"error-log\"></div>\n    <canvas id=\"gameCanvas\"></canvas>\n    <script>\n        // Error Handling\n        window.onerror = function(message, source, lineno, colno, error) {\n            let log = document.getElementById('error-log');\n            log.innerText = `Error: ${message} at ${lineno}:${colno}`;\n            log.style.display = 'block';\n            setTimeout(() => log.style.display = 'none', 5000);\n        };\n        \n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        \n        canvas.width = window.innerWidth;\n        canvas.height = window.innerHeight;\n        \n        let ball = { x: canvas.width / 2, y: canvas.height / 2, radius: 20, speed: 2, dx: 0, dy: 0 };\n        let goal = { x: canvas.width - 50, y: canvas.height - 50, size: 40 };\n        \n        function drawBall() {\n            ctx.beginPath();\n            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);\n            ctx.fillStyle = \"blue\";\n            ctx.fill();\n            ctx.closePath();\n        }\n        \n        function drawGoal() {\n            ctx.fillStyle = \"green\";\n            ctx.fillRect(goal.x, goal.y, goal.size, goal.size);\n        }\n        \n        function updateBall() {\n            ball.x += ball.dx;\n            ball.y += ball.dy;\n            \n            if (ball.x - ball.radius < 0) ball.x = ball.radius;\n            if (ball.x + ball.radius > canvas.width) ball.x = canvas.width - ball.radius;\n            if (ball.y - ball.radius < 0) ball.y = ball.radius;\n            if (ball.y + ball.radius > canvas.height) ball.y = canvas.height - ball.radius;\n        }\n        \n        function checkWin() {\n            if (ball.x > goal.x && ball.x < goal.x + goal.size &&\n                ball.y > goal.y && ball.y < goal.y + goal.size) {\n                alert(\"You Win!\");\n                ball.x = canvas.width / 2;\n                ball.y = canvas.height / 2;\n            }\n        }\n        \n        function gameLoop() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            drawGoal();\n            drawBall();\n            updateBall();\n            checkWin();\n            requestAnimationFrame(gameLoop);\n        }\n        \n        window.addEventListener(\"deviceorientation\", (event) => {\n            let tiltX = event.beta;\n            let tiltY = event.gamma;\n            \n            ball.dx = (tiltY / 30) * ball.speed;\n            ball.dy = (tiltX / 30) * ball.speed;\n        });\n        \n        gameLoop();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T20:48:23.873Z","url":"https://quickhtml.app/tilt-ball-game"},{"id":12,"app_id":9,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Drawing App</title>\n    <style>\n        body {\n            margin: 0;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            height: 100vh;\n            background-color: #f0f0f0;\n        }\n        canvas {\n            border: 1px solid black;\n            background-color: white;\n        }\n        .toolbar {\n            display: flex;\n            gap: 10px;\n            margin-bottom: 10px;\n        }\n        button, input {\n            padding: 5px;\n        }\n        .dark-mode {\n            background-color: #222;\n            color: white;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"toolbar\">\n        <input type=\"color\" id=\"colorPicker\" value=\"#000000\">\n        <input type=\"range\" id=\"brushSize\" min=\"1\" max=\"20\" value=\"5\">\n        <button onclick=\"clearCanvas()\">Clear</button>\n        <button onclick=\"undo()\">Undo</button>\n        <button onclick=\"redo()\">Redo</button>\n        <button onclick=\"saveCanvas()\">Save</button>\n        <button onclick=\"toggleDarkMode()\">Dark Mode</button>\n    </div>\n    <canvas id=\"drawingCanvas\" width=\"500\" height=\"500\"></canvas>\n    <script>\n        const canvas = document.getElementById('drawingCanvas');\n        const ctx = canvas.getContext('2d');\n        const colorPicker = document.getElementById('colorPicker');\n        const brushSize = document.getElementById('brushSize');\n        let drawing = false;\n        let paths = [], redoStack = [];\n        \n        canvas.addEventListener('mousedown', startDrawing);\n        canvas.addEventListener('mousemove', draw);\n        canvas.addEventListener('mouseup', stopDrawing);\n        canvas.addEventListener('mouseleave', stopDrawing);\n        \n        function startDrawing(event) {\n            drawing = true;\n            ctx.beginPath();\n            ctx.moveTo(event.offsetX, event.offsetY);\n            paths.push(ctx.getImageData(0, 0, canvas.width, canvas.height));\n        }\n        \n        function draw(event) {\n            if (!drawing) return;\n            ctx.lineTo(event.offsetX, event.offsetY);\n            ctx.strokeStyle = colorPicker.value;\n            ctx.lineWidth = brushSize.value;\n            ctx.lineCap = 'round';\n            ctx.stroke();\n        }\n        \n        function stopDrawing() {\n            drawing = false;\n            ctx.closePath();\n        }\n        \n        function clearCanvas() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            paths = [];\n            redoStack = [];\n        }\n        \n        function undo() {\n            if (paths.length > 0) {\n                redoStack.push(paths.pop());\n                ctx.putImageData(paths[paths.length - 1] || ctx.createImageData(canvas.width, canvas.height), 0, 0);\n            }\n        }\n        \n        function redo() {\n            if (redoStack.length > 0) {\n                paths.push(redoStack.pop());\n                ctx.putImageData(paths[paths.length - 1], 0, 0);\n            }\n        }\n        \n        function saveCanvas() {\n            const link = document.createElement('a');\n            link.download = 'drawing.png';\n            link.href = canvas.toDataURL();\n            link.click();\n        }\n        \n        function toggleDarkMode() {\n            document.body.classList.toggle('dark-mode');\n        }\n    </script>\n</body>\n</html>","created_at":"2025-02-04T18:04:15.713Z","url":"https://quickhtml.app/drawing-app"},{"id":13,"app_id":10,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Tip Calculator</title>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            text-align: center;\n            margin: 40px;\n        }\n        .container {\n            max-width: 300px;\n            margin: auto;\n            padding: 20px;\n            border: 1px solid #ddd;\n            border-radius: 8px;\n            box-shadow: 2px 2px 10px rgba(0,0,0,0.1);\n        }\n        input, select, button {\n            width: 100%;\n            padding: 10px;\n            margin: 10px 0;\n            font-size: 16px;\n        }\n        .result {\n            margin-top: 20px;\n            font-size: 18px;\n            font-weight: bold;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <h2>Tip Calculator</h2>\n        <label for=\"bill\">Bill Amount:</label>\n        <input type=\"number\" id=\"bill\" placeholder=\"Enter bill amount\">\n        \n        <label for=\"tip\">Tip Percentage:</label>\n        <select id=\"tip\" onchange=\"toggleCustomTip()\">\n            <option value=\"0.10\">10%</option>\n            <option value=\"0.15\" selected>15%</option>\n            <option value=\"0.20\">20%</option>\n            <option value=\"custom\">Custom</option>\n        </select>\n        \n        <input type=\"number\" id=\"customTip\" placeholder=\"Enter custom %\" style=\"display:none;\">\n        \n        <button onclick=\"calculateTip()\">Calculate</button>\n        \n        <div class=\"result\" id=\"result\"></div>\n    </div>\n\n    <script>\n        function toggleCustomTip() {\n            const tipSelect = document.getElementById('tip');\n            const customTipInput = document.getElementById('customTip');\n            if (tipSelect.value === 'custom') {\n                customTipInput.style.display = 'block';\n            } else {\n                customTipInput.style.display = 'none';\n            }\n        }\n\n        function calculateTip() {\n            let bill = parseFloat(document.getElementById('bill').value);\n            let tipPercent = document.getElementById('tip').value;\n            \n            if (tipPercent === 'custom') {\n                tipPercent = parseFloat(document.getElementById('customTip').value) / 100;\n            } else {\n                tipPercent = parseFloat(tipPercent);\n            }\n            \n            if (isNaN(bill) || bill <= 0 || isNaN(tipPercent) || tipPercent < 0) {\n                document.getElementById('result').innerText = 'Please enter valid values';\n                return;\n            }\n            \n            let tipAmount = bill * tipPercent;\n            let totalAmount = bill + tipAmount;\n            \n            document.getElementById('result').innerText = `Tip: $${tipAmount.toFixed(2)} \\nTotal: $${totalAmount.toFixed(2)}`;\n        }\n    </script>\n</body>\n</html>","created_at":"2025-02-04T18:08:42.160Z","url":"https://quickhtml.app/tips"},{"id":14,"app_id":11,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Rolling Ball</title>\n    <style>\n        body {\n            margin: 0;\n            overflow: hidden;\n            background: #222;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            height: 100vh;\n        }\n        canvas {\n            display: block;\n        }\n    </style>\n</head>\n<body>\n    <canvas id=\"gameCanvas\"></canvas>\n    <script>\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = window.innerWidth;\n        canvas.height = window.innerHeight;\n        \n        const ball = {\n            x: canvas.width / 2,\n            y: canvas.height / 2,\n            radius: 30,\n            vx: 0,\n            vy: 0,\n            friction: 0.98,\n            textureAngle: 0,\n        };\n\n        window.addEventListener(\"deviceorientation\", (event) => {\n            const { beta, gamma } = event;\n            ball.vx += (gamma || 0) * 0.1;\n            ball.vy += (beta || 0) * 0.1;\n        });\n        \n        function update() {\n            ball.vx *= ball.friction;\n            ball.vy *= ball.friction;\n            ball.x += ball.vx;\n            ball.y += ball.vy;\n            ball.textureAngle += Math.hypot(ball.vx, ball.vy) * 0.05;\n            \n            if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {\n                ball.vx *= -0.8;\n                ball.x = Math.max(ball.radius, Math.min(canvas.width - ball.radius, ball.x));\n            }\n            if (ball.y - ball.radius < 0 || ball.y + ball.radius > canvas.height) {\n                ball.vy *= -0.8;\n                ball.y = Math.max(ball.radius, Math.min(canvas.height - ball.radius, ball.y));\n            }\n        }\n        \n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            ctx.save();\n            ctx.translate(ball.x, ball.y);\n            ctx.rotate(ball.textureAngle);\n            ctx.fillStyle = \"#f00\";\n            ctx.beginPath();\n            ctx.arc(0, 0, ball.radius, 0, Math.PI * 2);\n            ctx.fill();\n            ctx.fillStyle = \"#fff\";\n            ctx.beginPath();\n            ctx.arc(-10, 0, 5, 0, Math.PI * 2);\n            ctx.fill();\n            ctx.restore();\n        }\n        \n        function loop() {\n            update();\n            draw();\n            requestAnimationFrame(loop);\n        }\n        \n        loop();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T18:11:38.440Z","url":"https://quickhtml.app/rolling-ball"},{"id":15,"app_id":12,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Test Page</title>\n    <style>\n        body {\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            height: 100vh;\n            background-color: #f4f4f4;\n            font-family: Arial, sans-serif;\n        }\n        .message {\n            font-size: 24px;\n            font-weight: bold;\n            color: #333;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"message\">Everything is working!</div>\n</body>\n</html>","created_at":"2025-02-04T18:12:45.211Z","url":"https://quickhtml.app/test-page"},{"id":141,"app_id":13,"version":2,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Test App</title>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; padding: 20px; }\n        .toast { position: fixed; top: 10px; left: 50%; transform: translateX(-50%); background: red; color: white; padding: 10px; border-radius: 5px; display: none; }\n    </style>\n</head>\n<body>\n    <div id=\"errorToast\" class=\"toast\"></div>\n    <h1>Welcome to the Test App</h1>\n    <p>This is a simple test application.</p>\n    <script>\n        window.onerror = function(message, source, lineno, colno, error) {\n            var toast = document.getElementById('errorToast');\n            toast.innerText = `Error: ${message} at ${source}:${lineno}:${colno}`;\n            toast.style.display = 'block';\n            setTimeout(() => toast.style.display = 'none', 5000);\n        };\n    </script>\n</body>\n</html>","created_at":"2025-02-10T03:48:21.477Z","url":"https://quickhtml.app/test-app"},{"id":17,"app_id":14,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Test Lorem Ipsum</title>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; padding: 20px; }\n    </style>\n</head>\n<body>\n    <h1>Lorem Ipsum Test</h1>\n    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam vehicula magna at ex consequat, nec fringilla nisl aliquet.</p>\n</body>\n</html>","created_at":"2025-02-04T18:16:45.083Z","url":"https://quickhtml.app/test-lorem"},{"id":18,"app_id":15,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Another Lorem Ipsum Test</title>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; padding: 20px; }\n    </style>\n</head>\n<body>\n    <h1>Another Lorem Ipsum Test</h1>\n    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vitae justo id eros eleifend mollis eget at turpis.</p>\n</body>\n</html>","created_at":"2025-02-04T18:27:54.065Z","url":"https://quickhtml.app/lorem-test-2"},{"id":41,"app_id":16,"version":14,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Face & Emotion Detection</title>\n    <script defer src=\"https://cdn.jsdelivr.net/npm/@tensorflow/tfjs\"></script>\n    <script defer src=\"https://cdn.jsdelivr.net/npm/face-api.js\"></script>\n    <style>\n        body { text-align: center; font-family: Arial, sans-serif; position: relative; }\n        .container { position: relative; display: inline-block; }\n        video { width: 100%; max-width: 640px; display: block; }\n        canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }\n        #emotion { font-size: 20px; margin-top: 10px; }\n    </style>\n</head>\n<body>\n    <h2>Face & Emotion Detection</h2>\n    <div class=\"container\">\n        <video id=\"video\" autoplay playsinline></video>\n        <canvas id=\"overlay\"></canvas>\n    </div>\n    <p id=\"emotion\">Detecting...</p>\n    <script>\n        async function setupCamera() {\n            console.log(\"Setting up camera...\");\n            const video = document.getElementById('video');\n            const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 1280, height: 720 } });\n            video.srcObject = stream;\n            return new Promise(resolve => { video.onloadedmetadata = resolve; });\n        }\n\n        async function loadModels() {\n            console.log(\"Loading FaceAPI models...\");\n            await faceapi.nets.tinyFaceDetector.loadFromUri('https://cdn.jsdelivr.net/npm/face-api.js/models');\n            await faceapi.nets.faceExpressionNet.loadFromUri('https://cdn.jsdelivr.net/npm/face-api.js/models');\n            console.log(\"Models loaded successfully.\");\n        }\n\n        async function detectFaces() {\n            await setupCamera();\n            await loadModels();\n            const video = document.getElementById('video');\n            const canvas = document.getElementById('overlay');\n            const ctx = canvas.getContext('2d');\n            function resizeCanvas() {\n                canvas.width = video.videoWidth;\n                canvas.height = video.videoHeight;\n            }\n            video.addEventListener('loadedmetadata', resizeCanvas);\n            window.addEventListener('resize', resizeCanvas);\n            resizeCanvas();\n            \n            async function analyzeFrame() {\n                const detections = await faceapi.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions()).withFaceExpressions();\n                ctx.clearRect(0, 0, canvas.width, canvas.height);\n                \n                if (detections.length > 0) {\n                    faceapi.draw.drawDetections(canvas, detections);\n                    faceapi.draw.drawFaceExpressions(canvas, detections);\n                    \n                    const emotions = detections[0].expressions;\n                    const dominantEmotion = Object.entries(emotions).reduce((a, b) => a[1] > b[1] ? a : b);\n                    document.getElementById('emotion').innerText = `Emotion: ${dominantEmotion[0]}`;\n                } else {\n                    document.getElementById('emotion').innerText = 'No face detected';\n                }\n                requestAnimationFrame(analyzeFrame);\n            }\n            analyzeFrame();\n        }\n        detectFaces();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T19:15:24.531Z","url":"https://quickhtml.app/face-detect"},{"id":22,"app_id":17,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Emotion Detection App</title>\n    <script defer src=\"https://cdn.jsdelivr.net/npm/@tensorflow/tfjs\"></script>\n    <script defer src=\"https://cdn.jsdelivr.net/npm/@tensorflow-models/blazeface\"></script>\n    <script defer src=\"https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh\"></script>\n    <script defer src=\"https://cdn.jsdelivr.net/npm/face-api.js\"></script>\n    <style>\n        body { text-align: center; font-family: Arial, sans-serif; }\n        video, canvas { display: block; margin: auto; }\n        #emotion { margin-top: 20px; font-size: 20px; font-weight: bold; }\n    </style>\n</head>\n<body>\n    <h1>Emotion Detection App</h1>\n    <video id=\"video\" width=\"640\" height=\"480\" autoplay></video>\n    <canvas id=\"canvas\" width=\"640\" height=\"480\"></canvas>\n    <div id=\"emotion\">Detecting emotion...</div>\n    \n    <script>\n        async function setupCamera() {\n            const video = document.getElementById('video');\n            const stream = await navigator.mediaDevices.getUserMedia({ video: true });\n            video.srcObject = stream;\n        }\n        \n        async function detectEmotion() {\n            await faceapi.nets.tinyFaceDetector.loadFromUri('https://justadudewhohacks.github.io/face-api.js/models');\n            await faceapi.nets.faceExpressionNet.loadFromUri('https://justadudewhohacks.github.io/face-api.js/models');\n            \n            const video = document.getElementById('video');\n            const canvas = document.getElementById('canvas');\n            const ctx = canvas.getContext('2d');\n            \n            video.addEventListener('play', async () => {\n                const displaySize = { width: video.width, height: video.height };\n                faceapi.matchDimensions(canvas, displaySize);\n                \n                setInterval(async () => {\n                    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n                    \n                    const detections = await faceapi.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions())\n                        .withFaceExpressions();\n                    \n                    if (detections.length > 0) {\n                        let bestEmotion = \"Neutral\";\n                        let bestScore = 0;\n                        \n                        for (const [emotion, score] of Object.entries(detections[0].expressions)) {\n                            if (score > bestScore) {\n                                bestEmotion = emotion;\n                                bestScore = score;\n                            }\n                        }\n                        \n                        document.getElementById('emotion').innerText = `Emotion: ${bestEmotion}`;\n                    }\n                }, 500);\n            });\n        }\n        \n        async function applyEdgeDetection() {\n            const canvas = document.getElementById('canvas');\n            const ctx = canvas.getContext('2d');\n            \n            setInterval(() => {\n                const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n                const data = imageData.data;\n                \n                for (let i = 0; i < data.length; i += 4) {\n                    const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;\n                    data[i] = data[i + 1] = data[i + 2] = avg > 128 ? 255 : 0;\n                }\n                \n                ctx.putImageData(imageData, 0, 0);\n            }, 500);\n        }\n        \n        setupCamera().then(() => {\n            detectEmotion();\n            applyEdgeDetection();\n        });\n    </script>\n</body>\n</html>","created_at":"2025-02-04T18:50:05.976Z","url":"https://quickhtml.app/emotion-detection-app"},{"id":36,"app_id":18,"version":7,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Bouncing Ball</title>\n    <style>\n        body {\n            margin: 0;\n            background-color: green;\n            overflow: hidden;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            height: 100vh;\n            width: 100vw;\n        }\n        .ball {\n            position: absolute;\n            width: 50px;\n            height: 50px;\n            background-color: red;\n            border-radius: 50%;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"ball\" id=\"ball\"></div>\n    <script>\n        const ball = document.getElementById('ball');\n        let x = Math.random() * window.innerWidth;\n        let y = Math.random() * window.innerHeight;\n        let dx = 3;\n        let dy = 3;\n        let size = 50;\n        \n        function animate() {\n            x += dx;\n            y += dy;\n            \n            if (x + size >= window.innerWidth || x <= 0) {\n                dx *= -1;\n            }\n            if (y + size >= window.innerHeight || y <= 0) {\n                dy *= -1;\n            }\n            \n            ball.style.left = x + 'px';\n            ball.style.top = y + 'px';\n            requestAnimationFrame(animate);\n        }\n        \n        ball.addEventListener('click', () => {\n            size += 10;\n            ball.style.width = size + 'px';\n            ball.style.height = size + 'px';\n        });\n        \n        ball.style.position = 'absolute';\n        animate();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T19:09:56.429Z","url":"https://quickhtml.app/hello-world-test"},{"id":50,"app_id":19,"version":7,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n    <title>Falling Sand Game</title>\n    <style>\n        * { margin: 0; padding: 0; box-sizing: border-box; }\n        body { display: flex; flex-direction: column; align-items: center; justify-content: center; background: #222; height: 100vh; overflow: hidden; }\n        #game-container { position: relative; width: 90vw; height: 80vh; border: 2px solid white; display: flex; justify-content: center; align-items: center; }\n        canvas { width: 100%; height: 100%; display: block; }\n        .controls { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; justify-content: center; }\n        button { padding: 10px; font-size: 14px; cursor: pointer; border: none; border-radius: 5px; background: white; }\n        .selected { background: orange; }\n        #error-log { position: fixed; top: 10px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.8); color: white; padding: 10px; font-size: 12px; border-radius: 5px; z-index: 9999; display: none; }\n        #close-error { margin-left: 10px; cursor: pointer; color: red; }\n    </style>\n</head>\n<body>\n    <div id=\"error-log\"><span id=\"error-message\"></span><span id=\"close-error\"> ✖</span></div>\n    <div id=\"game-container\">\n        <canvas id=\"canvas\"></canvas>\n    </div>\n    <div class=\"controls\" id=\"controls\"></div>\n    <script>\n        (function() {\n            const logDiv = document.getElementById(\"error-log\");\n            const logMsg = document.getElementById(\"error-message\");\n            const closeError = document.getElementById(\"close-error\");\n            closeError.onclick = () => logDiv.style.display = \"none\";\n            window.onerror = function(message, source, lineno) {\n                logMsg.innerHTML = message + \" (Line \" + lineno + \")\";\n                logDiv.style.display = \"block\";\n                return false;\n            };\n        })();\n    </script>\n    <script>\n        const canvas = document.getElementById(\"canvas\");\n        const ctx = canvas.getContext(\"2d\");\n        let cellSize = 5;\n        let gridSizeX, gridSizeY, grid;\n        let currentElement = 'sand';\n        const elements = ['sand', 'water', 'fire', 'wood', 'oil', 'lava', 'steam', 'metal', 'acid', 'ice', 'gas'];\n\n        function resizeCanvas() {\n            canvas.width = document.getElementById(\"game-container\").clientWidth;\n            canvas.height = document.getElementById(\"game-container\").clientHeight;\n            gridSizeX = Math.floor(canvas.width / cellSize);\n            gridSizeY = Math.floor(canvas.height / cellSize);\n            grid = Array.from({ length: gridSizeY }, () => Array(gridSizeX).fill(null));\n        }\n\n        resizeCanvas();\n        window.addEventListener(\"resize\", resizeCanvas);\n\n        function setElement(type) {\n            currentElement = type;\n            document.querySelectorAll(\".controls button\").forEach(btn => btn.classList.remove(\"selected\"));\n            document.getElementById(type).classList.add(\"selected\");\n        }\n\n        function clearGrid() { grid = Array.from({ length: gridSizeY }, () => Array(gridSizeX).fill(null)); }\n\n        function placeParticle(x, y) {\n            const gridX = Math.floor(x / cellSize);\n            const gridY = Math.floor(y / cellSize);\n            if (gridY < gridSizeY && gridX < gridSizeX) grid[gridY][gridX] = { type: currentElement, timer: 0 };\n        }\n\n        canvas.addEventListener(\"mousemove\", (e) => { if (e.buttons === 1) placeParticle(e.offsetX, e.offsetY); });\n        canvas.addEventListener(\"touchmove\", (e) => {\n            e.preventDefault();\n            for (let touch of e.touches) placeParticle(touch.clientX - canvas.offsetLeft, touch.clientY - canvas.offsetTop);\n        }, { passive: false });\n\n        function update() {\n            for (let y = gridSizeY - 2; y >= 0; y--) {\n                for (let x = 0; x < gridSizeX; x++) {\n                    let cell = grid[y][x];\n                    if (!cell) continue;\n                    \n                    if (cell.type === 'fire') {\n                        cell.timer++;\n                        if (cell.timer > 30) grid[y][x] = { type: 'smoke', timer: 0 };\n                        if (grid[y + 1]?.[x]?.type === 'wood' || grid[y + 1]?.[x]?.type === 'oil') grid[y + 1][x] = { type: 'fire', timer: 0 };\n                    }\n                    else if (cell.type === 'smoke') {\n                        if (y > 0 && grid[y - 1][x] === null) {\n                            grid[y - 1][x] = cell;\n                            grid[y][x] = null;\n                        }\n                    }\n                }\n            }\n        }\n\n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            for (let y = 0; y < gridSizeY; y++) {\n                for (let x = 0; x < gridSizeX; x++) {\n                    let cell = grid[y][x];\n                    if (!cell) continue;\n                    let colors = { sand: 'yellow', water: 'blue', fire: 'red', wood: 'brown', oil: 'darkorange', lava: 'orangered', steam: 'lightgray', metal: 'gray', acid: 'green', ice: 'cyan', gas: 'purple' };\n                    ctx.fillStyle = colors[cell.type] || 'white';\n                    ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);\n                }\n            }\n        }\n\n        function loop() {\n            update();\n            draw();\n            requestAnimationFrame(loop);\n        }\n\n        loop();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T19:31:47.934Z","url":"https://quickhtml.app/falling-sand-game"},{"id":45,"app_id":20,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Test HTML Page</title>\n  <style>\n    body {\n      font-family: Arial, sans-serif;\n      background-color: #f0f0f0;\n      margin: 0;\n      padding: 20px;\n    }\n    header, footer {\n      background-color: #333;\n      color: #fff;\n      padding: 10px;\n      text-align: center;\n    }\n    main {\n      background-color: #fff;\n      padding: 20px;\n      margin-top: 20px;\n    }\n  </style>\n</head>\n<body>\n  <header>\n    <h1>Welcome to My Test HTML Page</h1>\n  </header>\n  <main>\n    <p>This is a simple test page to demonstrate the basic structure of an HTML document.</p>\n    <p>You can add more elements and content as needed for your testing purposes.</p>\n  </main>\n  <footer>\n    <p>&copy; 2025 Your Name or Company</p>\n  </footer>\n</body>\n</html>","created_at":"2025-02-04T19:21:13.048Z","url":"https://quickhtml.app/yup"},{"id":76,"app_id":21,"version":7,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n    <title>Falling Sand Game v2 - Fire Update</title>\n    <style>\n        * { margin: 0; padding: 0; box-sizing: border-box; }\n        body { display: flex; flex-direction: column; align-items: center; justify-content: center; background: #222; height: 100vh; overflow: hidden; }\n        #error-log { position: fixed; top: 10px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.8); color: white; padding: 10px; font-size: 12px; border-radius: 5px; z-index: 9999; display: none; }\n        #close-error { margin-left: 10px; cursor: pointer; color: red; }\n        #game-container { position: relative; width: 90vw; height: 80vh; border: 2px solid white; display: flex; justify-content: center; align-items: center; }\n        canvas { width: 100%; height: 100%; display: block; }\n        .controls { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; justify-content: center; }\n        button { padding: 10px; font-size: 14px; cursor: pointer; border: none; border-radius: 5px; background: white; }\n        .selected { background: orange; }\n    </style>\n</head>\n<body>\n    <div id=\"error-log\"><span id=\"error-message\"></span><span id=\"close-error\"> ✖</span></div>\n    <div id=\"game-container\">\n        <canvas id=\"canvas\"></canvas>\n    </div>\n    <div class=\"controls\" id=\"controls\"></div>\n    <script>\n        (function() {\n            const logDiv = document.getElementById(\"error-log\");\n            const logMsg = document.getElementById(\"error-message\");\n            const closeError = document.getElementById(\"close-error\");\n            closeError.onclick = () => logDiv.style.display = \"none\";\n            window.onerror = function(message, source, lineno) {\n                logMsg.innerHTML = message + \" (Line \" + lineno + \")\";\n                logDiv.style.display = \"block\";\n                return false;\n            };\n        })();\n    </script>\n    <script>\n        const canvas = document.getElementById(\"canvas\");\n        const ctx = canvas.getContext(\"2d\");\n        let cellSize = 5;\n        let gridSizeX, gridSizeY, grid;\n        let currentElement = 'sand';\n        const elements = ['sand', 'water', 'fire', 'wood', 'oil', 'lava', 'steam', 'metal', 'acid', 'ice', 'gas'];\n\n        function resizeCanvas() {\n            canvas.width = document.getElementById(\"game-container\").clientWidth;\n            canvas.height = document.getElementById(\"game-container\").clientHeight;\n            gridSizeX = Math.floor(canvas.width / cellSize);\n            gridSizeY = Math.floor(canvas.height / cellSize);\n            grid = Array.from({ length: gridSizeY }, () => Array(gridSizeX).fill(null));\n        }\n\n        resizeCanvas();\n        window.addEventListener(\"resize\", resizeCanvas);\n\n        function setElement(type) {\n            currentElement = type;\n            document.querySelectorAll(\".controls button\").forEach(btn => btn.classList.remove(\"selected\"));\n            document.getElementById(type).classList.add(\"selected\");\n        }\n\n        function createControls() {\n            const controlsDiv = document.getElementById(\"controls\");\n            controlsDiv.innerHTML = '';\n            elements.forEach(el => {\n                let btn = document.createElement(\"button\");\n                btn.id = el;\n                btn.innerText = el.charAt(0).toUpperCase() + el.slice(1);\n                btn.onclick = () => setElement(el);\n                controlsDiv.appendChild(btn);\n            });\n            setElement('sand');\n        }\n\n        createControls();\n\n        function clearGrid() { grid = Array.from({ length: gridSizeY }, () => Array(gridSizeX).fill(null)); }\n\n        function placeParticle(x, y) {\n            const gridX = Math.floor(x / cellSize);\n            const gridY = Math.floor(y / cellSize);\n            if (gridY < gridSizeY && gridX < gridSizeX) grid[gridY][gridX] = { type: currentElement, timer: 0 };\n        }\n\n        canvas.addEventListener(\"mousemove\", (e) => { if (e.buttons === 1) placeParticle(e.offsetX, e.offsetY); });\n        canvas.addEventListener(\"touchmove\", (e) => {\n            e.preventDefault();\n            for (let touch of e.touches) placeParticle(touch.clientX - canvas.offsetLeft, touch.clientY - canvas.offsetTop);\n        }, { passive: false });\n\n        function update() {\n            for (let y = gridSizeY - 2; y >= 0; y--) {\n                for (let x = 0; x < gridSizeX; x++) {\n                    let cell = grid[y][x];\n                    if (!cell) continue;\n                    \n                    let below = grid[y + 1]?.[x];\n                    let left = grid[y + 1]?.[x - 1];\n                    let right = grid[y + 1]?.[x + 1];\n                    \n                    if (cell.type === 'fire') {\n                        cell.timer++;\n                        if (cell.timer > 30) grid[y][x] = null; \n                        if (below?.type === 'wood' || below?.type === 'oil') grid[y + 1][x] = { type: 'fire', timer: 0 };\n                        if (left?.type === 'wood' || left?.type === 'oil') grid[y + 1][x - 1] = { type: 'fire', timer: 0 };\n                        if (right?.type === 'wood' || right?.type === 'oil') grid[y + 1][x + 1] = { type: 'fire', timer: 0 };\n                    }\n                    \n                    if (cell.type === 'water' && below?.type === 'fire') {\n                        grid[y + 1][x] = null;\n                    }\n                }\n            }\n        }\n\n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            for (let y = 0; y < gridSizeY; y++) {\n                for (let x = 0; x < gridSizeX; x++) {\n                    let cell = grid[y][x];\n                    if (!cell) continue;\n                    let colors = { sand: 'yellow', water: 'blue', fire: 'red', wood: 'brown', oil: 'darkorange', lava: 'orangered', steam: 'lightgray', metal: 'gray', acid: 'green', ice: 'cyan', gas: 'purple' };\n                    ctx.fillStyle = colors[cell.type] || 'white';\n                    ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);\n                }\n            }\n        }\n\n        function loop() {\n            update();\n            draw();\n            requestAnimationFrame(loop);\n        }\n\n        loop();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T21:30:01.797Z","url":"https://quickhtml.app/falling-sand-v2"},{"id":54,"app_id":22,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Test Error App</title>\n</head>\n<body>\n    <h1>Test Error App</h1>\n    <p>This app will throw an error on load for logging purposes.</p>\n\n    <script>\n        window.onload = function() {\n            throw new Error(\"Test error: This is a deliberate error for logging.\");\n        };\n    </script>\n</body>\n</html>","created_at":"2025-02-04T19:36:06.870Z","url":"https://quickhtml.app/test-error-app"},{"id":55,"app_id":23,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Error Test App</title>\n    <style>\n        body { font-family: Arial, sans-serif; padding: 20px; text-align: center; }\n        .error-log { background: #ffdddd; color: #900; padding: 10px; margin-top: 20px; border: 1px solid #900; display: none; }\n    </style>\n</head>\n<body>\n    <h1>Error Test App</h1>\n    <p>This app intentionally throws an error for logging purposes.</p>\n    <div class=\"error-log\" id=\"error-log\"></div>\n    <script>\n        (function() {\n            window.onerror = function(message, source, lineno, colno, error) {\n                let errorLog = document.getElementById('error-log');\n                errorLog.innerHTML = `Error: ${message} <br> Source: ${source} <br> Line: ${lineno}, Column: ${colno}`;\n                errorLog.style.display = 'block';\n            };\n            \n            // Intentionally throwing an error\n            throw new Error(\"Test error for logging\");\n        })();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T19:37:38.256Z","url":"https://quickhtml.app/error-test-app"},{"id":65,"app_id":24,"version":6,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Ball Roll Game</title>\n    <style>\n        body {\n            margin: 0;\n            overflow: hidden;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            height: 100vh;\n            background-color: #222;\n            color: white;\n            font-family: Arial, sans-serif;\n        }\n        #gameCanvas {\n            background: #111;\n            border: 2px solid white;\n        }\n        .toast {\n            position: fixed;\n            top: 10px;\n            left: 50%;\n            transform: translateX(-50%);\n            background: red;\n            color: white;\n            padding: 10px;\n            border-radius: 5px;\n            display: none;\n        }\n    </style>\n</head>\n<body>\n    <canvas id=\"gameCanvas\"></canvas>\n    <div id=\"errorToast\" class=\"toast\"></div>\n    <script>\n        window.onerror = function(message) {\n            let errorToast = document.getElementById('errorToast');\n            errorToast.innerText = message;\n            errorToast.style.display = 'block';\n            setTimeout(() => errorToast.style.display = 'none', 5000);\n        };\n\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = window.innerWidth * 0.9;\n        canvas.height = window.innerHeight * 0.9;\n\n        let ball = { x: canvas.width / 2, y: canvas.height / 2, radius: 15, speedX: 0, speedY: 0, friction: 0.98 };\n        let goal = { x: Math.random() * (canvas.width - 50), y: Math.random() * (canvas.height - 50), size: 30 };\n        let obstacles = Array.from({ length: Math.floor(Math.random() * 4) + 3 }, () => ({\n            x: Math.random() * canvas.width,\n            y: Math.random() * canvas.height,\n            width: Math.random() * 50 + 30,\n            height: Math.random() * 50 + 30,\n            speedX: (Math.random() - 0.5) * 4,\n            speedY: (Math.random() - 0.5) * 4\n        }));\n\n        window.addEventListener(\"deviceorientation\", (event) => {\n            ball.speedX += event.gamma / 10;\n            ball.speedY += event.beta / 10;\n        });\n\n        function update() {\n            ball.speedX *= ball.friction;\n            ball.speedY *= ball.friction;\n            ball.x += ball.speedX;\n            ball.y += ball.speedY;\n            if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) ball.speedX *= -0.7;\n            if (ball.y - ball.radius < 0 || ball.y + ball.radius > canvas.height) ball.speedY *= -0.7;\n            obstacles.forEach(obstacle => {\n                obstacle.x += obstacle.speedX;\n                obstacle.y += obstacle.speedY;\n                if (obstacle.x < 0 || obstacle.x + obstacle.width > canvas.width) obstacle.speedX *= -1;\n                if (obstacle.y < 0 || obstacle.y + obstacle.height > canvas.height) obstacle.speedY *= -1;\n                if (ball.x + ball.radius > obstacle.x && ball.x - ball.radius < obstacle.x + obstacle.width &&\n                    ball.y + ball.radius > obstacle.y && ball.y - ball.radius < obstacle.y + obstacle.height) {\n                    ball.x = canvas.width / 2;\n                    ball.y = canvas.height / 2;\n                    ball.speedX = 0;\n                    ball.speedY = 0;\n                }\n            });\n            if (ball.x > goal.x && ball.x < goal.x + goal.size && ball.y > goal.y && ball.y < goal.y + goal.size) {\n                goal.x = Math.random() * (canvas.width - 50);\n                goal.y = Math.random() * (canvas.height - 50);\n            }\n        }\n\n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            ctx.fillStyle = \"white\";\n            ctx.beginPath();\n            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);\n            ctx.fill();\n            ctx.fillStyle = \"green\";\n            ctx.fillRect(goal.x, goal.y, goal.size, goal.size);\n            ctx.fillStyle = \"red\";\n            obstacles.forEach(obstacle => ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height));\n        }\n\n        function gameLoop() {\n            update();\n            draw();\n            requestAnimationFrame(gameLoop);\n        }\n\n        gameLoop();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T19:57:06.083Z","url":"https://quickhtml.app/accelerometer-ball-game"},{"id":69,"app_id":25,"version":5,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Regina is Cool and Nice</title>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            background-color: #f4f4f4;\n            margin: 0;\n            overflow: hidden;\n            height: 100vh;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n        }\n        .container {\n            position: absolute;\n            background: white;\n            padding: 20px;\n            border-radius: 20px;\n            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n            text-align: center;\n            width: 90%;\n            max-width: 400px;\n        }\n        h2 {\n            font-size: 2.5em;\n        }\n        input {\n            margin: 10px 0;\n            padding: 10px;\n            font-size: 1em;\n            border: 1px solid #ccc;\n            border-radius: 5px;\n            text-align: center;\n            width: auto;\n            min-width: 50px;\n        }\n        button {\n            margin: 10px 0;\n            padding: 10px;\n            width: 100%;\n            font-size: 1em;\n            background: linear-gradient(to right, #ff69b4, #dda0dd);\n            color: white;\n            border: none;\n            cursor: pointer;\n            border-radius: 10px;\n        }\n        button:hover {\n            opacity: 0.9;\n        }\n        #result {\n            margin-top: 15px;\n            font-size: 1.2em;\n            font-weight: bold;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"container\" id=\"box\">\n        <h2>Regina is Cool and Nice</h2>\n        <label for=\"bill\">Awesomeness Amount ($):</label>\n        <input type=\"number\" id=\"bill\" placeholder=\"Enter awesomeness amount\">\n        \n        <label for=\"tip\">Stinky Amount (%):</label>\n        <input type=\"number\" id=\"tip\" placeholder=\"Enter stinky amount\">\n        \n        <button onclick=\"calculateAwesomeness()\">Calculate</button>\n        \n        <div id=\"result\"></div>\n    </div>\n    \n    <script>\n        function calculateAwesomeness() {\n            let awesomeness = parseFloat(document.getElementById('bill').value);\n            let stinky = parseFloat(document.getElementById('tip').value);\n            \n            if (isNaN(awesomeness) || isNaN(stinky)) {\n                document.getElementById('result').innerText = \"Please enter valid numbers.\";\n                return;\n            }\n            \n            let resultValue = (awesomeness * stinky) / (stinky + 1);\n            \n            document.getElementById('result').innerText = `Result: ${resultValue.toFixed(2)}`;\n        }\n\n        // Circular animation logic\n        let box = document.getElementById('box');\n        let angle = 0;\n        let radius = 100;\n        let centerX = window.innerWidth / 2;\n        let centerY = window.innerHeight / 2;\n        \n        function animate() {\n            angle += 0.02;\n            let x = centerX + radius * Math.cos(angle) - (box.clientWidth / 2);\n            let y = centerY + radius * Math.sin(angle) - (box.clientHeight / 2);\n            \n            box.style.left = x + 'px';\n            box.style.top = y + 'px';\n            \n            requestAnimationFrame(animate);\n        }\n        \n        animate();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T20:03:19.146Z","url":"https://quickhtml.app/tip-calculator"},{"id":87,"app_id":26,"version":5,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n    <title>Fullscreen Drawing App</title>\n    <style>\n        * { margin: 0; padding: 0; box-sizing: border-box; }\n        html, body { width: 100%; height: 100%; overflow: hidden; background: #222; touch-action: none; }\n        canvas { display: block; width: 100%; height: 100%; }\n        .controls {\n            position: fixed; bottom: 0; left: 0; width: 100%;\n            background: rgba(255, 255, 255, 0.95); padding: 8px;\n            display: flex; justify-content: space-around; align-items: center;\n        }\n        button, input {\n            font-size: 16px; padding: 8px; cursor: pointer; border-radius: 5px;\n        }\n        button.active { background: #007BFF; color: white; }\n        #brushPreview {\n            position: absolute; width: 20px; height: 20px; border-radius: 50%;\n            background: black; pointer-events: none; display: none;\n        }\n    </style>\n</head>\n<body>\n    <canvas id=\"canvas\"></canvas>\n    <div class=\"controls\">\n        <button id=\"fullscreen\">⛶</button>\n        <button id=\"pen\" class=\"active\">✎</button>\n        <button id=\"eraser\">⌫</button>\n        <input type=\"color\" id=\"colorPicker\" value=\"#000000\">\n        <input type=\"range\" id=\"brushSize\" min=\"1\" max=\"50\" value=\"5\">\n        <input type=\"color\" id=\"bgColor\" value=\"#222\">\n        <button id=\"undo\">↶</button>\n        <button id=\"redo\">↷</button>\n        <button id=\"clear\">🗑</button>\n        <button id=\"save\">💾</button>\n    </div>\n    <div id=\"brushPreview\"></div>\n    <script>\n        const canvas = document.getElementById(\"canvas\");\n        const ctx = canvas.getContext(\"2d\");\n        const colorPicker = document.getElementById(\"colorPicker\");\n        const brushSize = document.getElementById(\"brushSize\");\n        const bgColor = document.getElementById(\"bgColor\");\n        const eraser = document.getElementById(\"eraser\");\n        const pen = document.getElementById(\"pen\");\n        const undoBtn = document.getElementById(\"undo\");\n        const redoBtn = document.getElementById(\"redo\");\n        const clear = document.getElementById(\"clear\");\n        const save = document.getElementById(\"save\");\n        const fullscreen = document.getElementById(\"fullscreen\");\n        const brushPreview = document.getElementById(\"brushPreview\");\n        \n        let drawing = false;\n        let brushColor = colorPicker.value;\n        let brushWidth = brushSize.value;\n        let isEraser = false;\n        let history = [], redoStack = [];\n\n        function resizeCanvas() {\n            canvas.width = window.innerWidth;\n            canvas.height = window.innerHeight;\n            ctx.fillStyle = bgColor.value;\n            ctx.fillRect(0, 0, canvas.width, canvas.height);\n            saveState();\n        }\n        window.addEventListener(\"resize\", resizeCanvas);\n        resizeCanvas();\n        \n        function saveState() {\n            history.push(ctx.getImageData(0, 0, canvas.width, canvas.height));\n            if (history.length > 50) history.shift();\n            redoStack = [];\n        }\n        \n        function undo() {\n            if (history.length > 1) {\n                redoStack.push(history.pop());\n                ctx.putImageData(history[history.length - 1], 0, 0);\n            }\n        }\n        \n        function redo() {\n            if (redoStack.length > 0) {\n                history.push(redoStack.pop());\n                ctx.putImageData(history[history.length - 1], 0, 0);\n            }\n        }\n        \n        function startDraw(e) {\n            drawing = true;\n            ctx.beginPath();\n            ctx.moveTo(e.clientX || e.touches[0].clientX, e.clientY || e.touches[0].clientY);\n            saveState();\n            brushPreview.style.display = \"block\";\n        }\n        \n        function draw(e) {\n            if (!drawing) return;\n            const x = e.clientX || e.touches[0].clientX;\n            const y = e.clientY || e.touches[0].clientY;\n            ctx.lineTo(x, y);\n            ctx.strokeStyle = isEraser ? bgColor.value : brushColor;\n            ctx.lineWidth = brushWidth;\n            ctx.lineCap = \"round\";\n            ctx.stroke();\n            brushPreview.style.left = `${x - brushWidth / 2}px`;\n            brushPreview.style.top = `${y - brushWidth / 2}px`;\n            brushPreview.style.width = `${brushWidth}px`;\n            brushPreview.style.height = `${brushWidth}px`;\n            brushPreview.style.backgroundColor = isEraser ? bgColor.value : brushColor;\n        }\n        \n        function stopDraw() { drawing = false; ctx.closePath(); brushPreview.style.display = \"none\"; }\n        \n        canvas.addEventListener(\"mousedown\", startDraw);\n        canvas.addEventListener(\"mousemove\", draw);\n        canvas.addEventListener(\"mouseup\", stopDraw);\n        canvas.addEventListener(\"touchstart\", startDraw);\n        canvas.addEventListener(\"touchmove\", draw);\n        canvas.addEventListener(\"touchend\", stopDraw);\n        \n        colorPicker.addEventListener(\"input\", () => brushColor = colorPicker.value);\n        brushSize.addEventListener(\"input\", () => brushWidth = brushSize.value);\n        bgColor.addEventListener(\"input\", () => {\n            ctx.fillStyle = bgColor.value;\n            ctx.fillRect(0, 0, canvas.width, canvas.height);\n            saveState();\n        });\n        eraser.addEventListener(\"click\", () => { isEraser = true; toggleActive(eraser); });\n        pen.addEventListener(\"click\", () => { isEraser = false; toggleActive(pen); });\n        undoBtn.addEventListener(\"click\", undo);\n        redoBtn.addEventListener(\"click\", redo);\n        clear.addEventListener(\"click\", () => { ctx.fillRect(0, 0, canvas.width, canvas.height); saveState(); });\n        save.addEventListener(\"click\", () => {\n            const link = document.createElement(\"a\");\n            link.download = \"drawing.png\";\n            link.href = canvas.toDataURL();\n            link.click();\n        });\n        fullscreen.addEventListener(\"click\", () => {\n            if (!document.fullscreenElement) {\n                document.documentElement.requestFullscreen();\n            } else {\n                document.exitFullscreen();\n            }\n        });\n        \n        function toggleActive(button) {\n            document.querySelectorAll(\".controls button\").forEach(btn => btn.classList.remove(\"active\"));\n            button.classList.add(\"active\");\n        }\n    </script>\n</body>\n</html>","created_at":"2025-02-04T23:10:09.415Z","url":"https://quickhtml.app/fullscreen-drawing"},{"id":68,"app_id":27,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Drawing App</title>\n    <style>\n        * { margin: 0; padding: 0; box-sizing: border-box; }\n        html, body { width: 100%; height: 100%; overflow: hidden; background: #eee; }\n        canvas { display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; touch-action: none; }\n        .toolbar { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; background: rgba(0, 0, 0, 0.5); padding: 8px; border-radius: 8px; }\n        .toolbar input, .toolbar button { border: none; padding: 6px; cursor: pointer; }\n        .toolbar input[type='color'] { width: 40px; height: 40px; border-radius: 50%; }\n        .toolbar input[type='range'] { width: 100px; }\n    </style>\n</head>\n<body>\n    <canvas id=\"canvas\"></canvas>\n    <div class=\"toolbar\">\n        <input type=\"color\" id=\"colorPicker\" value=\"#000000\">\n        <input type=\"range\" id=\"brushSize\" min=\"1\" max=\"50\" value=\"5\">\n        <button id=\"eraser\">Eraser</button>\n        <button id=\"clear\">Clear</button>\n    </div>\n    <script>\n        const canvas = document.getElementById('canvas');\n        const ctx = canvas.getContext('2d');\n        const colorPicker = document.getElementById('colorPicker');\n        const brushSize = document.getElementById('brushSize');\n        const eraser = document.getElementById('eraser');\n        const clearBtn = document.getElementById('clear');\n\n        let painting = false;\n        let currentColor = colorPicker.value;\n        let currentSize = brushSize.value;\n        let isEraser = false;\n\n        function resizeCanvas() {\n            canvas.width = window.innerWidth;\n            canvas.height = window.innerHeight;\n        }\n        window.addEventListener('resize', resizeCanvas);\n        resizeCanvas();\n\n        function startPosition(e) {\n            painting = true;\n            draw(e);\n        }\n        function endPosition() {\n            painting = false;\n            ctx.beginPath();\n        }\n        function draw(e) {\n            if (!painting) return;\n            ctx.lineWidth = currentSize;\n            ctx.lineCap = 'round';\n            ctx.strokeStyle = isEraser ? '#eee' : currentColor;\n            ctx.lineTo(e.clientX || e.touches[0].clientX, e.clientY || e.touches[0].clientY);\n            ctx.stroke();\n            ctx.beginPath();\n            ctx.moveTo(e.clientX || e.touches[0].clientX, e.clientY || e.touches[0].clientY);\n        }\n\n        canvas.addEventListener('mousedown', startPosition);\n        canvas.addEventListener('mouseup', endPosition);\n        canvas.addEventListener('mousemove', draw);\n        canvas.addEventListener('touchstart', startPosition);\n        canvas.addEventListener('touchend', endPosition);\n        canvas.addEventListener('touchmove', draw);\n\n        colorPicker.addEventListener('input', () => {\n            currentColor = colorPicker.value;\n            isEraser = false;\n        });\n        brushSize.addEventListener('input', () => {\n            currentSize = brushSize.value;\n        });\n        eraser.addEventListener('click', () => {\n            isEraser = true;\n        });\n        clearBtn.addEventListener('click', () => {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n        });\n    </script>\n</body>\n</html>","created_at":"2025-02-04T20:00:21.386Z","url":"https://quickhtml.app/fullscreen-drawing-app"},{"id":71,"app_id":28,"version":2,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Classic Tilt Breakout</title>\n    <style>\n        body {\n            margin: 0;\n            overflow: hidden;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            height: 100vh;\n            background-color: black;\n            color: white;\n            font-family: Arial, sans-serif;\n        }\n        #gameCanvas {\n            background: black;\n            border: 2px solid white;\n        }\n        .toast {\n            position: fixed;\n            top: 10px;\n            left: 50%;\n            transform: translateX(-50%);\n            background: red;\n            color: white;\n            padding: 10px;\n            border-radius: 5px;\n            display: none;\n        }\n    </style>\n</head>\n<body>\n    <canvas id=\"gameCanvas\"></canvas>\n    <div id=\"errorToast\" class=\"toast\"></div>\n    <script>\n        window.onerror = function(message) {\n            let errorToast = document.getElementById('errorToast');\n            errorToast.innerText = message;\n            errorToast.style.display = 'block';\n            setTimeout(() => errorToast.style.display = 'none', 5000);\n        };\n\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = window.innerWidth * 0.9;\n        canvas.height = window.innerHeight * 0.9;\n\n        let lives = 3;\n        let score = 0;\n        let level = 1;\n        let paddle = { width: 80, height: 10, x: canvas.width / 2 - 40, y: canvas.height - 30, speed: 0 };\n        let ball = { x: canvas.width / 2, y: canvas.height / 2, radius: 8, speedX: 3, speedY: -3 };\n        let rows = 5, cols = 8, brickWidth = canvas.width / cols - 5, brickHeight = 20, offsetY = 50;\n        let bricks = [];\n        \n        function generateBricks() {\n            bricks = [];\n            for (let r = 0; r < rows; r++) {\n                for (let c = 0; c < cols; c++) {\n                    bricks.push({ x: c * (brickWidth + 5), y: offsetY + r * (brickHeight + 5), status: 1 });\n                }\n            }\n        }\n        generateBricks();\n\n        window.addEventListener(\"deviceorientation\", (event) => {\n            paddle.speed = event.gamma / 2;\n        });\n\n        function update() {\n            paddle.x += paddle.speed;\n            if (paddle.x < 0) paddle.x = 0;\n            if (paddle.x + paddle.width > canvas.width) paddle.x = canvas.width - paddle.width;\n            \n            ball.x += ball.speedX;\n            ball.y += ball.speedY;\n\n            if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) ball.speedX *= -1;\n            if (ball.y - ball.radius < 0) ball.speedY *= -1;\n\n            if (ball.y + ball.radius > canvas.height) {\n                lives--;\n                if (lives === 0) {\n                    alert(\"Game Over!\");\n                    document.location.reload();\n                }\n                ball.x = canvas.width / 2;\n                ball.y = canvas.height / 2;\n                ball.speedX = 3;\n                ball.speedY = -3;\n            }\n            \n            if (ball.y + ball.radius > paddle.y && ball.x > paddle.x && ball.x < paddle.x + paddle.width) {\n                let hitPosition = (ball.x - paddle.x) / paddle.width - 0.5;\n                ball.speedX = hitPosition * 6;\n                ball.speedY *= -1;\n            }\n            \n            bricks.forEach(brick => {\n                if (brick.status && ball.x > brick.x && ball.x < brick.x + brickWidth &&\n                    ball.y > brick.y && ball.y < brick.y + brickHeight) {\n                    ball.speedY *= -1;\n                    brick.status = 0;\n                    score += 10;\n                }\n            });\n            \n            if (bricks.every(brick => brick.status === 0)) {\n                level++;\n                rows++;\n                generateBricks();\n                ball.speedX *= 1.1;\n                ball.speedY *= 1.1;\n            }\n        }\n\n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            ctx.fillStyle = \"white\";\n            ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);\n            ctx.beginPath();\n            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);\n            ctx.fill();\n            bricks.forEach(brick => {\n                if (brick.status) {\n                    ctx.fillRect(brick.x, brick.y, brickWidth, brickHeight);\n                }\n            });\n            ctx.fillText(`Score: ${score}  Lives: ${lives}  Level: ${level}`, 10, 20);\n        }\n\n        function gameLoop() {\n            update();\n            draw();\n            requestAnimationFrame(gameLoop);\n        }\n\n        gameLoop();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T20:09:10.553Z","url":"https://quickhtml.app/tilt-breakout"},{"id":78,"app_id":29,"version":2,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>WebRTC P2P with QR Codes</title>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/qr-code-styling/1.5.0/qr-code-styling.min.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js\"></script>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; padding: 20px; }\n        #qr-container { margin: 20px; }\n        #remoteOfferInput { width: 100%; height: 60px; }\n    </style>\n</head>\n<body>\n    <h2>WebRTC P2P with QR Codes</h2>\n    <button onclick=\"startConnection(true)\">Start as Offerer</button>\n    <button onclick=\"startConnection(false)\">Start as Answerer</button>\n    \n    <div id=\"qr-container\"></div>\n    <textarea id=\"remoteOfferInput\" placeholder=\"Paste remote offer here\"></textarea>\n    <button onclick=\"setRemoteOffer()\">Set Remote Offer</button>\n    \n    <div id=\"messages\"></div>\n    <input id=\"messageInput\" type=\"text\" placeholder=\"Type a message\">\n    <button onclick=\"sendMessage()\">Send</button>\n\n    <script>\n        let peerConnection;\n        let dataChannel;\n        const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };\n        \n        function startConnection(isOfferer) {\n            peerConnection = new RTCPeerConnection(config);\n            \n            if (isOfferer) {\n                dataChannel = peerConnection.createDataChannel(\"chat\");\n                setupDataChannel();\n                peerConnection.createOffer().then(offer => {\n                    return peerConnection.setLocalDescription(offer);\n                }).then(() => {\n                    generateQRCode(JSON.stringify(peerConnection.localDescription));\n                });\n            } else {\n                peerConnection.ondatachannel = event => {\n                    dataChannel = event.channel;\n                    setupDataChannel();\n                };\n            }\n            \n            peerConnection.onicecandidate = event => {\n                if (event.candidate === null) {\n                    generateQRCode(JSON.stringify(peerConnection.localDescription));\n                }\n            };\n        }\n        \n        function setupDataChannel() {\n            dataChannel.onmessage = event => displayMessage(\"Peer: \" + event.data);\n            dataChannel.onopen = () => displayMessage(\"Connection established!\");\n        }\n\n        function generateQRCode(text) {\n            document.getElementById('qr-container').innerHTML = \"\";\n            new QRCode(document.getElementById('qr-container'), text);\n        }\n\n        function setRemoteOffer() {\n            const remoteOffer = JSON.parse(document.getElementById('remoteOfferInput').value);\n            peerConnection.setRemoteDescription(new RTCSessionDescription(remoteOffer)).then(() => {\n                if (remoteOffer.type === \"offer\") {\n                    peerConnection.createAnswer().then(answer => {\n                        return peerConnection.setLocalDescription(answer);\n                    }).then(() => {\n                        generateQRCode(JSON.stringify(peerConnection.localDescription));\n                    });\n                }\n            });\n        }\n\n        function sendMessage() {\n            const message = document.getElementById('messageInput').value;\n            if (dataChannel && dataChannel.readyState === 'open') {\n                dataChannel.send(message);\n                displayMessage(\"You: \" + message);\n            }\n        }\n\n        function displayMessage(msg) {\n            const messagesDiv = document.getElementById('messages');\n            messagesDiv.innerHTML += `<p>${msg}</p>`;\n        }\n    </script>\n</body>\n</html>","created_at":"2025-02-04T21:35:35.156Z","url":"https://quickhtml.app/webrtc-qr"},{"id":79,"app_id":30,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Habit Tracker</title>\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/codedgar/Puppertino@latest/dist/css/newfull.css\">\n    <style>\n        body { padding: 20px; max-width: 600px; margin: auto; }\n        .habit-item { display: flex; align-items: center; justify-content: space-between; margin: 10px 0; }\n        .days-container { display: flex; overflow-x: auto; }\n        .days-container input { margin: 0 2px; }\n        .toast { position: fixed; bottom: 10px; left: 50%; transform: translateX(-50%); background: red; color: white; padding: 10px; display: none; }\n    </style>\n</head>\n<body>\n    <header>\n        <h1>Habit Tracker</h1>\n        <button id=\"reset\" class=\"btn\">Reset All</button>\n    </header>\n    <section id=\"habit-input\">\n        <input type=\"text\" id=\"new-habit\" placeholder=\"Enter new habit\">\n        <button id=\"add-habit\" class=\"btn\">Add Habit</button>\n    </section>\n    <section id=\"habit-list\"></section>\n    <div id=\"error-toast\" class=\"toast\">\n        <span id=\"error-message\"></span>\n        <button onclick=\"document.getElementById('error-toast').style.display='none'\">Dismiss</button>\n    </div>\n    <script>\n        document.addEventListener('DOMContentLoaded', () => {\n            const habitInput = document.getElementById('new-habit');\n            const addHabitButton = document.getElementById('add-habit');\n            const habitList = document.getElementById('habit-list');\n            const resetButton = document.getElementById('reset');\n            const habits = JSON.parse(localStorage.getItem('habits')) || [];\n\n            const saveHabits = () => localStorage.setItem('habits', JSON.stringify(habits));\n            const renderHabits = () => {\n                habitList.innerHTML = '';\n                habits.forEach((habit, index) => {\n                    const habitItem = document.createElement('div');\n                    habitItem.className = 'habit-item';\n                    const habitName = document.createElement('span');\n                    habitName.textContent = habit.name;\n                    const daysContainer = document.createElement('div');\n                    daysContainer.className = 'days-container';\n                    for (let i = 0; i < 30; i++) {\n                        const checkbox = document.createElement('input');\n                        checkbox.type = 'checkbox';\n                        checkbox.checked = habit.days[i] || false;\n                        checkbox.addEventListener('change', () => {\n                            habit.days[i] = checkbox.checked;\n                            saveHabits();\n                        });\n                        daysContainer.appendChild(checkbox);\n                    }\n                    const deleteButton = document.createElement('button');\n                    deleteButton.textContent = 'Delete';\n                    deleteButton.className = 'btn btn-danger';\n                    deleteButton.addEventListener('click', () => {\n                        habits.splice(index, 1);\n                        saveHabits();\n                        renderHabits();\n                    });\n                    habitItem.append(habitName, daysContainer, deleteButton);\n                    habitList.appendChild(habitItem);\n                });\n            };\n            addHabitButton.addEventListener('click', () => {\n                const habitName = habitInput.value.trim();\n                if (habitName) {\n                    habits.push({ name: habitName, days: Array(30).fill(false) });\n                    saveHabits();\n                    renderHabits();\n                    habitInput.value = '';\n                }\n            });\n            resetButton.addEventListener('click', () => {\n                localStorage.removeItem('habits');\n                habits.length = 0;\n                renderHabits();\n            });\n            renderHabits();\n        });\n        window.onerror = (message, source, lineno, colno, error) => {\n            const errorMessage = `${message} at ${source}:${lineno}:${colno}`;\n            document.getElementById('error-message').textContent = errorMessage;\n            document.getElementById('error-toast').style.display = 'block';\n            console.error(errorMessage);\n        };\n    </script>\n</body>\n</html>","created_at":"2025-02-04T21:53:07.375Z","url":"https://quickhtml.app/habit-tracker"},{"id":80,"app_id":31,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Habit Tracker</title>\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css\">\n    <style>\n        body { max-width: 500px; margin: auto; padding: 20px; }\n        .habit-item { display: flex; align-items: center; justify-content: space-between; padding: 10px; border-bottom: 1px solid #ddd; }\n        .habit-name { flex: 1; font-weight: bold; }\n        .days-container { display: flex; overflow-x: auto; gap: 4px; }\n        .days-container button { width: 24px; height: 24px; border: none; border-radius: 50%; background: #eee; cursor: pointer; }\n        .days-container button.active { background: #4CAF50; color: white; }\n        .delete-btn { background: none; border: none; color: red; cursor: pointer; }\n        .toast { position: fixed; bottom: 10px; left: 50%; transform: translateX(-50%); background: red; color: white; padding: 10px; display: none; }\n    </style>\n</head>\n<body>\n    <header>\n        <h2>Habit Tracker</h2>\n        <small id=\"stats\">0 habits tracked</small>\n    </header>\n    <section>\n        <input type=\"text\" id=\"new-habit\" placeholder=\"Enter a habit\" aria-label=\"Enter a habit\">\n        <button id=\"add-habit\">+ Add</button>\n    </section>\n    <section id=\"habit-list\"></section>\n    <button id=\"reset\" class=\"contrast\">Reset All</button>\n    <div id=\"error-toast\" class=\"toast\">\n        <span id=\"error-message\"></span>\n        <button onclick=\"document.getElementById('error-toast').style.display='none'\">Dismiss</button>\n    </div>\n    <script>\n        document.addEventListener('DOMContentLoaded', () => {\n            const habitInput = document.getElementById('new-habit');\n            const addHabitButton = document.getElementById('add-habit');\n            const habitList = document.getElementById('habit-list');\n            const resetButton = document.getElementById('reset');\n            const stats = document.getElementById('stats');\n            let habits = JSON.parse(localStorage.getItem('habits')) || [];\n\n            const saveHabits = () => localStorage.setItem('habits', JSON.stringify(habits));\n            const renderHabits = () => {\n                habitList.innerHTML = '';\n                habits.forEach((habit, index) => {\n                    const habitItem = document.createElement('div');\n                    habitItem.className = 'habit-item';\n                    const habitName = document.createElement('span');\n                    habitName.textContent = habit.name;\n                    habitName.className = 'habit-name';\n                    const daysContainer = document.createElement('div');\n                    daysContainer.className = 'days-container';\n                    for (let i = 0; i < 30; i++) {\n                        const button = document.createElement('button');\n                        button.textContent = i + 1;\n                        button.classList.toggle('active', habit.days[i] || false);\n                        button.addEventListener('click', () => {\n                            habit.days[i] = !habit.days[i];\n                            button.classList.toggle('active', habit.days[i]);\n                            saveHabits();\n                            updateStats();\n                        });\n                        daysContainer.appendChild(button);\n                    }\n                    const deleteButton = document.createElement('button');\n                    deleteButton.textContent = '×';\n                    deleteButton.className = 'delete-btn';\n                    deleteButton.addEventListener('click', () => {\n                        habits.splice(index, 1);\n                        saveHabits();\n                        renderHabits();\n                        updateStats();\n                    });\n                    habitItem.append(habitName, daysContainer, deleteButton);\n                    habitList.appendChild(habitItem);\n                });\n                updateStats();\n            };\n            const updateStats = () => {\n                stats.textContent = `${habits.length} habits tracked`;\n            };\n            addHabitButton.addEventListener('click', () => {\n                const habitName = habitInput.value.trim();\n                if (habitName) {\n                    habits.push({ name: habitName, days: Array(30).fill(false) });\n                    saveHabits();\n                    renderHabits();\n                    habitInput.value = '';\n                }\n            });\n            resetButton.addEventListener('click', () => {\n                localStorage.removeItem('habits');\n                habits = [];\n                renderHabits();\n                updateStats();\n            });\n            renderHabits();\n        });\n        window.onerror = (message, source, lineno, colno, error) => {\n            document.getElementById('error-message').textContent = `${message} at ${source}:${lineno}:${colno}`;\n            document.getElementById('error-toast').style.display = 'block';\n            console.error(message);\n        };\n    </script>\n</body>\n</html>","created_at":"2025-02-04T22:23:24.136Z","url":"https://quickhtml.app/habit-tracker-v2"},{"id":82,"app_id":32,"version":2,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Page Not Found</title>\n    <style>\n        body { text-align: center; padding: 50px; font-family: Arial, sans-serif; }\n    </style>\n</head>\n<body>\n    <h2>This app has been removed.</h2>\n</body>\n</html>","created_at":"2025-02-04T22:37:44.396Z","url":"https://quickhtml.app/iframe-loader"},{"id":83,"app_id":33,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Sphere Game of Life</title>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"></script>\n    <style>\n        body { margin: 0; background: black; overflow: hidden; }\n        canvas { display: block; }\n    </style>\n</head>\n<body>\n    <script>\n        let scene = new THREE.Scene();\n        let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);\n        let renderer = new THREE.WebGLRenderer();\n        renderer.setSize(window.innerWidth, window.innerHeight);\n        document.body.appendChild(renderer.domElement);\n\n        let sphereGeometry = new THREE.SphereGeometry(2, 64, 64);\n        let material = new THREE.MeshBasicMaterial({ wireframe: false, vertexColors: true });\n        let sphere = new THREE.Mesh(sphereGeometry, material);\n        scene.add(sphere);\n\n        camera.position.z = 5;\n\n        // Create Game of Life grid on sphere\n        let gridSize = 64;\n        let grid = Array(gridSize).fill().map(() => Array(gridSize).fill(0));\n\n        function randomizeGrid() {\n            for (let i = 0; i < gridSize; i++) {\n                for (let j = 0; j < gridSize; j++) {\n                    grid[i][j] = Math.random() > 0.8 ? 1 : 0;\n                }\n            }\n        }\n        randomizeGrid();\n\n        function updateGrid() {\n            let newGrid = grid.map(arr => [...arr]);\n            for (let i = 0; i < gridSize; i++) {\n                for (let j = 0; j < gridSize; j++) {\n                    let neighbors = 0;\n                    for (let x = -1; x <= 1; x++) {\n                        for (let y = -1; y <= 1; y++) {\n                            if (x === 0 && y === 0) continue;\n                            let ni = (i + x + gridSize) % gridSize;\n                            let nj = (j + y + gridSize) % gridSize;\n                            neighbors += grid[ni][nj];\n                        }\n                    }\n                    newGrid[i][j] = (grid[i][j] && (neighbors === 2 || neighbors === 3)) || (!grid[i][j] && neighbors === 3) ? 1 : 0;\n                }\n            }\n            grid = newGrid;\n        }\n\n        function applyColors() {\n            let colors = [];\n            for (let i = 0; i < gridSize; i++) {\n                for (let j = 0; j < gridSize; j++) {\n                    let color = grid[i][j] ? new THREE.Color(Math.random(), Math.random(), Math.random()) : new THREE.Color(0, 0, 0);\n                    colors.push(color.r, color.g, color.b);\n                }\n            }\n            sphere.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));\n        }\n\n        let rotationSpeed = 0.005;\n        let rotationTarget = { x: Math.random() * 0.02 - 0.01, y: Math.random() * 0.02 - 0.01 };\n\n        function animate() {\n            requestAnimationFrame(animate);\n            updateGrid();\n            applyColors();\n\n            sphere.rotation.x += (rotationTarget.x - sphere.rotation.x) * 0.02;\n            sphere.rotation.y += (rotationTarget.y - sphere.rotation.y) * 0.02;\n            \n            if (Math.random() < 0.01) {\n                rotationTarget.x = Math.random() * 0.02 - 0.01;\n                rotationTarget.y = Math.random() * 0.02 - 0.01;\n            }\n\n            renderer.render(scene, camera);\n        }\n        animate();\n\n        window.addEventListener('resize', () => {\n            camera.aspect = window.innerWidth / window.innerHeight;\n            camera.updateProjectionMatrix();\n            renderer.setSize(window.innerWidth, window.innerHeight);\n        });\n    </script>\n</body>\n</html>","created_at":"2025-02-04T22:44:59.931Z","url":"https://quickhtml.app/spherical-game-of-life"},{"id":89,"app_id":34,"version":3,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Game of Life Sphere</title>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"></script>\n    <style>\n        body { margin: 0; overflow: hidden; background: black; }\n        canvas { display: block; }\n    </style>\n</head>\n<body>\n<script>\n    // Scene setup\n    const scene = new THREE.Scene();\n    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);\n    const renderer = new THREE.WebGLRenderer({ powerPreference: \"high-performance\", alpha: false, depth: true, antialias: true });\n    renderer.setSize(window.innerWidth, window.innerHeight);\n    document.body.appendChild(renderer.domElement);\n\n    // Prevent WebGL storage errors\n    try {\n        renderer.context.getExtension('WEBGL_lose_context')?.loseContext();\n    } catch (e) {\n        console.warn(\"WebGL context extension error:\", e);\n    }\n    \n    // Sphere setup\n    const size = 100; // Grid size\n    const sphereGeometry = new THREE.SphereGeometry(5, size, size);\n    const sphereMaterial = new THREE.MeshBasicMaterial({ vertexColors: true, wireframe: false });\n    const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);\n    scene.add(sphere);\n\n    // Game of Life Grid\n    let grid = Array(size * size).fill().map(() => Math.random() > 0.8 ? 1 : 0);\n    let colors = new Float32Array(size * size * 3);\n\n    function randomColor() {\n        return [Math.random(), Math.random(), Math.random()];\n    }\n\n    function updateColors() {\n        for (let i = 0; i < grid.length; i++) {\n            const color = grid[i] ? randomColor() : [0, 0, 0];\n            colors.set(color, i * 3);\n        }\n        sphere.geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));\n        sphere.geometry.attributes.color.needsUpdate = true;\n    }\n\n    function nextGen() {\n        let newGrid = grid.slice();\n        for (let i = 0; i < grid.length; i++) {\n            let aliveNeighbors = 0;\n            [-1, 1, -size, size].forEach(offset => {\n                let neighbor = (i + offset + grid.length) % grid.length;\n                aliveNeighbors += grid[neighbor];\n            });\n            newGrid[i] = (grid[i] && aliveNeighbors === 2) || aliveNeighbors === 3 ? 1 : 0;\n        }\n        grid = newGrid;\n        updateColors();\n    }\n\n    // Animation\n    let rotationSpeed = { x: 0.002, y: 0.002 };\n\n    function animate() {\n        requestAnimationFrame(animate);\n        sphere.rotation.x += rotationSpeed.x;\n        sphere.rotation.y += rotationSpeed.y;\n        renderer.render(scene, camera);\n    }\n\n    function randomizeRotation() {\n        rotationSpeed.x = (Math.random() - 0.5) * 0.004;\n        rotationSpeed.y = (Math.random() - 0.5) * 0.004;\n        setTimeout(randomizeRotation, Math.random() * 5000 + 3000);\n    }\n    \n    randomizeRotation();\n    setInterval(nextGen, 500);\n    camera.position.z = 10;\n    animate();\n</script>\n</body>\n</html>","created_at":"2025-02-04T23:33:51.353Z","url":"https://quickhtml.app/game-of-life-sphere"},{"id":90,"app_id":35,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Hangman</title>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; }\n        #word { font-size: 24px; letter-spacing: 5px; }\n        #message { color: red; font-weight: bold; }\n        .hangman { font-size: 24px; white-space: pre; font-family: monospace; }\n        button { margin: 5px; }\n    </style>\n</head>\n<body>\n    <h1>Hangman</h1>\n    <pre id=\"hangman-display\" class=\"hangman\"></pre>\n    <p id=\"word\"></p>\n    <p id=\"message\"></p>\n    <input type=\"text\" id=\"guess\" maxlength=\"1\" placeholder=\"Enter a letter\" />\n    <button onclick=\"makeGuess()\">Guess</button>\n    <button onclick=\"resetGame()\">Restart</button>\n    \n    <script>\n        const hangmanStages = [\n            \"\\n\\n\\n\\n\\n\\n\",\n            \"\\n\\n\\n\\n\\n___\",\n            \"|\\n|\\n|\\n|\\n|\\n|___\",\n            \"______\\n|/   |\\n|\\n|\\n|\\n|___\",\n            \"______\\n|/   |\\n|    O\\n|\\n|\\n|___\",\n            \"______\\n|/   |\\n|    O\\n|    |\\n|\\n|___\",\n            \"______\\n|/   |\\n|    O\\n|   /|\\n|\\n|___\",\n            \"______\\n|/   |\\n|    O\\n|   /|\\\\\\n|\\n|___\",\n            \"______\\n|/   |\\n|    O\\n|   /|\\\\\\n|   /\\n|___\",\n            \"______\\n|/   |\\n|    O\\n|   /|\\\\\\n|   / \\\\\\n|___ GAME OVER\"];\n\n        let word = \"\";\n        let guessedWord = [];\n        let guessedLetters = [];\n        let incorrectGuesses = 0;\n\n        function fetchWord() {\n            fetch('https://random-word-api.herokuapp.com/word?number=1')\n                .then(response => response.json())\n                .then(data => {\n                    word = data[0].toUpperCase();\n                    guessedWord = Array(word.length).fill(\"_\");\n                    updateDisplay();\n                })\n                .catch(() => {\n                    word = \"HANGMAN\";\n                    guessedWord = Array(word.length).fill(\"_\");\n                    updateDisplay();\n                });\n        }\n\n        function updateDisplay() {\n            document.getElementById(\"hangman-display\").textContent = hangmanStages[incorrectGuesses];\n            document.getElementById(\"word\").textContent = guessedWord.join(\" \");\n            document.getElementById(\"message\").textContent = \"\";\n        }\n\n        function makeGuess() {\n            let input = document.getElementById(\"guess\").value.toUpperCase();\n            document.getElementById(\"guess\").value = \"\";\n            \n            if (!input || guessedLetters.includes(input) || input.length !== 1) {\n                document.getElementById(\"message\").textContent = \"Invalid or repeated guess!\";\n                return;\n            }\n\n            guessedLetters.push(input);\n\n            if (word.includes(input)) {\n                for (let i = 0; i < word.length; i++) {\n                    if (word[i] === input) guessedWord[i] = input;\n                }\n            } else {\n                incorrectGuesses++;\n            }\n\n            updateDisplay();\n            checkGameOver();\n        }\n\n        function checkGameOver() {\n            if (incorrectGuesses >= hangmanStages.length - 1) {\n                document.getElementById(\"message\").textContent = `Game Over! The word was ${word}.`;\n            } else if (!guessedWord.includes(\"_\")) {\n                document.getElementById(\"message\").textContent = \"You Win!\";\n            }\n        }\n\n        function resetGame() {\n            guessedLetters = [];\n            incorrectGuesses = 0;\n            fetchWord();\n        }\n\n        fetchWord();\n    </script>\n</body>\n</html>","created_at":"2025-02-04T23:37:27.079Z","url":"https://quickhtml.app/hangman"},{"id":94,"app_id":36,"version":4,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Letter Tracing</title>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; margin: 0; background: #f8f8f8; }\n        #canvas { background: white; border: 2px solid black; touch-action: none; }\n        #controls { margin: 10px; }\n        #letterPicker { display: flex; overflow-x: auto; white-space: nowrap; padding: 10px; background: #ddd; }\n        .letter { padding: 10px; cursor: pointer; font-size: 24px; }\n        #nextBtn { display: none; margin-top: 10px; padding: 10px; background: green; color: white; border: none; cursor: pointer; }\n        #resetBtn, #playSoundBtn { padding: 10px; margin: 5px; cursor: pointer; }\n        #indicator { font-size: 24px; color: green; display: none; }\n    </style>\n</head>\n<body>\n    <h1>Letter Tracing</h1>\n    <canvas id=\"canvas\" width=\"400\" height=\"400\"></canvas>\n    <div id=\"controls\">\n        <button id=\"playSoundBtn\">🔊 Play Letter</button>\n        <button id=\"resetBtn\">↺ Reset</button>\n    </div>\n    <div id=\"indicator\">✔ Letter Complete!</div>\n    <button id=\"nextBtn\">Next Letter</button>\n    <div id=\"letterPicker\"></div>\n    \n    <script>\n        const canvas = document.getElementById(\"canvas\");\n        const ctx = canvas.getContext(\"2d\");\n        const resetBtn = document.getElementById(\"resetBtn\");\n        const playSoundBtn = document.getElementById(\"playSoundBtn\");\n        const nextBtn = document.getElementById(\"nextBtn\");\n        const indicator = document.getElementById(\"indicator\");\n        const letterPicker = document.getElementById(\"letterPicker\");\n        let isDrawing = false;\n        let drawnLength = 0;\n        let currentLetter = \"A\";\n        let guideImage = new Image();\n\n        function loadLetter(letter) {\n            currentLetter = letter;\n            guideImage.src = `https://dummyimage.com/400x400/ffffff/cccccc&text=${letter}`;\n            resetCanvas();\n        }\n\n        guideImage.onload = function () {\n            ctx.globalAlpha = 0.2;\n            ctx.drawImage(guideImage, 0, 0, 400, 400);\n            ctx.globalAlpha = 1.0;\n        };\n\n        function resetCanvas() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            ctx.globalAlpha = 0.2;\n            ctx.drawImage(guideImage, 0, 0, 400, 400);\n            ctx.globalAlpha = 1.0;\n            drawnLength = 0;\n            indicator.style.display = \"none\";\n            nextBtn.style.display = \"none\";\n        }\n\n        function checkCompletion() {\n            if (drawnLength > 100) { // Extremely loose requirement\n                indicator.style.display = \"block\";\n                nextBtn.style.display = \"inline-block\";\n            }\n        }\n\n        function getTouchPos(e) {\n            const rect = canvas.getBoundingClientRect();\n            return {\n                x: e.touches[0].clientX - rect.left,\n                y: e.touches[0].clientY - rect.top\n            };\n        }\n\n        function startDrawing(x, y) {\n            isDrawing = true;\n            ctx.beginPath();\n            ctx.moveTo(x, y);\n            drawnLength = 1;\n        }\n\n        function drawLine(x, y) {\n            if (!isDrawing) return;\n            ctx.lineTo(x, y);\n            ctx.strokeStyle = \"black\";\n            ctx.lineWidth = 5;\n            ctx.lineCap = \"round\";\n            ctx.stroke();\n            drawnLength++;\n            checkCompletion();\n        }\n\n        function stopDrawing() {\n            isDrawing = false;\n            ctx.closePath();\n        }\n\n        canvas.addEventListener(\"mousedown\", (e) => startDrawing(e.offsetX, e.offsetY));\n        canvas.addEventListener(\"mouseup\", stopDrawing);\n        canvas.addEventListener(\"mousemove\", (e) => drawLine(e.offsetX, e.offsetY));\n\n        canvas.addEventListener(\"touchstart\", (e) => {\n            e.preventDefault();\n            const pos = getTouchPos(e);\n            startDrawing(pos.x, pos.y);\n        });\n        canvas.addEventListener(\"touchend\", stopDrawing);\n        canvas.addEventListener(\"touchmove\", (e) => {\n            e.preventDefault();\n            const pos = getTouchPos(e);\n            drawLine(pos.x, pos.y);\n        });\n\n        resetBtn.addEventListener(\"click\", resetCanvas);\n\n        playSoundBtn.addEventListener(\"click\", () => {\n            const utterance = new SpeechSynthesisUtterance(currentLetter);\n            speechSynthesis.speak(utterance);\n        });\n\n        nextBtn.addEventListener(\"click\", () => {\n            const nextIndex = (currentLetter.charCodeAt(0) - 65 + 1) % 26;\n            loadLetter(String.fromCharCode(65 + nextIndex));\n        });\n\n        for (let i = 65; i <= 90; i++) {\n            const letter = String.fromCharCode(i);\n            const btn = document.createElement(\"div\");\n            btn.className = \"letter\";\n            btn.innerText = letter;\n            btn.addEventListener(\"click\", () => loadLetter(letter));\n            letterPicker.appendChild(btn);\n        }\n\n        loadLetter(currentLetter);\n    </script>\n</body>\n</html>","created_at":"2025-02-04T23:57:35.667Z","url":"https://quickhtml.app/letter-tracing"},{"id":98,"app_id":37,"version":4,"html":"<!DOCTYPE html>\n<html>\n<head>\n    <title>Classic Tilt Racer</title>\n    <style>\n        body { margin: 0; overflow: hidden; background: black; color: white; font-family: sans-serif; text-align: center; }\n        canvas { display: block; background: black; }\n        #hud { position: absolute; top: 10px; left: 10px; font-size: 20px; text-align: left; }\n        #startButton { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 20px; background: rgba(0, 0, 0, 0.7); padding: 20px; cursor: pointer; }\n    </style>\n</head>\n<body>\n    <canvas id=\"gameCanvas\"></canvas>\n    <div id=\"hud\">Speed: 0 | Laps: 0/3 | Lives: 3</div>\n    <div id=\"startButton\">Tap to Start</div>\n    \n    <script>\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        const hud = document.getElementById(\"hud\");\n        const startButton = document.getElementById(\"startButton\");\n        \n        canvas.width = window.innerWidth;\n        canvas.height = window.innerHeight;\n        \n        let speed = 0, tiltX = 0, tiltY = 0;\n        let roadPos = 0, carX = 0;\n        let gameStarted = false;\n        let lives = 3, laps = 0, trackLength = 10000, distance = 0;\n        let opponents = [{ x: Math.random() * 200 - 100, z: 5000 }];\n        \n        function requestMotionPermission() {\n            if (typeof DeviceMotionEvent !== 'undefined' && typeof DeviceMotionEvent.requestPermission === 'function') {\n                DeviceMotionEvent.requestPermission().then(permissionState => {\n                    if (permissionState === 'granted') {\n                        startGame();\n                    }\n                }).catch(console.error);\n            } else {\n                startGame();\n            }\n        }\n        \n        function startGame() {\n            startButton.style.display = \"none\";\n            gameStarted = true;\n            gameLoop();\n        }\n        \n        window.addEventListener(\"deviceorientation\", (event) => {\n            tiltX = event.gamma / 30;\n            tiltY = event.beta / 30;\n        });\n        \n        function update() {\n            if (!gameStarted || lives <= 0) return;\n            speed = Math.max(0, Math.min(10, speed + tiltY * 0.5 - 0.1));\n            carX += tiltX * speed * 2;\n            distance += speed * 3;\n            \n            if (distance >= trackLength) {\n                laps++;\n                distance = 0;\n                if (laps >= 3) gameStarted = false;\n            }\n            \n            opponents.forEach(car => {\n                car.z -= speed * 5;\n                if (car.z < 50 && Math.abs(car.x - carX) < 30) {\n                    lives--;\n                    car.z = Math.random() * 5000 + 5000;\n                }\n            });\n            \n            hud.innerText = `Speed: ${Math.round(speed * 10)} | Laps: ${laps}/3 | Lives: ${lives}`;\n        }\n        \n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            \n            ctx.fillStyle = \"gray\";\n            ctx.beginPath();\n            ctx.moveTo(canvas.width * 0.2 + carX, canvas.height);\n            ctx.lineTo(canvas.width * 0.8 + carX, canvas.height);\n            ctx.lineTo(canvas.width * 0.6, canvas.height * 0.3);\n            ctx.lineTo(canvas.width * 0.4, canvas.height * 0.3);\n            ctx.closePath();\n            ctx.fill();\n            \n            ctx.fillStyle = \"white\";\n            for (let i = 0; i < 5; i++) {\n                let y = (canvas.height * 0.3 + ((roadPos + i * 100) % 500));\n                let lineW = 10 + (y - canvas.height * 0.3) * 0.05;\n                ctx.fillRect(canvas.width / 2 - lineW / 2 + carX * 0.2, y, lineW, 20);\n            }\n            \n            ctx.fillStyle = \"red\";\n            ctx.fillRect(canvas.width / 2 - 20, canvas.height - 50, 40, 20);\n            \n            opponents.forEach(car => {\n                let scale = 1 - car.z / 5000;\n                let x = canvas.width / 2 + car.x * scale;\n                let y = canvas.height * 0.5 - car.z * scale;\n                ctx.fillStyle = \"blue\";\n                ctx.fillRect(x - 20 * scale, y, 40 * scale, 20 * scale);\n            });\n        }\n        \n        function gameLoop() {\n            update();\n            draw();\n            if (gameStarted && lives > 0) requestAnimationFrame(gameLoop);\n        }\n        \n        startButton.addEventListener(\"click\", requestMotionPermission);\n    </script>\n</body>\n</html>","created_at":"2025-02-05T00:06:17.104Z","url":"https://quickhtml.app/pole-position-tilt"},{"id":103,"app_id":38,"version":5,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n    <title>Rhode Island City Guessing Game</title>\n    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css\" />\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js\"></script>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.10.11/interact.min.js\"></script>\n    <style>\n        body { font-family: Arial, sans-serif; text-align: center; overflow: hidden; touch-action: none; }\n        #map { height: 500px; width: 100%; margin-bottom: 10px; z-index: 0; position: relative; }\n        #city-list { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-bottom: 10px; z-index: 10; position: relative; }\n        .city { padding: 5px 10px; background: lightblue; cursor: grab; border-radius: 5px; position: relative; z-index: 10; touch-action: none; }\n        .city.dragging { opacity: 0.5; }\n        .win-message { display: none; color: green; font-size: 24px; margin-top: 10px; }\n        #test-guess { margin-top: 10px; padding: 10px 20px; font-size: 16px; cursor: pointer; display: block; margin: 20px auto; }\n    </style>\n</head>\n<body>\n    <h2>Rhode Island City Guessing Game</h2>\n    <div id=\"city-list\"></div>\n    <div id=\"map\"></div>\n    <button id=\"test-guess\">Test Guess</button>\n    <p class=\"win-message\">You Win! 🎉</p>\n    <script>\n        const cities = [\"Providence\", \"Cranston\", \"Warwick\", \"Pawtucket\", \"East Providence\", \"Newport\", \"Woonsocket\", \"Central Falls\", \"Westerly\", \"Coventry\"];\n        const chosenCities = cities.sort(() => 0.5 - Math.random()).slice(0, 5);\n        let placedCities = {};\n\n        const map = L.map('map', { preferCanvas: true, dragging: false, zoomControl: false, scrollWheelZoom: false, doubleClickZoom: false, boxZoom: false, keyboard: false, touchZoom: false })\n            .setView([41.7, -71.5], 10); // Adjusted zoom level\n        L.tileLayer('https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png').addTo(map);\n\n        document.getElementById('city-list').innerHTML = chosenCities.map(city => `<div class='city' id='${city}'>${city}</div>`).join('');\n\n        interact('.city').draggable({\n            inertia: true,\n            autoScroll: false,\n            listeners: {\n                start(event) { event.target.classList.add('dragging'); },\n                end(event) { event.target.classList.remove('dragging'); },\n                move(event) {\n                    let target = event.target;\n                    let x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;\n                    let y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;\n                    target.style.transform = `translate(${x}px, ${y}px)`;\n                    target.setAttribute('data-x', x);\n                    target.setAttribute('data-y', y);\n                }\n            }\n        });\n\n        map.on('click', function(e) {\n            const selectedCity = document.querySelector('.city.dragging');\n            if (!selectedCity) return;\n            \n            placedCities[selectedCity.id] = { lat: e.latlng.lat, lng: e.latlng.lng };\n            selectedCity.remove();\n        });\n\n        document.getElementById('test-guess').addEventListener('click', validateCities);\n\n        function validateCities() {\n            let correct = 0;\n            const cityCoords = {\n                \"Providence\": [41.8236, -71.4222],\n                \"Cranston\": [41.7798, -71.4373],\n                \"Warwick\": [41.7001, -71.4162],\n                \"Pawtucket\": [41.8787, -71.3826],\n                \"East Providence\": [41.8137, -71.3701],\n                \"Newport\": [41.4901, -71.3128],\n                \"Woonsocket\": [42.0029, -71.5148],\n                \"Central Falls\": [41.8901, -71.3927],\n                \"Westerly\": [41.3776, -71.8273],\n                \"Coventry\": [41.7003, -71.6822]\n            };\n\n            Object.keys(placedCities).forEach(city => {\n                let { lat, lng } = placedCities[city];\n                let [cityLat, cityLng] = cityCoords[city];\n                let distance = Math.sqrt(Math.pow(lat - cityLat, 2) + Math.pow(lng - cityLng, 2));\n                if (distance < 0.05) correct++; // More accuracy\n            });\n\n            if (correct === chosenCities.length) {\n                document.querySelector('.win-message').style.display = 'block';\n            } else {\n                alert('Some placements are incorrect! Try again.');\n                placedCities = {};\n                document.getElementById('city-list').innerHTML = chosenCities.map(city => `<div class='city' id='${city}'>${city}</div>`).join('');\n            }\n        }\n    </script>\n</body>\n</html>","created_at":"2025-02-05T03:53:29.878Z","url":"https://quickhtml.app/ri-city-guess"},{"id":104,"app_id":39,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Red Sphere Run</title>\n    <style>\n        body { margin: 0; overflow: hidden; background: #87CEEB; }\n        canvas { display: block; }\n        #score { position: absolute; top: 10px; left: 10px; font-size: 20px; color: white; font-family: Arial, sans-serif; }\n        #restart { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: none; padding: 10px 20px; font-size: 20px; }\n    </style>\n</head>\n<body>\n    <div id=\"score\">Score: 0</div>\n    <button id=\"restart\" onclick=\"restartGame()\">Restart</button>\n    <canvas id=\"gameCanvas\"></canvas>\n    <script>\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        const scoreDisplay = document.getElementById(\"score\");\n        const restartButton = document.getElementById(\"restart\");\n\n        canvas.width = window.innerWidth;\n        canvas.height = window.innerHeight;\n\n        let sphere = { x: 100, y: canvas.height - 100, radius: 20, dx: 0, dy: 0 };\n        let gravity = 0.5;\n        let jumpPower = -10;\n        let onGround = false;\n        let score = 0;\n        let startTime = Date.now();\n\n        function updateScore() {\n            let timeBonus = Math.max(0, 1000 - Math.floor((Date.now() - startTime) / 100));\n            score = Math.max(0, timeBonus - Math.floor(sphere.y / 10));\n            scoreDisplay.innerText = `Score: ${score}`;\n        }\n\n        function jump() {\n            if (onGround) {\n                sphere.dy = jumpPower;\n                onGround = false;\n                score -= 5;\n            }\n        }\n\n        window.addEventListener(\"deviceorientation\", (event) => {\n            let tilt = event.gamma;\n            sphere.dx = (tilt / 30) * 5;\n        });\n\n        window.addEventListener(\"touchstart\", jump);\n\n        function update() {\n            sphere.dy += gravity;\n            sphere.x += sphere.dx;\n            sphere.y += sphere.dy;\n\n            if (sphere.y + sphere.radius >= canvas.height - 20) {\n                sphere.y = canvas.height - 20 - sphere.radius;\n                sphere.dy = 0;\n                onGround = true;\n            }\n\n            if (sphere.x > canvas.width - 50) {\n                alert(\"Level Complete! Final Score: \" + score);\n                restartGame();\n            }\n\n            if (sphere.y > canvas.height) {\n                restartButton.style.display = \"block\";\n            }\n\n            updateScore();\n        }\n\n        function restartGame() {\n            sphere.x = 100;\n            sphere.y = canvas.height - 100;\n            sphere.dx = 0;\n            sphere.dy = 0;\n            score = 0;\n            startTime = Date.now();\n            restartButton.style.display = \"none\";\n        }\n\n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            ctx.fillStyle = \"red\";\n            ctx.beginPath();\n            ctx.arc(sphere.x, sphere.y, sphere.radius, 0, Math.PI * 2);\n            ctx.fill();\n        }\n\n        function gameLoop() {\n            update();\n            draw();\n            requestAnimationFrame(gameLoop);\n        }\n\n        gameLoop();\n    </script>\n</body>\n</html>","created_at":"2025-02-05T13:34:18.303Z","url":"https://quickhtml.app/red-sphere-run"},{"id":109,"app_id":40,"version":5,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Gyro Ball Platformer</title>\n    <style>\n        * { margin: 0; padding: 0; box-sizing: border-box; }\n        body { overflow: hidden; background-color: #87CEEB; font-family: Arial, sans-serif; text-align: center; }\n        canvas { display: block; background: #c0f0ff; margin: auto; }\n        #score { position: absolute; top: 10px; left: 10px; font-size: 20px; font-weight: bold; }\n        #startButton { padding: 10px 20px; font-size: 18px; margin-top: 20px; }\n    </style>\n</head>\n<body>\n    <div id=\"score\">Score: 0</div>\n    <button id=\"startButton\">Enable Motion Controls</button>\n    <canvas id=\"gameCanvas\"></canvas>\n    \n    <script>\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        const startButton = document.getElementById(\"startButton\");\n        canvas.width = window.innerWidth;\n        canvas.height = window.innerHeight;\n        \n        const ball = { x: 100, y: 100, radius: 20, dx: 0, dy: 0, speed: 2, gravity: 0.5, jumpPower: -15 };\n        let cameraX = 0;\n        let platforms = [];\n        let clouds = [];\n        let score = 0;\n        \n        function generatePlatforms() {\n            platforms = [];\n            for (let i = 0; i < 50; i++) {\n                platforms.push({ x: i * 300, y: canvas.height - (Math.random() * 200 + 50), width: 200, height: 20 });\n            }\n        }\n        \n        function generateClouds() {\n            clouds = [];\n            for (let i = 0; i < 10; i++) {\n                clouds.push({ x: Math.random() * 5000, y: Math.random() * (canvas.height / 2), width: 100, height: 50 });\n            }\n        }\n        \n        generatePlatforms();\n        generateClouds();\n        \n        function requestMotionPermission() {\n            if (typeof DeviceMotionEvent.requestPermission === 'function') {\n                DeviceMotionEvent.requestPermission().then(permissionState => {\n                    if (permissionState === 'granted') {\n                        window.addEventListener(\"deviceorientation\", handleOrientation);\n                    }\n                }).catch(console.error);\n            } else {\n                window.addEventListener(\"deviceorientation\", handleOrientation);\n            }\n        }\n        \n        function handleOrientation(event) {\n            let tilt = event.gamma;\n            if (tilt > 5) ball.dx = ball.speed;\n            else if (tilt < -5) ball.dx = -ball.speed;\n            else ball.dx = 0;\n        }\n        \n        startButton.addEventListener(\"click\", () => {\n            requestMotionPermission();\n            startButton.style.display = \"none\";\n        });\n        \n        window.addEventListener(\"touchstart\", () => {\n            if (ball.dy === 0) ball.dy = ball.jumpPower;\n        });\n        \n        function update() {\n            ball.dy += ball.gravity;\n            ball.y += ball.dy;\n            ball.x += ball.dx;\n            \n            cameraX = ball.x - canvas.width / 2;\n            \n            platforms.forEach(platform => {\n                if (\n                    ball.y + ball.radius >= platform.y &&\n                    ball.y + ball.radius <= platform.y + platform.height &&\n                    ball.x >= platform.x && ball.x <= platform.x + platform.width\n                ) {\n                    ball.dy = 0;\n                    ball.y = platform.y - ball.radius;\n                }\n            });\n            \n            if (ball.y > canvas.height) {\n                score = 0;\n                ball.x = 100;\n                ball.y = 100;\n                cameraX = 0;\n                generatePlatforms();\n            }\n        }\n        \n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            \n            ctx.fillStyle = \"white\";\n            clouds.forEach(cloud => {\n                ctx.beginPath();\n                ctx.arc(cloud.x - cameraX, cloud.y, 25, 0, Math.PI * 2);\n                ctx.arc(cloud.x + 30 - cameraX, cloud.y + 10, 30, 0, Math.PI * 2);\n                ctx.arc(cloud.x + 60 - cameraX, cloud.y, 25, 0, Math.PI * 2);\n                ctx.fill();\n            });\n            \n            ctx.fillStyle = \"red\";\n            ctx.beginPath();\n            ctx.arc(ball.x - cameraX, ball.y, ball.radius, 0, Math.PI * 2);\n            ctx.fill();\n            \n            ctx.fillStyle = \"brown\";\n            platforms.forEach(platform => {\n                ctx.fillRect(platform.x - cameraX, platform.y, platform.width, platform.height);\n            });\n            \n            document.getElementById(\"score\").innerText = \"Score: \" + score;\n        }\n        \n        function gameLoop() {\n            update();\n            draw();\n            requestAnimationFrame(gameLoop);\n        }\n        \n        gameLoop();\n    </script>\n</body>\n</html>","created_at":"2025-02-05T13:54:12.131Z","url":"https://quickhtml.app/gyro-ball-platformer"},{"id":110,"app_id":67,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Air Fried Carrots</title>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            text-align: center;\n            margin: 0;\n            padding: 0;\n            background-color: #f4f4f4;\n        }\n        .container {\n            margin-top: 20px;\n        }\n        img {\n            max-width: 90%;\n            height: auto;\n            border-radius: 10px;\n            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);\n        }\n        .error-container {\n            position: fixed;\n            bottom: 10px;\n            left: 50%;\n            transform: translateX(-50%);\n            background: rgba(255, 0, 0, 0.8);\n            color: white;\n            padding: 10px;\n            border-radius: 5px;\n            display: none;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <h1>Air Fried Carrots</h1>\n        <img src=\"https://quickhtml.app/uploads/airfried-carrots.jpg\" alt=\"Air fried carrots\">\n    </div>\n    <div class=\"error-container\" id=\"errorBox\"></div>\n    <script>\n        window.onerror = function(message, source, lineno, colno, error) {\n            var errorBox = document.getElementById(\"errorBox\");\n            errorBox.textContent = `Error: ${message} at ${source}:${lineno}:${colno}`;\n            errorBox.style.display = \"block\";\n            setTimeout(() => errorBox.style.display = \"none\", 5000);\n        };\n    </script>\n</body>\n</html>","created_at":"2025-02-06T02:23:05.050Z","url":"https://quickhtml.app/airfried-carrots"},{"id":134,"app_id":100,"version":2,"html":"<!DOCTYPE html>\n<html>\n<head>\n    <title>Pixel Pet</title>\n    <style>\n        body {\n            margin: 0;\n            background: #87CEEB;\n            display: flex;\n            justify-content: center;\n            align-items: center;\n            height: 100vh;\n            overflow: hidden;\n        }\n        canvas {\n            image-rendering: pixelated;\n            background: #228B22; /* Green grass background */\n        }\n        #ui {\n            position: absolute;\n            top: 10px;\n            left: 10px;\n            background: rgba(255, 255, 255, 0.8);\n            padding: 5px;\n            font-family: Arial, sans-serif;\n            font-size: 14px;\n            border-radius: 5px;\n        }\n    </style>\n</head>\n<body>\n    <canvas id=\"gameCanvas\"></canvas>\n    <div id=\"ui\">\n        Hunger: <span id=\"hunger\">50</span><br>\n        Thirst: <span id=\"thirst\">50</span><br>\n        Boredom: <span id=\"boredom\">50</span><br>\n        <button onclick=\"resetGame()\">Reset</button>\n    </div>\n    <script>\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = 160;\n        canvas.height = 160;\n        \n        const SCALE = 8;\n        const GRID_SIZE = canvas.width / SCALE;\n        let pet = { x: 10, y: 10, hunger: 50, thirst: 50, boredom: 50, mood: \"neutral\" };\n        let objects = [];\n        \n        function drawBackground() {\n            ctx.fillStyle = \"#228B22\";\n            ctx.fillRect(0, 0, canvas.width, canvas.height);\n        }\n        \n        function drawPet() {\n            ctx.fillStyle = \"#FFCC00\";\n            ctx.fillRect(pet.x * SCALE, pet.y * SCALE, SCALE, SCALE);\n        }\n        \n        function drawObjects() {\n            ctx.fillStyle = \"#8B4513\";\n            objects.forEach(obj => {\n                ctx.fillRect(obj.x * SCALE, obj.y * SCALE, SCALE, SCALE);\n            });\n        }\n        \n        function updateGame() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            drawBackground();\n            drawObjects();\n            drawPet();\n        }\n        \n        function placeObject(x, y) {\n            objects.push({ x, y });\n            updateGame();\n        }\n        \n        function resetGame() {\n            objects = [];\n            pet = { x: 10, y: 10, hunger: 50, thirst: 50, boredom: 50, mood: \"neutral\" };\n            updateGame();\n        }\n        \n        canvas.addEventListener(\"click\", (e) => {\n            let rect = canvas.getBoundingClientRect();\n            let x = Math.floor((e.clientX - rect.left) / SCALE);\n            let y = Math.floor((e.clientY - rect.top) / SCALE);\n            placeObject(x, y);\n        });\n        \n        setInterval(() => {\n            pet.hunger = Math.max(0, pet.hunger - 1);\n            pet.thirst = Math.max(0, pet.thirst - 1);\n            pet.boredom = Math.max(0, pet.boredom - 1);\n            document.getElementById(\"hunger\").innerText = pet.hunger;\n            document.getElementById(\"thirst\").innerText = pet.thirst;\n            document.getElementById(\"boredom\").innerText = pet.boredom;\n            updateGame();\n        }, 3000);\n        \n        updateGame();\n    </script>\n</body>\n</html>","created_at":"2025-02-07T06:17:35.545Z","url":"https://quickhtml.app/pixel_pet"},{"id":140,"app_id":101,"version":6,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Pixel Pet</title>\n    <style>\n        @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');\n        body { margin: 0; overflow: hidden; background: #222; display: flex; justify-content: center; align-items: center; height: 100vh; }\n        canvas { image-rendering: pixelated; display: block; }\n        .hud { position: absolute; top: 10px; left: 10px; color: white; font-family: 'Press Start 2P', cursive; font-size: 12px; }\n        .radial-menu { position: absolute; display: none; background: rgba(0,0,0,0.7); padding: 10px; border-radius: 8px; }\n        .radial-menu button { display: block; margin: 5px; color: white; background: #444; border: none; padding: 5px; cursor: pointer; }\n    </style>\n</head>\n<body>\n    <canvas id=\"gameCanvas\"></canvas>\n    <div class=\"hud\">Hunger: <span id=\"hunger\">100</span> | Thirst: <span id=\"thirst\">100</span> | Boredom: <span id=\"boredom\">100</span></div>\n    <div class=\"radial-menu\" id=\"radialMenu\">\n        <button onclick=\"placeObject('food')\">Food</button>\n        <button onclick=\"placeObject('water')\">Water</button>\n        <button onclick=\"placeObject('toy')\">Toy</button>\n    </div>\n    <script>\n        const canvas = document.getElementById(\"gameCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = window.innerWidth;\n        canvas.height = window.innerHeight;\n        const gridSize = 20;\n        const tileSize = Math.floor(canvas.width / gridSize);\n\n        function generateTerrain() {\n            let terrain = [];\n            for (let y = 0; y < gridSize; y++) {\n                let row = [];\n                for (let x = 0; x < gridSize; x++) {\n                    let noise = Math.random();\n                    if (noise > 0.85) row.push(\"water\");\n                    else if (noise > 0.75) row.push(\"sand\");\n                    else row.push(\"grass\");\n                }\n                terrain.push(row);\n            }\n            return terrain;\n        }\n        let terrain = generateTerrain();\n\n        let pet = { x: 10, y: 10, hunger: 100, thirst: 100, boredom: 100 };\n        function updateStats() {\n            pet.hunger -= 1;\n            pet.thirst -= 1;\n            pet.boredom -= 1;\n            document.getElementById(\"hunger\").innerText = pet.hunger;\n            document.getElementById(\"thirst\").innerText = pet.thirst;\n            document.getElementById(\"boredom\").innerText = pet.boredom;\n        }\n        setInterval(updateStats, 5000);\n\n        let objects = [];\n        function placeObject(type) {\n            let x = Math.floor(lastClickX / tileSize);\n            let y = Math.floor(lastClickY / tileSize);\n            objects.push({ x, y, type });\n            document.getElementById(\"radialMenu\").style.display = \"none\";\n        }\n        \n        let lastClickX = 0, lastClickY = 0;\n        function draw() {\n            ctx.clearRect(0, 0, canvas.width, canvas.height);\n            \n            for (let y = 0; y < gridSize; y++) {\n                for (let x = 0; x < gridSize; x++) {\n                    ctx.fillStyle = {\"grass\": \"#228B22\", \"sand\": \"#C2B280\", \"water\": \"#1E90FF\"}[terrain[y][x]];\n                    ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);\n                }\n            }\n\n            for (let obj of objects) {\n                ctx.fillStyle = obj.type === \"food\" ? \"red\" : obj.type === \"water\" ? \"blue\" : \"orange\";\n                ctx.fillRect(obj.x * tileSize + 2, obj.y * tileSize + 2, tileSize - 4, tileSize - 4);\n            }\n\n            let px = pet.x * tileSize;\n            let py = pet.y * tileSize;\n            ctx.fillStyle = \"yellow\";\n            ctx.fillRect(px, py, tileSize * 2, tileSize * 2);\n            \n            ctx.fillStyle = \"black\";\n            if (Math.random() > 0.1) {\n                ctx.fillRect(px + tileSize / 2, py + tileSize / 2, 4, 4);\n                ctx.fillRect(px + (3 * tileSize) / 2, py + tileSize / 2, 4, 4);\n            }\n            requestAnimationFrame(draw);\n        }\n        draw();\n\n        document.addEventListener(\"click\", (e) => {\n            lastClickX = e.clientX;\n            lastClickY = e.clientY;\n            const menu = document.getElementById(\"radialMenu\");\n            menu.style.display = \"block\";\n            menu.style.left = `${e.clientX}px`;\n            menu.style.top = `${e.clientY}px`;\n        });\n    </script>\n</body>\n</html>","created_at":"2025-02-07T06:34:53.058Z","url":"https://quickhtml.app/pixel-pet"},{"id":146,"app_id":102,"version":5,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Asteroids Grid Clone</title>\n    <style>\n        body {\n            background-color: black;\n            color: white;\n            text-align: center;\n            font-family: Arial, sans-serif;\n            margin: 0;\n            padding: 0;\n        }\n        .game-container {\n            display: grid;\n            grid-template-columns: repeat(150, 1fr);\n            grid-template-rows: repeat(75, 1fr);\n            gap: 1px;\n            width: 100%;\n            max-width: 100vw;\n            aspect-ratio: 2 / 1;\n            margin: auto;\n            border: 2px solid white;\n        }\n        .cell {\n            background-color: black;\n            border: 1px solid white;\n        }\n        .controls {\n            display: grid;\n            grid-template-columns: 1fr 1fr 1fr;\n            grid-template-rows: 1fr 1fr 1fr;\n            gap: 10px;\n            width: 200px;\n            margin: 20px auto;\n        }\n        .controls button {\n            background-color: gray;\n            color: white;\n            border: none;\n            padding: 20px;\n            font-size: 18px;\n            border-radius: 50%;\n            width: 60px;\n            height: 60px;\n            cursor: pointer;\n        }\n        .fire { grid-column: 2; grid-row: 1; }\n        .left { grid-column: 1; grid-row: 2; }\n        .right { grid-column: 3; grid-row: 2; }\n        .thrust { grid-column: 2; grid-row: 3; }\n    </style>\n</head>\n<body>\n    <h1>Asteroids Grid Clone</h1>\n    <div class=\"game-container\" id=\"game\"></div>\n    <div class=\"controls\">\n        <button class=\"fire\" onclick=\"shoot()\">Shoot</button>\n        <button class=\"left\" onclick=\"rotateLeft()\">◄</button>\n        <button class=\"right\" onclick=\"rotateRight()\">►</button>\n        <button class=\"thrust\" onclick=\"thrust()\">▲</button>\n    </div>\n\n    <script>\n        const gridWidth = 150;\n        const gridHeight = 75;\n        let gameGrid = [];\n\n        function createGrid() {\n            const gameContainer = document.getElementById('game');\n            for (let y = 0; y < gridHeight; y++) {\n                let row = [];\n                for (let x = 0; x < gridWidth; x++) {\n                    let cell = document.createElement('div');\n                    cell.classList.add('cell');\n                    gameContainer.appendChild(cell);\n                    row.push(cell);\n                }\n                gameGrid.push(row);\n            }\n        }\n\n        function drawPixel(x, y, shade) {\n            if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) {\n                gameGrid[y][x].style.backgroundColor = `rgb(${shade}, ${shade}, ${shade})`;\n            }\n        }\n\n        function clearGrid() {\n            for (let y = 0; y < gridHeight; y++) {\n                for (let x = 0; x < gridWidth; x++) {\n                    gameGrid[y][x].style.backgroundColor = 'black';\n                }\n            }\n        }\n\n        let player = { x: 75, y: 37, angle: 0, dx: 0, dy: 0, size: 3 };\n        let bullets = [];\n        let asteroids = [\n            { x: 40, y: 20, dx: 1, dy: 0.5, size: 10 },\n            { x: 110, y: 50, dx: -0.7, dy: 0.3, size: 15 }\n        ];\n\n        function updateGame() {\n            clearGrid();\n            \n            player.x += player.dx;\n            player.y += player.dy;\n            \n            if (player.x < 0) player.x = gridWidth - 1;\n            if (player.x >= gridWidth) player.x = 0;\n            if (player.y < 0) player.y = gridHeight - 1;\n            if (player.y >= gridHeight) player.y = 0;\n            \n            for (let i = -player.size; i <= player.size; i++) {\n                for (let j = -player.size; j <= player.size; j++) {\n                    drawPixel(Math.round(player.x + i), Math.round(player.y + j), 255);\n                }\n            }\n            \n            bullets.forEach((bullet, index) => {\n                bullet.x += Math.cos(bullet.angle) * 2;\n                bullet.y += Math.sin(bullet.angle) * 2;\n                drawPixel(Math.round(bullet.x), Math.round(bullet.y), 200);\n            });\n            \n            asteroids.forEach(asteroid => {\n                asteroid.x += asteroid.dx;\n                asteroid.y += asteroid.dy;\n                drawPixel(Math.round(asteroid.x), Math.round(asteroid.y), 150);\n            });\n        }\n\n        function rotateLeft() {\n            player.angle -= 0.1;\n        }\n        function rotateRight() {\n            player.angle += 0.1;\n        }\n        function thrust() {\n            player.dx += Math.cos(player.angle) * 0.5;\n            player.dy += Math.sin(player.angle) * 0.5;\n        }\n        function shoot() {\n            bullets.push({ x: player.x, y: player.y, angle: player.angle });\n        }\n\n        createGrid();\n        setInterval(updateGame, 50);\n    </script>\n</body>\n</html>","created_at":"2025-02-10T04:02:03.262Z","url":"https://quickhtml.app/asteroids-grid"},{"id":166,"app_id":133,"version":1,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Perlin Noise Terrain</title>\n    <style>\n        body { background: black; display: flex; justify-content: center; align-items: center; height: 100vh; }\n        canvas { image-rendering: pixelated; }\n    </style>\n</head>\n<body>\n    <canvas id=\"terrainCanvas\"></canvas>\n    \n    <script>\n        const canvas = document.getElementById(\"terrainCanvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = 800;\n        canvas.height = 400;\n\n        // Perlin Noise Implementation\n        class PerlinNoise {\n            constructor() {\n                this.gradients = {};\n                this.memory = {};\n            }\n\n            randVector() {\n                const theta = Math.random() * 2 * Math.PI;\n                return { x: Math.cos(theta), y: Math.sin(theta) };\n            }\n\n            dotProductGrid(x, y, vx, vy) {\n                const gVect = this.grad(x, y);\n                return (vx - x) * gVect.x + (vy - y) * gVect.y;\n            }\n\n            grad(x, y) {\n                const key = `${x},${y}`;\n                if (!this.gradients[key]) {\n                    this.gradients[key] = this.randVector();\n                }\n                return this.gradients[key];\n            }\n\n            fade(t) {\n                return t * t * t * (t * (t * 6 - 15) + 10);\n            }\n\n            lerp(a, b, t) {\n                return a + t * (b - a);\n            }\n\n            noise(x, y) {\n                const x0 = Math.floor(x);\n                const x1 = x0 + 1;\n                const y0 = Math.floor(y);\n                const y1 = y0 + 1;\n\n                const sx = this.fade(x - x0);\n                const sy = this.fade(y - y0);\n\n                const n0 = this.dotProductGrid(x0, y0, x, y);\n                const n1 = this.dotProductGrid(x1, y0, x, y);\n                const ix0 = this.lerp(n0, n1, sx);\n\n                const n2 = this.dotProductGrid(x0, y1, x, y);\n                const n3 = this.dotProductGrid(x1, y1, x, y);\n                const ix1 = this.lerp(n2, n3, sx);\n\n                return this.lerp(ix0, ix1, sy);\n            }\n        }\n\n        const perlin = new PerlinNoise();\n\n        function perlinNoise(x) {\n            return (perlin.noise(x * 0.05, 0) + 1) * 0.5 * 80 + 100;\n        }\n\n        function generateTerrain() {\n            const width = canvas.width;\n            const height = canvas.height;\n            const terrainHeight = [];\n            \n            for (let x = 0; x < width; x++) {\n                terrainHeight[x] = perlinNoise(x);\n            }\n            return terrainHeight;\n        }\n\n        function renderTerrain(terrainHeight) {\n            ctx.fillStyle = \"#4a2c2a\";\n            for (let x = 0; x < terrainHeight.length; x++) {\n                let yStart = Math.floor(terrainHeight[x]);\n                for (let y = yStart; y < canvas.height; y++) {\n                    ctx.fillRect(x, y, 1, 1);\n                }\n            }\n        }\n\n        function applyPixelArtShader() {\n            // Placeholder: Add effects like CRT lines, dithering later\n        }\n\n        const terrain = generateTerrain();\n        renderTerrain(terrain);\n        applyPixelArtShader();\n    </script>\n</body>\n</html>","created_at":"2025-02-12T18:57:52.979Z","url":"https://quickhtml.app/perlin-terrain"},{"id":200,"app_id":166,"version":2,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Campfire Simulation: Enhanced Tongues & Brown Logs</title>\n  <style>\n    body {\n      margin: 0;\n      background: #000;\n    }\n    canvas {\n      display: block;\n      margin: 0 auto;\n      background: #000;\n      image-rendering: pixelated;\n    }\n    #error-log {\n      position: fixed;\n      bottom: 10px;\n      left: 50%;\n      transform: translateX(-50%);\n      background: rgba(255, 0, 0, 0.8);\n      color: white;\n      padding: 10px;\n      border-radius: 5px;\n      font-family: monospace;\n      display: none;\n      max-width: 90%;\n      word-wrap: break-word;\n    }\n  </style>\n</head>\n<body>\n  <canvas id=\"canvas\"></canvas>\n  <div id=\"error-log\"></div>\n  <script>\n    (function() {\n      const errorLog = document.getElementById('error-log');\n      window.onerror = function(message, source, lineno, colno, error) {\n        errorLog.textContent = `Error: ${message} at ${source}:${lineno}:${colno}`;\n        errorLog.style.display = 'block';\n      };\n    })();\n  </script>\n  <script>\n    (function(){\n      \"use strict\";\n      const gridWidth = 128;\n      const gridHeight = 128;\n      const canvas = document.getElementById('canvas');\n      const ctx = canvas.getContext('2d');\n      const scale = 4;\n      canvas.width = gridWidth * scale;\n      canvas.height = gridHeight * scale;\n      ctx.imageSmoothingEnabled = false;\n      let temp = new Float32Array(gridWidth * gridHeight);\n      let smoke = new Float32Array(gridWidth * gridHeight);\n      let logMask = new Uint8Array(gridWidth * gridHeight);\n      let dt = 0.07;\n      const diffusionTemp = 0.1;\n      const diffusionSmoke = 0.08;\n      const simulationTicks = 3;\n      let simTime = 0;\n      function getFireColor(t) {\n        t = Math.max(0, Math.min(1, t));\n        if (t < 0.2) return `rgb(50, 0, 0)`;\n        if (t < 0.4) return `rgb(200, 0, 0)`;\n        if (t < 0.6) return `rgb(255, 100, 0)`;\n        if (t < 0.8) return `rgb(255, 200, 50)`;\n        return `rgb(255, 255, 200)`;\n      }\n      function updateSimulation() {\n        simTime += dt;\n        for (let i = 0; i < temp.length; i++) {\n          temp[i] *= 0.98;\n          if (Math.random() < 0.02) temp[i] += 0.5;\n        }\n      }\n      function draw() {\n        const cellWidth = canvas.width / gridWidth;\n        const cellHeight = canvas.height / gridHeight;\n        ctx.clearRect(0, 0, canvas.width, canvas.height);\n        for (let y = 0; y < gridHeight; y++) {\n          for (let x = 0; x < gridWidth; x++) {\n            const index = x + y * gridWidth;\n            ctx.fillStyle = getFireColor(temp[index]);\n            ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);\n          }\n        }\n      }\n      function loop() {\n        for (let i = 0; i < simulationTicks; i++) updateSimulation();\n        draw();\n        requestAnimationFrame(loop);\n      }\n      for (let i = 0; i < 500; i++) temp[Math.floor(Math.random() * temp.length)] = 1;\n      requestAnimationFrame(loop);\n    })();\n  </script>\n</body>\n</html>","created_at":"2025-02-16T17:45:19.690Z","url":"https://quickhtml.app/campfire-simulation"},{"id":202,"app_id":167,"version":2,"html":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n    <title>WebGL Campfire Smoke</title>\n    <style>\n        body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: black; overflow: hidden; }\n        canvas { width: 80vw; height: 80vw; max-width: 512px; max-height: 512px; image-rendering: pixelated; }\n        #error-log { position: fixed; top: 10px; left: 50%; transform: translateX(-50%); background: rgba(255, 0, 0, 0.8); color: white; padding: 10px; font-family: monospace; display: none; }\n    </style>\n</head>\n<body>\n    <canvas id=\"canvas\" width=\"64\" height=\"64\"></canvas>\n    <div id=\"error-log\"></div>\n    <script>\n        (function() {\n            const errorLog = document.getElementById(\"error-log\");\n            window.onerror = function(message) {\n                errorLog.textContent = message;\n                errorLog.style.display = \"block\";\n            };\n        })();\n    </script>\n    <script>\n        (async function(){\n            const canvas = document.getElementById('canvas');\n            const gl = canvas.getContext('webgl2');\n            if(!gl){ alert(\"WebGL2 not supported\"); return; }\n            const N = 64;\n            const px = 1.0 / N;\n            let dt = 0.16;\n            gl.getExtension('EXT_color_buffer_float');\n            const vsSource = `#version 300 es\n                precision highp float;\n                out vec2 vTex;\n                void main() {\n                    float x = (float((gl_VertexID & 1) * 2 - 1));\n                    float y = (float(((gl_VertexID >> 1) & 1) * 2 - 1));\n                    vTex = vec2((x+1.0)*0.5, (y+1.0)*0.5);\n                    gl_Position = vec4(x, y, 0, 1);\n                }`;\n            const fsRender = `#version 300 es\n                precision highp float;\n                in vec2 vTex;\n                out vec4 outColor;\n                void main() {\n                    vec3 bgColor = vec3(0.0, 0.0, 0.1);\n                    outColor = vec4(bgColor, 1.0);\n                }`;\n            function compileShader(src, type){\n                const shader = gl.createShader(type);\n                gl.shaderSource(shader, src);\n                gl.compileShader(shader);\n                if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){\n                    console.error(gl.getShaderInfoLog(shader));\n                    throw new Error(\"Shader compile failed\");\n                }\n                return shader;\n            }\n            function createProgram(vsSrc, fsSrc){\n                const vs = compileShader(vsSrc, gl.VERTEX_SHADER);\n                const fs = compileShader(fsSrc, gl.FRAGMENT_SHADER);\n                const prog = gl.createProgram();\n                gl.attachShader(prog, vs);\n                gl.attachShader(prog, fs);\n                gl.linkProgram(prog);\n                if(!gl.getProgramParameter(prog, gl.LINK_STATUS)){\n                    console.error(gl.getProgramInfoLog(prog));\n                    throw new Error(\"Program link failed\");\n                }\n                return prog;\n            }\n            const progRender = createProgram(vsSource, fsRender);\n            gl.useProgram(progRender);\n            function render() {\n                gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n                requestAnimationFrame(render);\n            }\n            render();\n        })();\n    </script>\n</body>\n</html>","created_at":"2025-02-16T18:02:35.038Z","url":"https://quickhtml.app/fire-simulation"}]