AquaMotion
by Sharxxy
HTML
<h1>AquaMotion 🎨</h1>
<div id="toolbar">
<button id="drawBtn">✏️ Draw</button>
<button id="eraseBtn">🩹 Erase</button>
<input type="color" id="colorPicker" value="#0077ff">
<input type="range" id="brushSize" min="2" max="30" value="6">
<button id="newFrame">➕ Frame</button>
<button id="deleteFrame">🗑️ Delete Frame</button>
<button id="play">▶️ Play</button>
<label>FPS: <input type="number" id="fps" value="6" min="1" max="24"></label>
</div>
<canvas id="drawCanvas" width="800" height="500"></canvas>
<div id="frames"></div>
CSS
body {
font-family: Arial, sans-serif;
background: #e0f7fa;
color: #0077ff;
display: flex;
flex-direction: column;
align-items: center;
padding: 1rem;
}
h1 {
margin-bottom: 1rem;
}
#toolbar {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
#toolbar button {
padding: 0.4rem 0.7rem;
}
canvas {
border: 2px solid #0077ff;
background: #ffffff;
cursor: crosshair;
}
#frames {
margin-top: 1rem;
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.frame {
width: 60px;
height: 40px;
border: 1px solid #aaa;
background: #ffffff;
display: flex;
justify-content: center;
align-items: center;
font-size: 0.7rem;
cursor: pointer;
}
.frame.active {
border: 2px solid #0077ff;
}
JavaScript
const canvas = document.getElementById("drawCanvas");
const ctx = canvas.getContext("2d");
let tool = "draw";
let color = document.getElementById("colorPicker").value;
let brushSize = 6;
let drawing = false;
let frames = [[]];
let currentFrame = 0;
let fps = 6;
let playing = false;
let currentPath = null;
// DRAWING FUNCTIONS
function startDraw(e) {
drawing = true;
currentPath = {
color: tool === "erase" ? "erase" : color,
size: brushSize,
points: [{ x: e.offsetX, y: e.offsetY }]
};
}
function drawMove(e) {
if (!drawing) return;
currentPath.points.push({ x: e.offsetX, y: e.offsetY });
redraw();
}
function endDraw() {
if (drawing && currentPath) frames[currentFrame].push(currentPath);
currentPath = null;
drawing = false;
}
function drawPath(path) {
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.lineWidth = path.size;
ctx.beginPath();
ctx.moveTo(path.points[0].x, path.points[0].y);
path.points.forEach(p => ctx.lineTo(p.x, p.y));
if (path.color === "erase") {
ctx.globalCompositeOperation = "destination-out";
ctx.strokeStyle = "rgba(0,0,0,1)";
} else {
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = path.color;
}
ctx.stroke();
}
function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
frames[currentFrame].forEach(drawPath);
if (currentPath) drawPath(currentPath);
// Onion skin previous frame
if (frames[currentFrame - 1]) {
ctx.save();
ctx.globalAlpha = 0.3;
frames[currentFrame - 1].forEach(drawPath);
ctx.restore();
}
}
// TOOLBAR EVENTS
document.getElementById("drawBtn").onclick = () => tool = "draw";
document.getElementById("eraseBtn").onclick = () => tool = "erase";
document.getElementById("colorPicker").oninput = (e) => color = e.target.value;
document.getElementById("brushSize").oninput = (e) => brushSize =...