<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>👾 Useless Robot Animator</title> <script src="./jquery.min.js"></script> <style> .circle { width: 20px; height: 20px; background-color: #525050; border-radius: 50%; display: inline-block; margin: 2px; cursor: pointer; } .circle.centerleft{ border-right: 1px solid white; } .circle.centerright{ border-left: 1px solid white; } .circle.active{ background-color: #f55142; } #grid-container { display: flex; position: relative; flex-wrap: wrap; width: calc(32 * (20px + 2px * 2)); } #dotmatrix{ display: flex; flex-wrap: wrap; } html, body { height: 100%; margin: 0; display: flex; align-items: center; justify-content: center; background-color: #242424; font-family: Verdana, sans-serif; color: white; } .matrixModule{ position: absolute; border: 1px solid #a3a3a3; width: calc(24px * 8); height: calc(24px * 8); pointer-events: none; } .matrixModule.one { top: 0; left: 0; } .matrixModule.two { top: 0; left: 192px; } .matrixModule.three { top: 0; left: 384px; } .matrixModule.four { top: 0; left: 576px; } .matrixModule.five { top: 192px; left: 0px; } .matrixModule.six { top: 192px; left: 192px; } .matrixModule.seven { top: 192px; left: 384px; } .matrixModule.eight { top: 192px; left: 576px; } button{ background-color: white; color: #3b3b3b; border-radius: 0em; box-shadow: none; padding-top: 0.4em; padding-bottom: 0.4em; padding-left: 1em; padding-right: 1em; cursor: pointer; margin: 0.4em; margin-top: 0.6em; } </style> </head> <body> <div id="grid-container"> <div id="layout"> <div class="matrixModule one"></div> <div class="matrixModule two"></div> <div class="matrixModule three"></div> <div class="matrixModule four"></div> <div class="matrixModule five"></div> <div class="matrixModule six"></div> <div class="matrixModule seven"></div> <div class="matrixModule eight"></div> </div> <div id="dotmatrix"></div> <br> <div style="width: 100%; padding: 1em; "> <div style="float: right;"> <button onclick="clearScreen();">Clear</button> <button onclick="loadDefault();">Load Default</button> <button onclick="downloadBinary();">Export Binary</button> <button onclick="openFilePicker()">Import Binary</button> <input type="file" id="fileInput" style="display: none;" accept=".bin" onchange="handleFile(event)"> </div> <div style="padding-top: 0.8em;"> 👾 Cute Useless Robot Animator </div> </div> </div> <script> let defaultTemplate = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; function generateCircleGrid(containerId) { const container = document.getElementById(containerId); if (!container) { console.error(`No element found with id "${containerId}"`); return; } // Clear the container if it already has content container.innerHTML = ''; // Create a grid of circles const rows = 16; const cols = 32; for (let i = 0; i < rows; i++) { for (let j = 0; j < cols; j++) { $(container).append('<div class="circle" onClick="toggleThis(this);"></div>'); } } } function getFrameAsIntArray(){ let results = []; $(".circle").each(function(){ let isActive = $(this).hasClass("active"); if (isActive){ results.push(1); }else{ results.push(0); } }); return results; } function drawFrameFromIntArray(frameArray){ let counter = 0; $(".circle").each(function(){ if (frameArray[counter] != undefined){ let isActive = frameArray[counter] == 1; if (isActive){ $(this).addClass('active'); }else{ $(this).removeClass('active'); } } counter++; }); } function loadDefault(){ drawFrameFromIntArray(defaultTemplate); } function downloadBinary(){ const bitArray = getFrameAsIntArray(); const byteArray = []; for (let i = 0; i < bitArray.length; i += 8) { let byte = 0; for (let j = 0; j < 8; j++) { if (bitArray[i + j]) { byte |= 1 << (7 - j); } } byteArray.push(byte); } const blob = new Blob([new Uint8Array(byteArray)], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'frame.bin'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } function toggleThis(led){ if (!$(led).hasClass('active')){ $(led).addClass('active'); }else{ $(led).removeClass('active'); } } // Call the function to generate the grid generateCircleGrid('dotmatrix'); function clearScreen(){ $(".circle.active").removeClass("active"); } //Import functions function openFilePicker() { document.getElementById('fileInput').click(); } function handleFile(event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(e) { const arrayBuffer = e.target.result; const byteArray = new Uint8Array(arrayBuffer); const bitArray = []; for (let byte of byteArray) { for (let i = 7; i >= 0; i--) { bitArray.push((byte >> i) & 1); } } renderBitArray(bitArray); }; reader.readAsArrayBuffer(file); } } function renderBitArray(bitArray) { drawFrameFromIntArray(bitArray); } </script> </body> </html>