AquaMotion

by Sharxxy

HTML

<div id="toolbar">
  <img src="https://via.placeholder.com/120x30?text=AquaMotion" alt="AquaMotion" id="logo">
  <button data-tool="pencil" class="active">✏️ Pencil</button>
  <button data-tool="eraser">🩹 Eraser</button>
  <button data-tool="line">➖ Line</button>
  <button data-tool="rect">⬛ Rectangle</button>
  <button data-tool="circle">⭕ Circle</button>
  Color: <input type="color" id="colorPicker" value="#00bfff">
  Size: <input type="range" id="brushSize" min="1" max="50" value="5">
  <button id="undo">↩️ Undo</button>
  <button id="redo">↪️ Redo</button>
  <button id="playPause">▶️ Play</button>
  FPS: <input type="number" id="fps" value="12" min="1" max="60">
  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">
  <button id="zoomIn">🔍+</button>
  <button id="zoomOut">🔍-</button>
  <button id="resetView">🎯 Reset</button>
</div>

<div id="main">
  <div id="canvasContainer">
    <canvas id="canvas" width="800" height="600"></canvas>
  </div>

  <!-- Timeline (bottom) -->
  <div id="timeline">
    <div id="layersPanel">
      <h3>Layers</h3>
      <p>Layer 1</p>
      <p>Layer 2</p>
    </div>
    <div id="framesPanel"></div>
  </div>
</div>

CSS

body {margin:0; font-family:sans-serif; background:#0b1e3d; color:#fff; display:flex; flex-direction:column; height:100vh;}
  #toolbar {
    display:flex; align-items:center; gap:5px; padding:5px;
    background:linear-gradient(90deg,#1e3c72,#2a5298); border-bottom:2px solid #4fc3f7;
    flex-wrap: wrap;
  }
  #logo {height:30px; margin-right:10px;}
  button {padding:5px 10px; background:rgba(255,255,255,0.1); border:none; color:#fff; border-radius:5px; cursor:pointer;}
  button.active {background:#4fc3f7;}
  button:hover {background:rgba(255,255,255,0.2);}
  input[type=color], input[type=range], input[type=number], input[type=file]{
    background:rgba(255,255,255,0.1); color:#fff; border:none; border-radius:3px; padding:2px;
  }

  #main {flex:1; display:flex; flex-direction:column; overflow:hidden;}
  #canvasContainer {flex:1; display:flex; justify-content:center; align-items:center; background:#07213f; overflow:hidden;}
  canvas {background:#0c2a50; border:1px solid #4fc3f7; cursor:crosshair;}

  /* Timeline at bottom */
  #timeline {
    height:160px; background:#0b1e3d; border-top:2px solid #4fc3f7;
    display:flex; overflow:hidden;
  }
  #layersPanel {
    width:120px; border-right:2px solid #4fc3f7; padding:10px;
  }
  #framesPanel {
    flex:1; display:flex; align-items:center; overflow-x:auto; padding:10px;
  }
  .frameItem {
    min-width:60px; height:80px; background:rgba(255,255,255,0.1);
    margin:0 5px; border-radius:5px; display:flex; justify-content:center; align-items:center;
    cursor:pointer; border:1px solid #4fc3f7;
  }
  .frameItem.active {background:#4fc3f7; color:#000;}

JavaScript

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

let currentTool = 'pencil';
let brushColor = '#00bfff';
let brushSize = 5;
let drawing = false;
let startPos = null;

let frames = [{strokes:[], audios:[]}];
let currentFrame = 0;

// Timeline handling
const framesPanel = document.getElementById("framesPanel");
function renderFrames(){
  framesPanel.innerHTML="";
  frames.forEach((f,i)=>{
    let el=document.createElement("div");
    el.className="frameItem"+(i===currentFrame?" active":"");
    el.textContent=i+1;
    el.onclick=()=>{currentFrame=i; renderFrames();};
    framesPanel.appendChild(el);
  });
}
function addFrame(){
  frames.push({strokes:[], audios:[]});
  currentFrame=frames.length-1;
  renderFrames();
}
addFrame();

// Pan + Zoom
let scale=1, offsetX=0, offsetY=0;
let isPanning=false, startX=0, startY=0;

function applyTransform(){
  ctx.setTransform(scale,0,0,scale,offsetX,offsetY);
}

canvas.addEventListener("wheel",e=>{
  e.preventDefault();
  const factor=e.deltaY<0?1.1:0.9;
  scale*=factor;
  draw();
});

canvas.addEventListener("mousedown",e=>{
  if(e.button===1){ // middle mouse
    isPanning=true;
    startX=e.clientX-offsetX;
    startY=e.clientY-offsetY;
  }
});
canvas.addEventListener("mousemove",e=>{
  if(isPanning){
    offsetX=e.clientX-startX;
    offsetY=e.clientY-startY;
    draw();
  }
});
canvas.addEventListener("mouseup",()=>isPanning=false);

document.getElementById("zoomIn").onclick=()=>{scale*=1.1; draw();};
document.getElementById("zoomOut").onclick=()=>{scale*=0.9; draw();};
document.getElementById("resetView").onclick=()=>{scale=1;offsetX=offsetY=0;draw();};

function draw(){
  ctx.setTransform(scale,0,0,scale,offsetX,offsetY);
  ctx.clearRect(-offsetX/scale,-offsetY/scale,canvas.width/scale,canvas.height/scale);
  ctx.fillStyle="red";
  ctx.fillRect(100,100,200,200);
}
draw();