---
name: splash-ascii-render
description: Convert a reference image into a terminal splash screen (render/<name>/show.sh) rendered as truecolor Unicode quadrant-block art, sized to the caller's terminal. Use when asked to create or regenerate an ASCII/Unicode-block splash, tune image-to-terminal-art conversion quality, or debug splash rendering (colors, frame sizing, locale) bugs.
---

# splash-ascii-render

Turns an image into a self-contained bash script that renders it in a
terminal at the best-fitting size, no runtime dependencies. Production path
is `src/quadrant.py` (image → quadrant-block glyph+color frames) followed by
`src/embed.py` (frames → `render/<name>/show.sh`). Both are driven by
`make` targets — see `AGENTS.md` at the repo root for the full layout.

This file is the workflow. Technical detail that would bloat it lives in
`references/`: read those on demand, don't inline their content here.

## Workflow

### 1. Scaffold the render

```sh
make new NAME=<name> SRC=/path/to/source.png
```

Creates `render/<name>/{frames,captures}/`, a README stub, and copies `SRC`
in as `render/<name>/target.png` in one step. Omit `SRC` to scaffold first
and drop the image in later — `target2.png` is also recognized (that name
wins if both exist, matching this repo's existing convention of keeping an
alternate source around for comparison), useful for adding a second
candidate source without re-running `make new`.

### 2. Inspect before tuning

```sh
.venv/bin/python3 src/inspect_target.py render/<name>/target.png \
    --out-dir render/<name>/captures --crops 3
```

Read the printed region means. **Near-binary line art** (a big gap between
background and ink, e.g. background ~0.01, lines ~0.2-0.4) wants
`convert.py`'s density+line model — the `--lo`/`--hi`/`--fill-gain` defaults
in `quadrant.py` are tuned for that. **Continuous tone** source images need
those thresholds re-tuned per image; probe actual region luminance rather
than guessing (see `references/lessons-learned.md` for why guessing burned
a full iteration here).

### 3. Generate

```sh
make render NAME=<name> CAPTION="optional text line below the art"
```

`CAPTION` is optional — omit it for a bare splash with no text row. This
runs `quadrant.py` (writes `render/<name>/frames/w<cols>_{glyph,color}.txt`
for the standard size ladder) then `embed.py` (bakes those frames into
`render/<name>/show.sh`).

### 4. Verify — don't trust the escape codes, look at the pixels

A shaded PNG preview and real terminal rendering can disagree (font
metrics, glyph visual weight, cell aspect ratio all differ). Two ways to
actually see it:

- In a real terminal: `render/<name>/show.sh --cols N --lines M`, or
  capture via `tmux capture-pane`.
- Without one: `src/ansi_to_png.py` rasterizes a captured ANSI stream
  (`show.sh ... > /tmp/out.ansi`) into an actual PNG you can view. This is
  how every quality check in this skill's history was actually confirmed,
  not just assumed from code review.

Check at several sizes, including the smallest embedded frame (typically
70-90 cols) — that's where detail loss is most visible, and where a splash
shown in a small terminal window has to still be recognizable.

### 5. Iterate

Re-run step 3 with adjusted `quadrant.py` flags (`--lo`, `--hi`,
`--fill-gain`, `--gamma`, `--cell-aspect`, `--buckets`) until step 4 looks
right. `make check` runs the unit tests and smoke-tests every
`render/*/show.sh` before you consider the work done.

## References

- `references/lessons-learned.md` — what broke across three prior
  generations of this renderer (single-glyph → half-block → quadrant-block)
  and the splash-specific design rule that came out of it. Read this before
  changing sizing/threshold/locale logic — every mistake documented there
  has already been made once.
- `references/frame-format.md` — the quadrant-block glyph table, the color
  bucket scheme, and the exact frame file format `embed.py` expects.

## Scripts

- `scripts/new-render.sh <name> [src.png]` — scaffolds `render/<name>/`
  without requiring `make` (same effect as `make new NAME=<name>
  SRC=src.png`; useful if invoked directly by an agent outside the repo's
  working directory conventions).
