Draw Pixel Art with Vanilla JS
Posted on Jul 15, 2026
Hi there! I\'m a frontend developer and learning to become a game developer. I got very stuck when searching for art and sprites for my game, so I decided to draw them with my JavaScript skills. Here is my approach — it\'s very simple and requires zero dependencies:
Prepare a Canvas Element
<div style="width: 100vw; height: 100vh; display: flex; justify-content: center; align-items: center;">
<div>
<canvas id="canvas" width="512" height="512" style="width: 512px; height: 512px;"></canvas>
</div>
</div>
Define Your Color Palette
const colors = [
"#c6bfbe", // 0 - light gray
"#040309", // 1 - black
"#e0e6e9", // 2 - white
"#9d919d", // 3 - gray
"#b0813f", // 4 - brown
"#cf7f33", // 5 - orange
"#adb6b1", // 6 - greenish gray
"#1d1f29" // 7 - dark blue
];
Create the Pixel Map
Each key follows the format x_y and maps to a color index from the palette:
const pixelMap = {
"2_3": 1,
"2_4": 1,
"2_5": 1,
"2_6": 1,
"2_8": 1,
"2_9": 1,
"3_3": 1,
"3_4": 3,
"3_5": 1,
"3_6": 4,
"3_7": 1,
"3_8": 6,
"3_9": 0,
"4_2": 1,
"4_3": 1,
"4_4": 1,
"4_5": 1,
"4_6": 4,
"4_7": 1,
"4_8": 1,
"4_9": 1,
"5_2": 1,
"5_3": 2,
"5_4": 1,
"5_5": 1,
"5_6": 1,
"5_7": 2,
"5_8": 1,
"5_9": 1,
"6_2": 1,
"6_3": 1,
"6_4": 1,
"6_5": 1,
"6_6": 1,
"6_7": 1,
"6_8": 1,
"6_9": 1,
"7_3": 1,
"7_4": 5,
"7_5": 1,
"7_6": 1,
"7_7": 5,
"7_8": 1,
"8_4": 1,
"8_5": 1,
"8_6": 1,
"8_7": 1
};
Draw the Pixel Art
const canvas = document.getElementById("canvas");
const size = 16; // 16x16 grid
const baseSize = Math.round(canvas.width / size);
const ctx = canvas.getContext("2d");
// Fill background
ctx.fillStyle = "#F0F0F0";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw each pixel
for (const key in pixelMap) {
const [x, y] = key.split("_");
ctx.fillStyle = colors[pixelMap[key]];
ctx.fillRect(+x * baseSize, +y * baseSize, baseSize, baseSize);
}
Tada! Here is the result — a simple pixel character drawn entirely with vanilla JavaScript:
Make It Interactive
Let\'s add a click-to-draw feature so users can create their own pixel art:
let currentColor = 1; // Default to black
let isDrawing = false;
// Handle mouse events
canvas.addEventListener("mousedown", () => isDrawing = true);
canvas.addEventListener("mouseup", () => isDrawing = false);
canvas.addEventListener("mouseleave", () => isDrawing = false);
canvas.addEventListener("mousemove", (e) => {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
const x = Math.floor((e.clientX - rect.left) / baseSize);
const y = Math.floor((e.clientY - rect.top) / baseSize);
ctx.fillStyle = colors[currentColor];
ctx.fillRect(x * baseSize, y * baseSize, baseSize, baseSize);
// Update pixel map
pixelMap[`${x}_${y}`] = currentColor;
});
// Color picker
const colorButtons = document.createElement("div");
colorButtons.style.display = "flex";
colorButtons.style.gap = "8px";
colorButtons.style.marginTop = "16px";
colors.forEach((color, index) => {
const btn = document.createElement("button");
btn.style.width = "32px";
btn.style.height = "32px";
btn.style.backgroundColor = color;
btn.style.border = index === currentColor ? "3px solid #333" : "1px solid #ccc";
btn.style.cursor = "pointer";
btn.onclick = () => {
currentColor = index;
// Update border styles
Array.from(colorButtons.children).forEach((b, i) => {
b.style.border = i === index ? "3px solid #333" : "1px solid #ccc";
});
};
colorButtons.appendChild(btn);
});
document.body.appendChild(colorButtons);
Export Your Creation
function exportPixelArt() {
const link = document.createElement("a");
link.download = "my-pixel-art.png";
link.href = canvas.toDataURL("image/png");
link.click();
}
// Add export button
const exportBtn = document.createElement("button");
exportBtn.textContent = "Export PNG";
exportBtn.style.marginTop = "16px";
exportBtn.style.padding = "8px 16px";
exportBtn.onclick = exportPixelArt;
document.body.appendChild(exportBtn);
Load Pixel Art from JSON
function loadPixelArt(jsonData) {
// Clear canvas
ctx.fillStyle = "#F0F0F0";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw from data
for (const key in jsonData) {
const [x, y] = key.split("_");
ctx.fillStyle = colors[jsonData[key]];
ctx.fillRect(+x * baseSize, +y * baseSize, baseSize, baseSize);
}
}
// Example: load a predefined sprite
const mushroomSprite = {
"6_4": 1, "7_4": 1, "8_4": 1,
"5_5": 1, "6_5": 2, "7_5": 2, "8_5": 2, "9_5": 1,
"4_6": 1, "5_6": 2, "6_6": 2, "7_6": 2, "8_6": 2, "9_6": 2, "10_6": 1,
"4_7": 1, "5_7": 1, "6_7": 1, "7_7": 1, "8_7": 1, "9_7": 1, "10_7": 1,
"6_8": 4, "7_8": 4, "8_8": 4,
"6_9": 4, "7_9": 4, "8_9": 4,
"6_10": 4, "7_10": 4, "8_10": 4
};
// Uncomment to draw: loadPixelArt(mushroomSprite);
Tools to Speed Up Your Pixel Art Workflow
Building pixel art from code is fun, but sometimes you need a visual grid to plan your designs first. Check out Pixel Art Grid — a free online tool with customizable grids for sketching pixel art before coding it. Perfect for planning sprites, icons, and game assets.
Want to turn your pixel art into a spiral wall poster? Spiral Betty takes any image and transforms it into a stunning spiral design using Canvas-based processing — great for gifts and room decor.
For tabletop RPG fans, Token Maker lets you generate circular and square VTT tokens with custom borders and frames. All rendered with Canvas, just like the code above.
Also try Spiral Betty for an alternative spiral effect with additional filter options.
You can get more pixel art data by inspecting APIs from Pixel Art Grid. I welcome that!
Full source code available. Happy pixel drawing!

Top comments (0)