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=()=>{
     ...