# ASCIInator ``` █████╗ ███████╗ ██████╗██╗██╗███╗ ██╗ █████╗ ████████╗ ██████╗ ██████╗ ██╔══██╗██╔════╝██╔════╝██║██║████╗ ██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ███████║███████╗██║ ██║██║██╔██╗ ██║███████║ ██║ ██║ ██║██████╔╝ ██╔══██║╚════██║██║ ██║██║██║╚██╗██║██╔══██║ ██║ ██║ ██║██╔══██╗ ██║ ██║███████║╚██████╗██║██║██║ ╚████║██║ ██║ ██║ ╚██████╔╝██║ ██║ ╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ``` > Turn any image into ASCII art. Headless Vue 3 front-end for your system's ASCII conversion binaries. --- ## What It Does ASCIInator is a local-first GUI wrapper around the ASCII conversion tools already on your system. Drop an image in, pick your tool, tune the flags, get plain-text ASCII out. No cloud, no SaaS, no telemetry — just your binaries, a thin Fastify bridge, and a Vue 3 interface. Built as a test bed for **Neovim IDE v2.1.x**. --- ## Supported Converters | Tool | Notes | |------|-------| | **chafa** | Default. Best quality, full flag exposure | | **jp2a** | JPEG-focused, classic output | | **ascii-image-converter** | Braille support, good for fine detail | | **img2txt** | libcaca-based, multiple output formats | All tools must be installed on your system. ASCIInator does not install them for you. --- ## Stack | Layer | Tech | |-------|------| | Frontend | Vue 3 + Vite | | Styling | Tailwind CSS (no component lib) | | API server | Fastify | | Shell invocation | execa | | Image processing | ImageMagick v7 (`magick`) | --- ## Architecture ``` ┌─────────────────────────────────────────┐ │ Vue 3 Frontend │ │ │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ ImageInput │ │ ToolSelector │ │ │ │ │ │ │ │ │ │ • Upload │ │ • chafa │ │ │ │ • Paste │ │ • jp2a │ │ │ │ • Drag-drop │ │ • ascii-i-c │ │ │ └──────┬──────┘ │ • img2txt │ │ │ │ └────────┬────────┘ │ │ └────────┬──────────┘ │ │ ▼ │ │ ┌───────────────┐ │ │ │ ShellBridge │ (renderless) │ │ └───────┬───────┘ │ │ │ POST /convert │ └──────────────────┼──────────────────────┘ │ ┌──────────────────┼──────────────────────┐ │ Fastify :3001 │ │ │ ▼ │ │ ImageMagick preprocessing │ │ ↓ │ │ execa → binary │ │ ↓ │ │ stdout → response │ └─────────────────────────────────────────┘ │ ┌──────────────────┼──────────────────────┐ │ Vue 3 Frontend │ │ │ │ ┌────────────────────┐ ┌───────────┐ │ │ │ OutputDisplay │ │ ErrorLog │ │ │ │ │ │ │ │ │ │
ASCII art │ │ stderr │ │ │ │ copy / download │ │ warnings │ │ │ └────────────────────┘ └───────────┘ │ └─────────────────────────────────────────┘ ``` --- ## Prerequisites **System binaries** (install via your package manager): ```bash # macOS brew install chafa jp2a libcaca imagemagick brew install ascii-image-converter # Debian/Ubuntu apt install chafa jp2a caca-utils imagemagick # ascii-image-converter: see https://github.com/TheZoraiz/ascii-image-converter # Arch pacman -S chafa jp2a libcaca imagemagick yay -S ascii-image-converter # AUR ``` **Node** — v20.19+ or v22.12+ required **Vite** — installed via npm --- ## Installation ```bash git clonecd asciinator npm install ``` --- ## IDE Setup **Neovim** (primary — this is a Neovim v2.1.x test bed): - Volar LSP in Takeover mode (disable tsserver for `.vue` files) - `tailwindcss-language-server` for class intellisense - `eslint-lsp` + `prettier` for format on save - See `CLAUDE.md §7` for the full Neovim config checklist **Browser DevTools:** - [Vue DevTools for Chrome/Brave](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) - [Vue DevTools for Firefox](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/) - Enable Custom Object Formatters in DevTools for readable Vue reactive state --- ## Running You need two terminals (or one split — you're using Neovim, you know the drill). ```bash # Terminal 1 — Fastify API server node server/index.js # Terminal 2 — Vite dev server npm run dev ``` | Service | URL | |---------|-----| | Vue app | http://localhost:5173 | | Fastify API | http://localhost:3001 | --- ## Project Structure ``` asciinator/ ├── CLAUDE.md ← Full spec for Claude Code ├── README.md ← You are here ├── index.html ├── vite.config.js ├── tailwind.config.js ├── src/ │ ├── main.js │ ├── App.vue │ ├── assets/ │ │ └── main.css │ └── components/ │ ├── ImageInput.vue ← Upload / paste / drag-drop │ ├── ToolSelector.vue ← Tool picker + flag controls │ ├── ShellBridge.vue ← GUI state → API call (renderless) │ ├── OutputDisplay.vue ← Plain-text ASCII result │ ├── ErrorLog.vue ← stderr / error surface │ └── options/ │ ├── ChafaOptions.vue │ ├── Jp2aOptions.vue │ ├── AsciiOptions.vue │ └── ImgTxtOptions.vue └── server/ ├── index.js ├── routes/ │ └── convert.js ← POST /convert handler └── lib/ ├── imagemagick.js ← Pre/post processing └── converters.js ← Per-tool execa invocations ``` --- ## npm Scripts ```bash npm run dev # Vite dev server (HMR) npm run build # Production build npm run preview # Preview production build npm run server # Fastify API server npm run server:dev # Fastify with --watch (auto-restart) npm run lint # oxlint + ESLint (with autofix) npm run format # Prettier npm run test:unit # Vitest unit tests npm run test:e2e # Playwright end-to-end tests ``` For e2e tests, build first if running on CI: ```bash npm run build npm run test:e2e npm run test:e2e -- --project=chromium # Chromium only npm run test:e2e -- --debug # Debug mode ``` --- ## API ### `POST /convert` **Request** — `multipart/form-data` | Field | Type | Description | |-------|------|-------------| | `image` | file | Image file to convert | | `tool` | string | `chafa` \| `jp2a` \| `ascii-image-converter` \| `img2txt` | | `flags` | JSON string | Tool-specific flags object | **Response** — `text/plain` — raw ASCII output on success, stderr on 422. **curl example:** ```bash curl -s -X POST http://localhost:3001/convert \ -F "image=@/path/to/photo.jpg" \ -F "tool=chafa" \ -F 'flags={"width":"80","colors":"256"}' ``` --- ## Flag Reference All flags are optional. Omitting a flag lets the binary use its own default. ### chafa | Flag | Type | Values | Description | |------|------|--------|-------------| | `width` | integer | e.g. `80` | Output width in characters (combined into `--size=WxH`) | | `height` | integer | e.g. `40` | Output height in characters (combined into `--size=WxH`) | | `colors` | enum | `none` `2` `8` `16/8` `16` `240` `256` `full` | Color depth | | `symbols` | string | e.g. `block+border+extra` | Symbol sets to use | | `dither` | enum | `none` `ordered` `diffusion` `noise` | Dithering algorithm | | `threshold` | float | `0.0`–`1.0` | Alpha threshold | | `font-ratio` | float | e.g. `0.5` | Terminal font width/height ratio | ### jp2a | Flag | Type | Values | Description | |------|------|--------|-------------| | `width` | integer | e.g. `80` | Output width in characters | | `height` | integer | e.g. `40` | Output height in characters | | `background` | enum | `light` `dark` | Assumed terminal background | | `chars` | string | e.g. `.:-=+*#%@` | Character ramp to use | ### ascii-image-converter | Flag | Type | Values | Description | |------|------|--------|-------------| | `width` | integer | e.g. `80` | Output width in characters | | `height` | integer | e.g. `40` | Output height in characters | | `color` | boolean | `true` | Emit ANSI color codes | | `braille` | boolean | `true` | Use braille dot patterns | | `threshold` | integer | `0`–`255` | Brightness threshold | ### img2txt | Flag | Type | Values | Description | |------|------|--------|-------------| | `width` | integer | e.g. `80` | Output width in characters | | `height` | integer | e.g. `40` | Output height in characters | | `format` | enum | `ansi` `utf8` `html` | Output format | | `dither` | string | e.g. `fstein` | Dithering mode | | `gamma` | float | e.g. `1.0` | Gamma correction | --- ## Troubleshooting **`command not found: chafa` (or jp2a, img2txt, ascii-image-converter)** The binary isn't on PATH. Install it via your package manager — see Prerequisites above. **`convert: command not found`** ImageMagick isn't installed. It's required for all conversions regardless of tool. **CORS error in the browser console** The Fastify server isn't running, or it's on a different port. Start it with `npm run server` and confirm it logs `Server listening at http://127.0.0.1:3001`. **422 from the server** The binary returned a non-zero exit code. The full stderr is in the response body and shown in the ErrorLog panel. **Blank or truncated output** Some tools default to terminal width detection which may return 0 in a non-TTY context. Set an explicit `--width` flag. --- ## Design - Always dark — light mode not wired (planned) - No component library — raw Tailwind only - Monospace output: JetBrains Mono - UI font: IBM Plex Sans - Accent: `#39ff14` (neon green — because ASCII) --- ## Neovim v2 Test Bed This project exists partly to stress-test the **Neovim IDE v2.1.x** setup across a real Vue 3 + JS project. See `CLAUDE.md §7` for the full test checklist covering Volar, Tailwind LSP, ESLint, DAP, and more. --- ## License MIT