AquaMotion π
by Sharxxy
HTML
<div id="toolbar">
<button data-tool="brush">ποΈ Brush</button>
<button data-tool="eraser">π§½ Eraser</button>
<button data-tool="line">π Line</button>
<button data-tool="rect">β¬ Rect</button>
<button data-tool="circle">βͺ Circle</button>
<button data-tool="bucket">πͺ£ Bucket</button>
<button data-tool="move">β Move</button>
<button data-tool="text">π€ Text</button>
Size: <input type="range" id="brushSize" min="1" max="30" value="5">
<input type="color" id="colorPicker" value="#000000">
<button id="undo">β© Undo</button>
<button id="redo">βͺ Redo</button>
<button id="copy">π Copy</button>
<button id="paste">π₯ Paste</button>
<button id="addLayer">β Layer</button>
<button id="addFrame">β Frame</button>
<button id="play">βΆ Play</button>
FPS: <input type="number" id="fpsInput" value="5" min="1" max="60">
<button id="resizeCanvas">π Resize</button>
W:<input type="number" id="canvasW" value="800" min="100">
H:<input type="number" id="canvasH" value="500" min="100">
Project: <input type="text" id="projectName" value="Untitled">
<button id="save">πΎ Save</button>
<button id="load">π Load</button>
<input type="file" id="fileInput" style="display:none">
<button id="exportMP4">π¬ Export MP4</button>
<button id="addAudio">π΅ Add Sound</button>
<input type="file" id="audioInput" accept="audio/*" style="display:none">
</div>
<div id="canvas-container">
<canvas id="drawCanvas" width="800" height="500"></canvas>
<div id="layersPanel"></div>
</div>
<div id="timeline"></div>
<audio id="audioPlayer" controls style="width:100%;"></audio>
<script src="https://unpkg.com/@ffmpeg/[email protected]/dist/ffmpeg.min.js"></script>
CSS
body {
margin: 0;
font-family: Arial, sans-serif;
background: linear-gradient(180deg, #082032, #1a374d);
color: white;
height: 100vh;
display: grid;
grid-template-rows: 40px 1fr 160px;
grid-template-columns: 1fr;
grid-template-areas:
"toolbar"
"canvas"
"timeline";
}
#toolbar {
grid-area: toolbar;
background: rgba(0, 80, 120, 0.95);
display: flex;
align-items: center;
gap: 8px;
padding: 4px 10px;
overflow-x: auto;
}
#toolbar button, #toolbar input, #toolbar select {
background: #00aaff;
border: none;
color: white;
padding: 4px 8px;
cursor: pointer;
border-radius: 4px;
}
#toolbar button:hover {
background: #008ecc;
}
#canvas-container {
grid-area: canvas;
background: #111;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
canvas {
background: white;
border: 2px solid #00d4ff;
}
#timeline {
grid-area: timeline;
background: rgba(0, 40, 70, 0.9);
overflow-x: auto;
display: flex;
align-items: center;
padding: 6px;
}
.frame {
width: 50px;
height: 50px;
background: #333;
border: 2px solid transparent;
margin: 2px;
cursor: pointer;
}
.frame.active {
border-color: #00d4ff;
}
#layersPanel {
position: absolute;
top: 50px;
right: 10px;
width: 150px;
background: rgba(0,60,100,0.95);
border: 1px solid #00d4ff;
padding: 6px;
max-height: 300px;
overflow-y: auto;
}
.layer {
background: #006699;
margin: 4px 0;
padding: 4px;
cursor: pointer;
}
.layer.active {
background: #00aaff;
}
JavaScript
const canvas=document.getElementById("drawCanvas");
const ctx=canvas.getContext("2d");
let drawing=false;
let tool="brush";
let brushSize=document.getElementById("brushSize").value;
let brushColor=document.getElementById("colorPicker").value;
document.querySelectorAll("#toolbar button[data-tool]").forEach(btn=>{
btn.onclick=()=>tool=btn.dataset.tool;
});
document.getElementById("brushSize").oninput=e=>brushSize=e.target.value;
document.getElementById("colorPicker").oninput=e=>brushColor=e.target.value;
let undoStack=[],redoStack=[];
let frames=[[]];
let currentFrame=0;
let layers=[[ctx.createImageData(canvas.width,canvas.height)]];
let currentLayer=0;
let copiedImage=null;
let fps=5;
function renderLayers(){
const panel=document.getElementById("layersPanel");
panel.innerHTML="";
layers[currentFrame].forEach((l,i)=>{
const div=document.createElement("div");
div.className="layer"+(i===currentLayer?" active":"");
div.textContent="Layer "+(i+1);
div.onclick=()=>{currentLayer=i;renderLayers();drawFrame();};
panel.appendChild(div);
});
}
function renderTimeline(){
const t=document.getElementById("timeline");
t.innerHTML="";
frames.forEach((f,i)=>{
const div=document.createElement("div");
div.className="frame"+(i===currentFrame?" active":"");
div.onclick=()=>{currentFrame=i;drawFrame();renderTimeline();};
t.appendChild(div);
});
}
document.getElementById("addFrame").onclick=()=>{
frames.push([]);
layers.push([ctx.createImageData(canvas.width,canvas.height)]);
currentFrame=frames.length-1;
currentLayer=0;
renderTimeline();renderLayers();drawFrame();
};
document.getElementById("addLayer").onclick=()=>{
...