For Melon Playground | Pixel Art Maker

// draw entire pixel matrix onto canvas function drawFullMatrix() if(!pixelMatrix.length) return; const size = currentGridSize; for(let row = 0; row < size; row++) for(let col = 0; col < size; col++) const color = pixelMatrix[row][col]; ctx.fillStyle = color; ctx.fillRect(col * cellW, row * cellH, cellW, cellH); // optional: draw subtle grid lines ctx.save(); ctx.beginPath(); ctx.strokeStyle = "#2c3e4e"; ctx.lineWidth = 0.5; for(let i = 0; i <= size; i++) ctx.beginPath(); ctx.moveTo(i * cellW, 0); ctx.lineTo(i * cellW, canvas.height); ctx.stroke(); ctx.moveTo(0, i * cellH); ctx.lineTo(canvas.width, i * cellH); ctx.stroke(); ctx.restore();

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <title>Pixel Art Maker for Melon Playground</title> <style> * box-sizing: border-box; user-select: none; /* avoid accidental text selection while drawing */

// ---------- Event listeners for drawing (mouse + touch) ---------- function handlePointerStart(e) e.altKey

// painting logic (color or erase) function paintAtEvent(e, forceErase = false) eraseMode; const row, col = getGridCoordFromEvent(e); if(row >= 0 && row < currentGridSize && col >=0 && col < currentGridSize) let newColor; if(useErase) newColor = DEFAULT_BG; else newColor = colorPicker.value; setPixel(row, col, newColor); pixel art maker for melon playground

// get mouse / touch coordinates to grid cell function getGridCoordFromEvent(e) const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; // canvas physical vs CSS const scaleY = canvas.height / rect.height; let clientX, clientY; if(e.touches) // touch event clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; else clientX = e.clientX; clientY = e.clientY; let canvasX = (clientX - rect.left) * scaleX; let canvasY = (clientY - rect.top) * scaleY; canvasX = Math.min(Math.max(0, canvasX), canvas.width - 0.01); canvasY = Math.min(Math.max(0, canvasY), canvas.height - 0.01); const col = Math.floor(canvasX / cellW); const row = Math.floor(canvasY / cellH); return row, col ;

<!-- canvas grid container --> <div class="canvas-area"> <canvas id="pixelCanvas" width="320" height="320" style="image-rendering: crisp-edges; image-rendering: pixelated; image-rendering: pixelated; width: 320px; height: 320px;"></canvas> </div>

.pixel-art-studio background: #2c2e3a; border-radius: 1.8rem; padding: 1.2rem; box-shadow: inset 0 0 8px #00000030, 0 10px 20px rgba(0,0,0,0.3); // draw entire pixel matrix onto canvas function

/* Main card container */ .maker-container background: rgba(30, 40, 50, 0.75); backdrop-filter: blur(2px); border-radius: 2.5rem; padding: 1.5rem; box-shadow: 0 20px 35px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1); border: 1px solid rgba(255,215,150,0.3);

#currentColorPicker width: 48px; height: 48px; border: 3px solid white; border-radius: 50%; cursor: pointer; background: #ff44aa; box-shadow: 0 2px 8px black; transition: transform 0.1s ease; #currentColorPicker:active transform: scale(0.95);

