Meta Description" name="description" />

Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Cascading Grid Mechanic</title> <style> body { background-color: #1a1a1a; color: #ffffff; font-family: sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; } canvas { border: 4px solid #ffd700; background-color: #111; box-shadow: 0 0 20px rgba(255, 215, 0, 0.3); } .controls { margin-top: 15px; text-align: center; } button { background: linear-gradient(#ffd700, #ffae00); border: none; padding: 12px 24px; font-size: 16px; font-weight: bold; color: #111; border-radius: 5px; cursor: pointer; box-shadow: 0 4px 6px rgba(0,0,0,0.3); } button:hover { background: #ffd700; } .score-board { font-size: 20px; margin-bottom: 10px; font-weight: bold; color: #ffd700; } </style> </head> <body> <div class="score-board">Score: <span id="score">0</span> | Combo: x<span id="multiplier">1</span></div> <canvas id="gameCanvas" width="400" height="500"></canvas> <div class="controls"> <button id="actionBtn">Check Matches / Cascade</button> </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const multEl = document.getElementById('multiplier'); const actionBtn = document.getElementById('actionBtn'); // Grid Configuration (Mobile portrait aspect ratio) const ROWS = 5; const COLS = 4; const TILE_SIZE = 100; // Symbol pool with visual definitions const SYMBOLS = { 1: { name: 'A', color: '#ff4d4d', textColor: '#fff' }, // Red 2: { name: 'B', color: '#4da6ff', textColor: '#fff' }, // Blue 3: { name: 'C', color: '#5cd65c', textColor: '#111' }, // Green 4: { name: 'D', color: '#e6b800', textColor: '#111' } // Yellow }; let grid = []; let score = 0; let multiplier = 1; let isAnimating = false; // Initialize grid with random symbols function initGrid() { grid = []; for (let r = 0; r < ROWS; r++) { grid[r] = []; for (let c = 0; c < COLS; c++) { grid[r][c] = getRandomSymbol(); } } } function getRandomSymbol() { const keys = Object.keys(SYMBOLS); return parseInt(keys[Math.floor(Math.random() * keys.length)]); } // Render the grid to the Canvas function drawGrid() { ctx.clearRect(0, 0, canvas.width, canvas.height); for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { const symbolId = grid[r][c]; const x = c * TILE_SIZE; const y = r * TILE_SIZE; if (symbolId !== 0) { // 0 means empty space const sym = SYMBOLS[symbolId]; // Draw tile background ctx.fillStyle = sym.color; ctx.fillRect(x + 4, y + 4, TILE_SIZE - 8, TILE_SIZE - 8); // Draw symbol character text ctx.fillStyle = sym.textColor; ctx.font = 'bold 32px sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(sym.name, x + TILE_SIZE / 2, y + TILE_SIZE / 2); } else { // Empty block background style ctx.fillStyle = '#222'; ctx.fillRect(x + 4, y + 4, TILE_SIZE - 8, TILE_SIZE - 8); } } } } // Phase 1: Scan grid for 3-in-a-row matches horizontally function scanMatches() { let matched = []; // Initialize blank tracking array mirroring layout for (let r = 0; r < ROWS; r++) { matched[r] = new Array(COLS).fill(false); } let hasMatches = false; // Check Horizontal matches for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS - 2; c++) { let id1 = grid[r][c]; let id2 = grid[r][c+1]; let id3 = grid[r][c+2]; if (id1 !== 0 && id1 === id2 && id1 === id3) { matched[r][c] = true; matched[r][c+1] = true; matched[r][c+2] = true; hasMatches = true; } } } // Apply match deletions (set to 0) and reward calculation if (hasMatches) { let matchCount = 0; for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { if (matched[r][c]) { grid[r][c] = 0; // Cleared status matchCount++; } } } score += matchCount * 10 * multiplier; multiplier += 1; // Step up combo mechanics multiplier scoreEl.innerText = score; multEl.innerText = multiplier; } return hasMatches; } // Phase 2: Shift columns down (Gravity processing) and drop new elements down function applyGravity() { for (let c = 0; c < COLS; c++) { // Collect all surviving blocks in this column from bottom to top let survivalArray = []; for (let r = ROWS - 1; r >= 0; r--) { if (grid[r][c] !== 0) { survivalArray.push(grid[r][c]); } } // Fill up remaining missing spaces with fresh random tiles while (survivalArray.length < ROWS) { survivalArray.push(getRandomSymbol()); } // Write the packed items back into the column structure let index = 0; for (let r = ROWS - 1; r >= 0; r--) { grid[r][c] = survivalArray[index]; index++; } } } // Logic sequencer processing loop function processTurn() { if (isAnimating) return; isAnimating = true; actionBtn.disabled = true; // 1. Scan for matching layouts const foundMatches = scanMatches(); drawGrid(); if (foundMatches) { actionBtn.innerText = "Cascading..."; // Pause briefly so user can visualize matching elements vanishing setTimeout(() => { // 2. Drop pieces down via gravity simulation logic applyGravity(); drawGrid(); isAnimating = false; actionBtn.disabled = false; actionBtn.innerText = "Check Next Cascade"; }, 600); } else { // Reset state mechanics if sequence breaks without wins multiplier = 1; multEl.innerText = multiplier; isAnimating = false; actionBtn.disabled = false; actionBtn.innerText = "Spin Again / Check"; initGrid(); // Refresh layout to continue testing demo loop seamlessly setTimeout(drawGrid, 200); } } // Initialization execute trigger actionBtn.addEventListener('click', processTurn); initGrid(); drawGrid(); </script> </body> </html>
Landing Page
This ad does not have a landing page available
Network Timeline
Performance Summary

1

Requests

1

Domains

8KB

Transfer Size

8KB

Content Size

73.0ms

Dom Content Loaded

132.0ms

First Paint

73.0ms

Load Time
Domain Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...
Timings (ms)
Loading...
Total Time
Loading...
Content Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...