Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

An art studio fanart game where you get to work as an artist assistant!

By irl La Brava If building the etch a sketch was the base to figure out how to bring my vision to life, this self-imposed project was another that was about making another dream come true! Previously, in the etch a ske

By irl La Brava

If building the etch a sketch was the base to figure out how to bring my vision to life, this self-imposed project was another that was about making another dream come true! Previously, in the etch a sketch- it was all about combining clean vanilla Javascript loops, precise event listeners, and strict resource safeguards. And, here? Here, we bring a responsive, snappy sketchbook canvas to suck you in, and make you feel as if you were inside the canvas itself!

Make no mistake! This is no regular artistic canvas that you get to be sucked in! This is a professional one where you get to work as an assistant for Shiina from akurasou no Pet na Kanojo. When you work for her, you get to be in a wholesome sanctuary, as you have never been before! Yes, I took everything from the foundations curriculum, and turned them into fanart projects! Others only do the projects to fulfill the assignment. While others also do it with hiring in mind. While I do it to make my dreams come true! The things that I always wanted to do, what aligns with my values, what matters, the feelings that they represent.

This one of a kind fanart game has 350 levels that you can go through. At first, I envisioned 50 levels, but as I kept going, I realised that it was not enough, nor rich an experience enough, so I dedicated myself to make it feel the way it should. What for? To go through a whole journey with Shiina, not just in drawing, but also emotionally. A sprawling, 350-stage progression canvas complete with custom multi-tool mechanics, DOM color swatches, local persistence, an embedded soundtrack player, and a floating Mashiro companion who watches your every stroke.

Without further ado, allow me to show you the technical breakdown behind this process to make my dream come to life:

1//The Blueprint: Modular Architecture and Vanilla Purity

In an era where modern web development is suffocated by heavy build tools, bundlers, and complex node modules, returning to vanilla JavaScript, HTML5, and CSS3 feels like clearing a dense fog.
The project structure was deliberately kept clean, modular, and transparent:
• index.html: The semantic markup housing the toolbar, canvas container, dialogue HUD, and global background music player.
• style.css: A dark, gothic-tinged aesthetic (#121212 base) accented by Shiina pink (#e5989b) and muted grays, completely free of external CSS frameworks.
• game.js: The core state machine handling level progression, local storage persistence, name acquisition, and pixel-coverage validation.
• app.js: The low-level canvas rendering engine managing drawing contexts, stroke types, undo stacks, and PNG exports.
• levels.js: The expansive database mapping out 350 unique stages of artistic progression and dialogue triggers.

2// Conquering the Void: Bypassing Transient Activation

Every custom engine hits roadblocks, and ours arrived early when handling the first-stroke name acquisition prompt.
Originally, we relied on the browser's native prompt() triggered inside a canvas drawing event (mousedown or touch). But modern browser security policies enforce strict Transient User Activation rules. Because a canvas stroke doesn't always register as a high-level form interaction in the eyes of browser heuristics, the native prompt gets silently swallowed and blocked.
Instead of accepting this automated interference, we engineered a custom in-app HTML modal overlay:
1. The UI Layer: An absolute-positioned backdrop (#name-modal) featuring a clean input card styled directly into our dark theme.
2. The Event Flow: When the player makes their first stroke, GameManager intercepts it, pauses execution, displays the modal, and waits for a deliberate string entry.
3. The Persistence Layer: Once entered, the name is sanitized, bound to this.playerName, and saved to localStorage so the user is never badgered twice unless they manually reset their progress.
JavaScript
checkFirstStrokePrompt() {
if (this.playerName && this.playerName.trim() !== '') return;
if (this.hasPromptedForName) return;

this.hasPromptedForName = true;
const modal = document.getElementById('name-modal');
const input = document.getElementById('modal-name-input');
const btn = document.getElementById('modal-submit-btn');

modal.style.display = 'flex';
input.focus();

const handleSave = () => {
const entered = input.value.trim();
this.playerName = entered ? entered : "Assistant";
localStorage.setItem('shiina_player_name', this.playerName);
modal.style.display = 'none';
this.loadLevel(this.currentLevel);
};

btn.onclick = handleSave;
input.onkeydown = (e) => { if (e.key === 'Enter') handleSave(); };
}

3// Pixel Math: Validating Art Across 350 Stages

An Etch a Sketch app is fun, but giving it a progression system transforms it into a game of composition. We structured levels.js to scale across 350 distinct stages, each requiring a specific threshold of canvas coverage before allowing the artist to advance.
How do you programmatically grade a drawing on an HTML5 canvas? By inspecting the pixel buffer directly using getImageData():
JavaScript
const canvasCtx = canvas.getContext('2d');
const imageData = canvasCtx.getImageData(0, 0, canvas.width, canvas.height);
const pixels = imageData.data;

let paintedPixels = 0;
const totalPixels = pixels.length / 4;

for (let i = 0; i < pixels.length; i += 4) {
const r = pixels[i];
const g = pixels[i + 1];
const b = pixels[i + 2];

// Check if pixel deviates from the clean white background
if (r < 240 || g < 240 || b < 240) {
paintedPixels++;
}
}

const coveragePercentage = (paintedPixels / totalPixels) * 100;
If the calculated coveragePercentage meets or exceeds the threshold defined in the current level data, Shiina approves the composition, saves the state to localStorage, and advances the stage. If not, she offers character-driven feedback demanding more from the canvas.

4// Crafting the Atmosphere: Audio, Styling, and Companions

Code is only half the equation; atmosphere is what gives an application a soul.
• The Soundtrack: We embedded a persistent background audio bar running the iconic Sakurasou theme, anchoring the user in the emotional resonance of the series while they code and draw.
• The Companion Widget: A floating Chibi Mashiro image positioned alongside the canvas (#mashiro-companion), utilizing keyframe animations (@keyframes mashiro-float) to give the illusion that she is quietly observing your progress from the corner of the screen.
• The Tools: Solid lines, pencil textures, and airbrush shade modes give the artist genuine creative flexibility, supported by DOM color swatches and a custom color picker input.

5//Final Thoughts

So, that is the technical base idea that was needed to make it happen. Building Shiina's studio, getting into her work, working for her as an artist is not about chasing fake algorithms, metrics that have no meaning, pursuing art to appease the masses, a fake applause- No! None of that. It is all for one sole purpose: to create art that feels alive, become one with it, and experience a whole new world like you would never would do otherwise! It is about merging Javascript to create soft whispers of delicate strokes with artists like Shiina. And those stroke brushes? Those stroke burshes were made with code!

Lastly, because I could not incorporate the official music inside ,due to copyright reasons, once more, at some point, I redid everything, and just embeded Shiina singing "Nande". So, go, and tell Shiina why you want to draw!

(Just gotta make sure that everything is committed) You can definitely see it for yourself, and become Shiina's assistant: https://labrava0x.github.io/shiina.canvas.studio/

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.