Setting up the stage with the etch a sketch project
By irl La Brava
Part of the rite in passage of The Odin Project´s curriculum in foundations was the etch a sketch. Before moving forward, you learn how to make basic drawings, but not in already existing applications, but as your very own to host! Such was the case with this assignment.
On paper, it sounds deceptively simple: build a browser-based drawing pad where a user can sketch across a grid of squares. But when you approach it not as a checkbox assignment, but as a deliberate exercise in DOM manipulation, event handling, and memory architecture. What is this for? To just check off another project assignment? You are wrong! This is but another part of the process to set up the stage that will lead to transform yourself into a masterpiece, into a masterclass in front-end engineering, into something out of this world, and beyond!
Without further ado, let me present you with the technical aspect that makes the etch a sketch possible:
1 //The Core Challenge: Dynamic DOM Grid Generation
The primary architectural constraint mandated by the curriculum is deceptively strict: you cannot hard-code your grid into the HTML. Typing out hundreds of individual square
elements by hand is an anti-pattern; instead, the browser needs to construct the entire field programmatically via JavaScript.To accomplish this cleanly, we engineered a dynamic grid generator function that accepts a dimension parameter ($N \times N$) and populates a parent container using CSS Flexbox:
JavaScript
function createGrid(size) {
const container = document.getElementById('sketch-container');
container.innerHTML = ''; // Clear any existing grid
// Set CSS custom properties for dynamic sizing
container.style.setProperty('--grid-size', size);
const totalSquares = size * size;
for (let i = 0; i < totalSquares; i++) {
const square = document.createElement('div');
square.classList.add('grid-square');
// Attach event listeners for the drawing trail
square.addEventListener('mouseenter', paintSquare);
container.appendChild(square);
}
}
By calculating flex-basis dynamically based on the requested side length, the layout scales fluidly without breaking container bounds or triggering unwanted layout shifts.
2// Event Routing and Mouse-State Management
Handling hover states across thousands of dynamically generated DOM elements requires efficient event delegation or direct listener binding. To simulate the classic physical resistance and continuous stroke of a real mechanical drawing toy, we track mouse down/up states globally:
JavaScript
let isMouseDown = false;
document.body.addEventListener('mousedown', () => { isMouseDown = true; });
document.body.addEventListener('mouseup', () => { isMouseDown = false; });
function paintSquare(e) {
// Only paint if the mouse button is actively held down
if (!isMouseDown && e.type === 'mouseenter') return;
// Apply dynamic color or progressive shading logic here
this.style.backgroundColor = getCurrentBrushColor();
}
This prevents accidental trailing smears and ensures the user feels absolute tactical control over every stroke they lay down on the grid.
3. Implementing Progressive Shading and Color Dynamics
To elevate the project beyond a basic black-and-white grid, we incorporated advanced drawing modes—paying homage to classic sketching techniques:
• Randomized RGB Mode: Assigns a completely random hex or rgb value on every mouseover event, turning the canvas into a vibrant mosaic.
• Progressive Darkening (The 10-Pass Opacity Rule): Mimics real charcoal or graphite buildup by incrementing the element's darkness by 10% on each successive pass until it reaches pure black:
JavaScript
function applyProgressiveShading(square) {
let currentOpacity = parseFloat(square.style.opacity) || 0;
if (currentOpacity < 1) {
currentOpacity += 0.1;
square.style.opacity = currentOpacity;
square.style.backgroundColor = '#000000';
}
}
4 //Guarding System Resources: Input Validation
Allowing users to customize their grid dimensions via a prompt sounds harmless until someone types 1000, instantly injecting one million DOM elements into the document and bringing the browser thread to a grinding halt.
To protect system performance—especially when running on lightweight Linux setups or constrained hardware—we implemented strict input validation and a hard performance ceiling (capping grids at $100 \times 100$):
JavaScript
function promptForNewGrid() {
let input = prompt("Enter squares per side (Maximum 100):", "16");
let size = parseInt(input);
if (isNaN(size) || size <= 0) {
alert("Please enter a valid positive number.");
return;
}
if (size > 100) {
alert("Canvas limit is 100x100 to protect browser memory performance.");
size = 100;
}
createGrid(size);
}
5//Final words, for prepping a new code:
Creating a Etch a sketch, is not another assignment to mark as completed, in the curriculum, it is about learning how to create art. Because html is not just html, and the DOM needs to be properly structured, and respected to get the desired results.
Top comments (0)