# 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 :3050 │ │ │ ▼ │ │ 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 clone 
cd 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:3050 |

---

## 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:3050/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:3050`.

**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