<script> (function() // ---------- DOM elements ---------- const canvas = document.getElementById('pixelCanvas'); const ctx = canvas.getContext('2d'); const gridSizeSelect = document.getElementById('gridSizeSelect'); const clearBtn = document.getElementById('clearCanvasBtn'); const fillBgBtn = document.getElementById('fillCanvasBtn'); const exportPngBtn = document.getElementById('exportPNG'); const exportJsonBtn = document.getElementById('exportSpriteData'); const colorPicker = document.getElementById('activeColor'); const colorPreview = document.getElementById('currentColorPicker'); const floodFillActiveBtn = document

footer font-size: 0.7rem; text-align: center; color: #8aaec0; margin-top: 12px;

.sub text-align: center; font-size: 0.8rem; color: #bbccdd; margin-bottom: 1.2rem; border-bottom: 1px dashed #ffb34755; display: inline-block; width: 100%; font-family: monospace;

<!-- tools --> <div class="tools-panel"> <div class="color-well"> <span class="color-label">🎨 COLOR</span> <input type="color" id="activeColor" value="#FFAA44"> <div id="currentColorPicker" style="background: #FFAA44;"></div> </div> <div class="size-control"> <span>🔲 GRID</span> <select id="gridSizeSelect"> <option value="16">16x16 (classic)</option> <option value="24">24x24 (detailed)</option> <option value="32" selected>32x32 (melon style)</option> <option value="48">48x48 (big art)</option> </select> </div> <button id="clearCanvasBtn" class="btn btn-danger">🗑️ CLEAR ALL</button> <button id="fillCanvasBtn" class="btn">🪣 FILL BG</button> </div>

function handlePointerEnd(e) isDrawing = false; // reset erase mode to default (based on next click, no persistent) eraseMode = false;

// additional: fill with selected color as bucket from button? add a new button? but we already have fill BG (background only) // Also we can add a "flood fill active color" button. const floodFillActiveBtn = document.createElement('button'); // we inject it elegantly into tools panel, but i'll just add near export for extra tool, but we can include without overclutter: let's modify tools panel // get tools panel and insert new button const toolsDiv = document.querySelector('.tools-panel'); const fillActiveBtn = document.createElement('button'); fillActiveBtn.innerText = '🪣 FLOOD FILL (active)'; fillActiveBtn.className = 'btn'; fillActiveBtn.style.background = '#5a4a2e'; fillActiveBtn.addEventListener('click', () => // prompt for which color? we need a target pixel? simplest: fill whole canvas? no, flood fill requires seed. // We'll make it interactive: click on canvas after pressing flood mode? easier: show message. alert('🔮 Double-click on any pixel to flood fill with current color! (or use the FILL BG button for full background)'); ); toolsDiv.appendChild(fillActiveBtn); // but also update fill BG: keep original fill background using default bg. // override fillBgBtn to fill canvas with DEFAULT_BG fillBgBtn.onclick = () => fillAllWithColor(DEFAULT_BG); ; // clear canvas clearBtn.onclick = () => clearCanvas(); ; // export PNG (scaled up to show pixels) function exportAsPNG() // we can export current canvas exactly as is, but we might also scale for better preview? But it's fine. const link = document.createElement('a'); link.download = `melon_pixelart_$currentGridSizex$currentGridSize.png`; link.href = canvas.toDataURL('image/png'); link.click(); // export sprite data (JSON matrix colors, also ready for melon playground community) function exportJSON() const exportObj = meta: tool: "Melon Playground Pixel Art Maker", gridSize: currentGridSize, paletteHint: "each cell holds hex color" , pixels: pixelMatrix.map(row => [...row]) ; const jsonStr = JSON.stringify(exportObj, null, 2); // copy to clipboard navigator.clipboard.writeText(jsonStr).then(() => alert(`✅ Sprite data ($currentGridSizex$currentGridSize) copied as JSON!\nYou can share or import later.`); ).catch(() => alert("⚠️ Could not copy, but you can use PNG export instead."); ); // color picker preview sync function updateColorPreview() const newColor = colorPicker.value; colorPreview.style.background = newColor; colorPicker.addEventListener('input', updateColorPreview); updateColorPreview(); // grid change event gridSizeSelect.addEventListener('change', changeGridSize); // ---- Mouse / touch event binding ---- canvas.addEventListener('mousedown', handlePointerStart); window.addEventListener('mousemove', handlePointerMove); window.addEventListener('mouseup', handlePointerEnd); // touch events canvas.addEventListener('touchstart', handlePointerStart, passive: false); canvas.addEventListener('touchmove', handlePointerMove, passive: false); canvas.addEventListener('touchend', handlePointerEnd); canvas.addEventListener('contextmenu', disableContextMenu); canvas.addEventListener('dblclick', handleCanvasDoubleClick); // additional keyboard: hold E to erase? optional, but we can set alt/ctrl handled already. // final initialisation function init() currentGridSize = 32; gridSizeSelect.value = "32"; pixelMatrix = initMatrix(currentGridSize, DEFAULT_BG); resizeAndRedraw(); // export listeners exportPngBtn.addEventListener('click', exportAsPNG); exportJsonBtn.addEventListener('click', exportJSON); init(); )(); </script> </body> </html>