JSFiddle - React, Tailwind, and code Playground

by Sharxxy

HTML

<div id="toolbar">
  <img src="https://via.placeholder.com/100x30?text=AquaMotion" alt="AquaMotion Logo" id="logo">
  <button id="pencilBtn" class="active">✏️ Pencil</button>
  <button id="eraserBtn">🩹 Eraser</button>
  <input type="color" id="colorPicker" value="#00bfff">
  <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">
</div>

<div id="main">
  <div id="canvasContainer">
    <canvas id="canvas" width="800" height="600"></canvas>
  </div>
  <div id="sidebar">
    <h3>Frames</h3>
    <div id="framesList"></div>
    <button id="addFrame">+ Add Frame</button>
    <button id="dupFrame">Duplicate Frame</button>
    <button id="delFrame">Delete Frame</button>
  </div>
</div>

CSS

body {margin:0; font-family:sans-serif; background:#121212; color:#fff;}
#toolbar {
  display:flex; align-items:center; gap:5px; padding:5px; background:#1e1e1e; border-bottom:1px solid #333;
}
#logo {height:30px; margin-right:10px;}
button {padding:5px 10px; background:#222; border:none; color:#eee; border-radius:3px; cursor:pointer;}
button.active {background:#00bfff;}
button:hover {background:#333;}
input[type=color] {width:40px; height:25px; border:none; cursor:pointer;}
input[type=range] {width:100px;}
input[type=number] {width:50px; background:#222; color:#eee; border:none; border-radius:3px; padding:2px;}

#main {display:flex; height:calc(100vh - 50px);}
#canvasContainer {flex:3; display:flex; justify-content:center; align-items:center; background:#1a1a1a; overflow:hidden;}
canvas {background:#1c1c1c; border:1px solid #333; cursor:crosshair;}

#sidebar {flex:1; background:#1e1e1e; padding:10px; display:flex; flex-direction:column; gap:10px; overflow-y:auto;}
#framesList .frameItem {padding:5px; background:#222; border-radius:3px; cursor:pointer; margin-bottom:3px;}
#framesList .frameItem.active {background:#00bfff;}
h3 {margin:5px 0; color:#00bfff;}

JavaScript

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

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

let frames = [[]]; // frame strokes
let currentFrame = 0;
let undoStack = [];
let redoStack = [];
let fps = 12;
let playInterval = null;

// DOM elements
const pencilBtn = document.getElementById('pencilBtn');
const eraserBtn = document.getElementById('eraserBtn');
const colorPicker = document.getElementById('colorPicker');
const brushSizeInput = document.getElementById('brushSize');
const undoBtn = document.getElementById('undo');
const redoBtn = document.getElementById('redo');
const playPauseBtn = document.getElementById('playPause');
const fpsInput = document.getElementById('fps');
const framesList = document.getElementById('framesList');
const addFrameBtn = document.getElementById('addFrame');
const dupFrameBtn = document.getElementById('dupFrame');
const delFrameBtn = document.getElementById('delFrame');

// --- Tools ---
function selectTool(tool){
    currentTool = tool;
    pencilBtn.classList.remove('active');
    eraserBtn.classList.remove('active');
    if(tool==='pencil') pencilBtn.classList.add('active');
    if(tool==='eraser') eraserBtn.classList.add('active');
}
pencilBtn.onclick = () => selectTool('pencil');
eraserBtn.onclick = () => selectTool('eraser');
colorPicker.onchange = e => brushColor = e.target.value;
brushSizeInput.oninput = e => brushSize = e.target.value;

// --- Drawing ---
canvas.addEventListener('mousedown',()=>drawing=true);
canvas.addEventListener('mouseup',()=>drawing=false);
canvas.addEventListener('mousemove', e=>{
    if(!drawing) return;
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const stroke = {tool: currentTool, x, y, size: brushSize, color: brushColor};
    frames[currentFrame].push(stroke);
   ...