Created
July 2, 2025 02:30
-
-
Save AaronKow/596543f2f3cba515e503faf7b32409cf to your computer and use it in GitHub Desktop.
ASCII → RP2040 Sprite Converter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>ASCII → RP2040 Sprite Converter</title> | |
| <style> | |
| body { font-family: system-ui, sans-serif; margin: 1rem; background: #f4f4f5; } | |
| h1 { font-size: 1.5rem; margin-bottom: 1rem; } | |
| textarea, pre { width: 100%; box-sizing: border-box; border: 1px solid #ddd; border-radius: 0.5rem; padding: 0.75rem; font-family: monospace; background: #fff; } | |
| textarea { min-height: 160px; resize: vertical; } | |
| button { | |
| padding: 0.6rem 1rem; margin-top: 0.75rem; border: none; | |
| border-radius: 0.5rem; cursor: pointer; font-weight: 600; | |
| background: #2563eb; color: #fff; | |
| } | |
| button:disabled { opacity: 0.5; cursor: not-allowed; } | |
| .flex { display: flex; gap: 1rem; flex-wrap: wrap; } | |
| .half { flex: 1 1 300px; min-width: 300px; } | |
| label { font-weight: 600; display: block; margin-bottom: 0.25rem; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>ASCII → C Sprite Converter (SSD1306 128×64)</h1> | |
| <button id="load-demo">Load Demo</button> | |
| <div class="flex"> | |
| <div class="half"> | |
| <label for="ascii">1️⃣ Draw sprite (non-space & non-dot = pixel ON)</label> | |
| <textarea id="ascii" placeholder="Example (16×16 smiley using . for blank):
................
.##############.
.#....##....##..
.#....##....##..
.#............#.
.#....######..#.
.#............#.
.#..##....##..#.
.#...######...#.
.##############.
................
................
................
................
................
................"></textarea> | |
| </div> | |
| <div class="half"> | |
| <label for="c-output">2️⃣ Generated C code</label> | |
| <textarea id="c-output" readonly placeholder="C array will appear here…"></textarea> | |
| <button id="copy" disabled>Copy to Clipboard</button> | |
| </div> | |
| </div> | |
| <button id="convert">Convert → C Bitmap</button> | |
| <pre id="info"></pre> | |
| <script> | |
| const asciiEl = document.getElementById('ascii'); | |
| const outputEl = document.getElementById('c-output'); | |
| const infoEl = document.getElementById('info'); | |
| const convertBtn = document.getElementById('convert'); | |
| const copyBtn = document.getElementById('copy'); | |
| const loadDemoBtn = document.getElementById('load-demo'); | |
| const demoSprite = [ | |
| "................", | |
| ".##############.", | |
| ".#....##....##..", | |
| ".#....##....##..", | |
| ".#............#.", | |
| ".#....######..#.", | |
| ".#............#.", | |
| ".#..##....##..#.", | |
| ".#...######...#.", | |
| ".##############.", | |
| "................", | |
| "................", | |
| "................", | |
| "................", | |
| "................", | |
| "................" | |
| ].join("\n"); | |
| function asciiToBytes(lines) { | |
| const height = lines.length; | |
| const width = Math.max(...lines.map(l => l.length)); | |
| if (width > 128 || height > 64) throw new Error('Sprite exceeds 128×64 limit'); | |
| // Pad lines to equal width | |
| lines = lines.map(l => l.padEnd(width, ' ')); | |
| const bytes = []; | |
| for (let y = 0; y < height; y += 8) { | |
| for (let x = 0; x < width; x++) { | |
| let byte = 0; | |
| for (let bit = 0; bit < 8; bit++) { | |
| const yy = y + bit; | |
| let pxOn = false; | |
| if (yy < height) { | |
| const ch = lines[yy][x]; | |
| pxOn = ch !== ' ' && ch !== '.'; // spaces & dots are OFF | |
| } | |
| byte |= (pxOn ? 1 : 0) << bit; // LSB = top pixel | |
| } | |
| bytes.push(byte); | |
| } | |
| } | |
| return { width, height, bytes }; | |
| } | |
| function generateC({ width, height, bytes }) { | |
| const hex = bytes.map(b => '0x' + b.toString(16).padStart(2, '0')); | |
| return `// Width: ${width}, Height: ${height}\nconst uint8_t sprite_${width}x${height}[${bytes.length}] = {\n ${hex.join(', ')}\n};`; | |
| } | |
| convertBtn.addEventListener('click', () => { | |
| try { | |
| const lines = asciiEl.value.replace(/\r/g, '').split('\n').filter(l => l.length); | |
| if (!lines.length) throw new Error('Please enter ASCII art'); | |
| const data = asciiToBytes(lines); | |
| const cCode = generateC(data); | |
| outputEl.value = cCode; | |
| infoEl.textContent = `Converted: ${data.width}×${data.height} → ${data.bytes.length} bytes`; | |
| copyBtn.disabled = false; | |
| } catch (err) { | |
| infoEl.textContent = err.message; | |
| outputEl.value = ''; | |
| copyBtn.disabled = true; | |
| } | |
| }); | |
| copyBtn.addEventListener('click', async () => { | |
| try { | |
| await navigator.clipboard.writeText(outputEl.value); | |
| copyBtn.textContent = 'Copied!'; | |
| setTimeout(() => (copyBtn.textContent = 'Copy to Clipboard'), 1500); | |
| } catch { | |
| alert('Clipboard failed. Please copy manually.'); | |
| } | |
| }); | |
| loadDemoBtn.addEventListener('click', () => { | |
| asciiEl.value = demoSprite; | |
| outputEl.value = ''; | |
| infoEl.textContent = ''; | |
| copyBtn.disabled = true; | |
| }); | |
| </script> | |
| <details style="margin-top:1rem;"> | |
| <summary><strong>How to use in C (TinyUSB / Pico‑SDK)</strong></summary> | |
| <pre> | |
| // Include the array this tool generated (e.g. sprite_16x16) | |
| #include "sprite.h" | |
| void oled_draw_sprite(uint8_t x, uint8_t page, const uint8_t *sprite, | |
| uint8_t w, uint8_t h) { | |
| /* SSD1306 page‑addressed write */ | |
| for (uint8_t col = 0; col < w; col++) { | |
| for (uint8_t p = 0; p < (h + 7) / 8; p++) { | |
| ssd1306_set_cursor(x + col, page + p); | |
| ssd1306_write_data(sprite[col + p * w]); | |
| } | |
| } | |
| } | |
| // Example usage | |
| oled_draw_sprite(0, 0, sprite_16x16, 16, 16); | |
| </pre> | |
| </details> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment