AquaMotion 🌊

by Sharxxy

HTML

<header>🌊 AquaMotion - Animation App Prototype</header>
  <div id="toolbar">
    <button data-tool="brush">πŸ–ŒοΈ</button>
    <button data-tool="eraser">🧽</button>
    <button data-tool="line">πŸ“</button>
    <button data-tool="rect">⬛</button>
    <button data-tool="circle">βšͺ</button>
    <button data-tool="bucket">πŸͺ£</button>
    <button data-tool="picker">🎨</button>
    Brush Size: <input type="range" id="brushSize" min="1" max="30" value="5">
    Color: <input type="color" id="colorPicker" value="#000000">
    <button id="addFrame">βž• Frame</button>
    <button id="play">β–Ά Play</button>
    <button id="undo">↩ Undo</button>
    <button id="redo">β†ͺ Redo</button>
    <button id="copy">πŸ“‹ Copy</button>
    <button id="paste">πŸ“₯ Paste</button>
    <button id="save">πŸ’Ύ Save .aqua</button>
    <button id="load">πŸ“‚ Load .aqua</button>
    <button id="export">πŸ“€ Export PNGs</button>
    <input type="file" id="fileInput" style="display:none">
    <button id="addLayer">βž• Layer</button>
    <button id="addAudio">🎡 Add Audio</button>
    <input type="file" id="audioInput" accept="audio/*" style="display:none">
    <label>Canvas W: <input type="number" id="canvasW" value="600" min="100"></label>
    <label>H: <input type="number" id="canvasH" value="400" min="100"></label>
    <button id="resizeCanvas">πŸ“ Resize</button>
    <label><input type="checkbox" id="onionSkin"> Onion Skin</label>
  </div>
  <div id="main">
    <div id="canvas-container">
      <canvas id="drawCanvas" width="600" height="400"></canvas>
    </div>
    <div style="flex:1;display:flex;flex-direction:column;">
      <div id="timeline"></div>
      <div id="layers"></div>
    </div>
  </div>
  <audio id="audioPlayer" controls style="width:100%;"></audio>

CSS

body {
      margin: 0;
      font-family: Arial, sans-serif;
      background: linear-gradient(180deg, #0a2540, #0f5c8d);
      color: white;
      display: flex;
      flex-direction: column;
      height: 100vh;
    }
    header {
      padding: 10px;
      background: rgba(0, 128, 192, 0.9);
      text-align: center;
      font-size: 22px;
      font-weight: bold;
      color: #fff;
      letter-spacing: 2px;
      text-shadow: 0 0 5px #00d4ff;
    }
    #toolbar {
      background: rgba(0, 50, 80, 0.9);
      padding: 6px;
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
      align-items: center;
    }
    #toolbar button, #toolbar input {
      cursor: pointer;
      padding: 4px 8px;
      border: none;
      border-radius: 4px;
    }
    #toolbar button {
      background: #00aaff;
      color: white;
    }
    #toolbar button:hover {
      background: #008ecc;
    }
    #main {
      flex: 1;
      display: flex;
      overflow: hidden;
    }
    #canvas-container {
      flex: 3;
      background: #222;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
    }
    canvas {
      background: white;
      border: 2px solid #00bfff;
    }
    #timeline {
      flex: 1;
      background: rgba(0, 40, 70, 0.9);
      padding: 10px;
      overflow-x: auto;
      white-space: nowrap;
    }
    .frame {
      display: inline-block;
      width: 40px;
      height: 40px;
      margin: 2px;
      background: #444;
      border: 2px solid transparent;
      cursor: pointer;
    }
    .frame.active {
      border: 2px solid #00adee;
    }
    #layers {
      background: rgba(0, 60, 100, 0.9);
      padding: 6px;
      color: white;
      height: 150px;
      overflow-y: auto;
    }
    .layer {
      background: #006699;
      margin: 4px 0;
      padding: 4px;
      cursor: pointer;
    }
    .layer.active {
   ...

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;
    let undoStack = [];
    let redoStack = [];
    let frames = [[]];
    let currentFrame = 0;
    let layers = [[]];
    let currentLayer = 0;
    let copiedImage = null;

    // Toolbar
    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;

    // Layers
    function renderLayers() {
      const container=document.getElementById('layers');
      container.innerHTML='';
      layers.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();}
        container.appendChild(div);
      });
    }
    document.getElementById('addLayer').onclick=()=>{
      layers[currentFrame].push(ctx.createImageData(canvas.width,canvas.height));
      renderLayers();
    };

    // Timeline
    function renderTimeline() {
      const timeline=document.getElementById('timeline');
      timeline.innerHTML='';
      frames.forEach((f,i)=>{
        const div=document.createElement('div');
        div.className='frame'+(i===currentFrame?' active':'');
        div.onclick=()=>{currentFrame=i;drawFrame();renderTimeline();}
        timeline.appendChild(div);
      });
    }
    document.getElementById('addFrame').onclick=()=>{
      frames.push([]);
      layers.push([ctx.createImageData(canvas.width,canvas.height)]);
      currentFrame=frames.length-1;
     ...