AquaMotion
by Sharxxy
HTML
<div style="display:flex; height:100%;">
<div id="toolbar">
<button data-tool="pencil" class="active">✏️</button>
<button data-tool="eraser">🩹</button>
<button data-tool="line">➖</button>
<button data-tool="rect">⬛</button>
<button data-tool="circle">⭕</button>
<input type="color" id="colorPicker" value="#000000">
<input type="range" id="brushSize" min="1" max="50" value="5">
</div>
<div id="main">
<div id="canvasContainer">
<canvas id="canvas" width="800" height="600"></canvas>
</div>
</div>
</div>
<div id="timeline">
<div class="controls">
<button class="small" id="addFrame">+ Frame</button>
<button class="small" id="dupFrame">Duplicate</button>
<button class="small" id="delFrame">Delete</button>
<button class="small" id="save">💾 Save</button>
<button class="small" id="load">📂 Load</button>
<button class="small" id="export">⬇️ Export PNG</button>
Canvas W:<input type="number" id="canvasWidth" value="800" min="100" max="2000">
H:<input type="number" id="canvasHeight" value="600" min="100" max="2000">
Zoom:<button class="small" id="zoomIn">+</button><button class="small" id="zoomOut">-</button>
</div>
<div id="framesList"></div>
</div>
CSS
body {margin:0; font-family:sans-serif; background:#0b1e3d; color:#fff; overflow:hidden;}
#toolbar {
width:60px; background:#1e3c72; display:flex; flex-direction:column;
padding:5px; border-right:2px solid #4fc3f7; align-items:center; gap:10px;
}
#toolbar button {
width:40px; height:40px; background:rgba(255,255,255,0.1); border:none; color:#fff;
border-radius:5px; cursor:pointer; font-size:18px;
}
#toolbar button.active {background:#4fc3f7;}
#toolbar button:hover {background:rgba(255,255,255,0.2);}
#main {display:flex; height:calc(100vh - 120px);} /* leave space for timeline */
#canvasContainer {flex:1; display:flex; justify-content:center; align-items:center; background:#07213f; overflow:hidden;}
canvas {background:#fff; border:1px solid #4fc3f7; cursor:crosshair;}
#timeline {
height:120px; background:#0c3a6b; border-top:2px solid #4fc3f7;
display:flex; flex-direction:column; overflow-x:auto; overflow-y:auto;
}
#framesList {display:flex; gap:5px; padding:5px;}
.frameItem {
min-width:60px; height:40px; background:rgba(255,255,255,0.1);
display:flex; justify-content:center; align-items:center; cursor:pointer;
border-radius:3px; border:1px solid #4fc3f7;
}
.frameItem.active {background:#4fc3f7;}
.controls {
padding:5px; display:flex; gap:5px; flex-wrap:wrap; background:#07213f; border-top:2px solid #4fc3f7;
}
input, button.small {padding:3px; border:none; border-radius:3px;}
button.small {background:rgba(255,255,255,0.1); color:#fff; cursor:pointer;}
button.small:hover {background:#4fc3f7;}
JavaScript
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let scale = 1, offsetX = 0, offsetY = 0, dragging = false, lastX, lastY;
let currentTool = 'pencil';
let brushColor = '#000000';
let brushSize = 5;
let drawing = false;
let startPos = null;
let frames = [{strokes:[]}];
let currentFrame = 0;
// setup tools
document.querySelectorAll('#toolbar button[data-tool]').forEach(btn=>{
btn.addEventListener('click', ()=>{
document.querySelectorAll('#toolbar button').forEach(b=>b.classList.remove('active'));
btn.classList.add('active');
currentTool = btn.dataset.tool;
});
});
document.getElementById('colorPicker').oninput = e=>brushColor = e.target.value;
document.getElementById('brushSize').oninput = e=>brushSize = +e.target.value;
// draw strokes
function drawAll(){
ctx.setTransform(scale,0,0,scale,offsetX,offsetY);
ctx.clearRect(-offsetX/scale,-offsetY/scale,canvas.width/scale,canvas.height/scale);
for (let s of frames[currentFrame].strokes){
ctx.strokeStyle = s.color;
ctx.lineWidth = s.size;
ctx.beginPath();
if(s.type==="pencil" || s.type==="eraser"){
ctx.moveTo(s.points[0].x, s.points[0].y);
for(let p of s.points){ctx.lineTo(p.x,p.y);}
} else if(s.type==="line"){
ctx.moveTo(s.points[0].x, s.points[0].y);
ctx.lineTo(s.points[1].x, s.points[1].y);
} else if(s.type==="rect"){
let x=s.points[0].x,y=s.points[0].y,w=s.points[1].x-x,h=s.points[1].y-y;
ctx.rect(x,y,w,h);
} else if(s.type==="circle"){
let dx=s.points[1].x-s.points[0].x, dy=s.points[1].y-s.points[0].y;
let r=Math.sqrt(dx*dx+dy*dy);
ctx.arc(s.points[0].x,s.points[0].y,r,0,Math.PI*2);
}
ctx.stroke();
}
}
// mouse
canvas.addEventListener('mousedown',e=>{
if(e.button===1){ dragging=true; lastX=e.offsetX; lastY=e.offsetY; return; }
drawing = true;
startPos = {x:(e.offsetX-offsetX)/scale,...