<p align="center">
  <a href="https://github.com/TechyNilesh/chatui">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/TechyNilesh/chatui/main/assets/banner-dark.png">
      <img src="https://raw.githubusercontent.com/TechyNilesh/chatui/main/assets/banner-light.png" alt="chatui" width="480">
    </picture>
  </a>
</p>

<p align="center">
  <a href="https://ctan.org/pkg/chatui"><img src="https://img.shields.io/badge/CTAN-chatui-2F81F7?style=flat-square" alt="CTAN"></a>&nbsp;
  <a href="chatui.sty"><img src="https://img.shields.io/badge/version-1.0.0-2E9E5B?style=flat-square" alt="Version"></a>&nbsp;
  <a href="https://www.latex-project.org/lppl.txt"><img src="https://img.shields.io/badge/License-LPPL%201.3c-C8871E?style=flat-square" alt="LPPL 1.3c License"></a>&nbsp;
  <a href="chatui-doc.pdf"><img src="https://img.shields.io/badge/Docs-chatui--doc.pdf-7C5CFC?style=flat-square" alt="Documentation"></a>&nbsp;
  <a href="https://github.com/TechyNilesh/chatui/stargazers"><img src="https://img.shields.io/github/stars/TechyNilesh/chatui?style=flat-square&color=E5A73B&label=stars" alt="GitHub stars"></a>
</p>

<p align="center">
  <a href="#preview">Preview</a> &nbsp;&bull;&nbsp;
  <a href="#install">Install</a> &nbsp;&bull;&nbsp;
  <a href="#using-on-overleaf">Overleaf</a> &nbsp;&bull;&nbsp;
  <a href="#usage">Usage</a> &nbsp;&bull;&nbsp;
  <a href="#environments">Environments</a> &nbsp;&bull;&nbsp;
  <a href="#customizing-colors">Customization</a> &nbsp;&bull;&nbsp;
  <a href="#examples">Examples</a> &nbsp;&bull;&nbsp;
  <a href="chatui-doc.pdf">Full docs</a>
</p>

A LaTeX package for typesetting AI chat transcripts: user/assistant messages,
reasoning ("thinking") traces, tool-call traces, and image/file attachments,
styled as a **terminal**, **web**, or **desktop** chat UI, in light or dark
theme.

## Preview

| Web | Terminal (dark) |
|---|---|
| ![web style](https://raw.githubusercontent.com/TechyNilesh/chatui/main/assets/screenshots/web.png) | ![terminal style](https://raw.githubusercontent.com/TechyNilesh/chatui/main/assets/screenshots/terminal.png) |

| Desktop | Tool-call kinds (cli / code / api) |
|---|---|
| ![desktop style](https://raw.githubusercontent.com/TechyNilesh/chatui/main/assets/screenshots/desktop.png) | ![tool-call kinds](https://raw.githubusercontent.com/TechyNilesh/chatui/main/assets/screenshots/tool-calling.png) |

More combinations (light/dark per style, attachments, page breaks, custom
themes) are in [`examples/`](examples/).

## Install

**Quickest:** drop `chatui.sty` next to your `.tex` file. Works anywhere,
no path setup needed.

**From CTAN**, once published: `tlmgr install chatui` (TeX Live) or via the
MiKTeX package manager.

**From GitHub**, for the latest version before it hits CTAN, or to track a
specific commit:

```sh
git clone https://github.com/TechyNilesh/chatui.git
```

Then either copy `chatui.sty` next to your project, or install it into your
personal texmf tree so every document on your machine can find it:

```sh
mkdir -p "$(kpsewhich -var-value TEXMFHOME)/tex/latex/chatui"
cp chatui/chatui.sty "$(kpsewhich -var-value TEXMFHOME)/tex/latex/chatui/"
texhash "$(kpsewhich -var-value TEXMFHOME)"   # or: mktexlsr
```

(`kpsewhich -var-value TEXMFHOME` prints your personal texmf root, e.g.
`~/texmf` on Linux, `~/Library/texmf` on macOS, or
`%USERPROFILE%\texmf` on Windows with MiKTeX.)

## Using on Overleaf

Overleaf doesn't have a texmf tree you can install into directly, but a
single `.sty` file works fine as a project upload:

1. Download
   [`chatui.sty`](https://raw.githubusercontent.com/TechyNilesh/chatui/main/chatui.sty)
   (right-click -> Save As, or `curl -O` it).
2. In your Overleaf project, click **New File -> Upload** (or drag and drop)
   and add `chatui.sty` to the project root, the same folder as your main
   `.tex` file.
3. Use it exactly as documented: `\usepackage[style=web]{chatui}`.

No further setup needed. Overleaf finds any `.sty` file sitting next to
your document automatically.

Once `chatui` is accepted on CTAN, Overleaf will eventually pick it up
through its own periodic TeX Live sync, and `\usepackage{chatui}` will work
without uploading anything. That sync isn't instant though, so the manual
upload above is the reliable path in the meantime.

## Usage

```latex
\usepackage[style=web]{chatui}   % style = terminal | web | desktop

\begin{chatconversation}[chat.example.com]

\begin{chatuser}[John Doe]
How do I show tool calls in a LaTeX paper?
\end{chatuser}

\begin{chatthinking}
\tstep{User wants a reusable way to render tool-call traces.}
\tstep{A titled box with a monospace body fits best.}
\end{chatthinking}

\begin{chattool}{web_search}
\toolargs{query="latex tool call trace package"}
\toolresult{3 results found.}
\end{chattool}

\begin{chatassistant}
Use the \texttt{chattool} environment: it renders a titled box with a
status glyph, plus \texttt{\textbackslash toolargs} and
\texttt{\textbackslash toolresult} helpers.
\end{chatassistant}

\end{chatconversation}
```

## Environments

| Environment | Purpose |
|---|---|
| `chatconversation[title]` | Outer window chrome (terminal bar / browser bar / macOS title bar) |
| `chatuser[name]` | User message bubble |
| `chatassistant[name]` | Assistant message bubble |
| `chatthinking[title][mode]` | Reasoning/thinking trace box. `mode` = `steps` (default, use `\tstep{...}` per bullet) \| `paragraph` (plain upright prose). |
| `chattool[status][kind]{name}` | Tool-call trace box. `status` = `ok` \| `error` \| `running`. `kind` = `api` (default, "tool: name" chip) \| `cli` (shell-style "$ name") \| `code` (function-call style "</> name"). Use `\toolargs{...}`, `\toolresult{...}`, and `\tooljson{...}` inside. |

`\chatimage[width]{path}` and `\chatfile{name}{size}`: use inside
`chatuser`/`chatassistant` (or standalone) to show an attached image or
file. `\chatimage` clips to the bubble's own corner radius; `\chatfile`
renders a small bordered chip with a document icon, filename, and size.
See `examples/x-tool-kinds/example-attachments.tex`.

## Package options

- `style`: `terminal` (monospace, shell-prompt look), `web` (rounded chat
  bubbles + browser chrome, default), or `desktop` (macOS-style window with
  traffic-light dots).
- `theme`: `auto` (default: terminal is dark, web/desktop are light),
  `light`, or `dark`. Dark mode uses the same palette across all three
  styles.

## Customizing colors

Every color is a plain `xcolor` name, redefine any of them after loading
the package, with a named color, a mix, or a raw hex code:

```latex
\usepackage[style=web]{chatui}
\colorlet{chatuiUserBg}{teal}                    % named xcolor
\colorlet{chatuiAssistantBg}{gray!10}             % mixed
\definecolor{chatuiToolAccent}{HTML}{7C5CFC}      % raw hex
```

Available: `chatuiUserBg/Fg`, `chatuiAssistantBg/Fg/Border`,
`chatuiThinkBg/Border/Fg`, `chatuiToolBg/Border/Accent`,
`chatuiOk`, `chatuiErr`, `chatuiWarn` (status glyphs and `chattool` accents),
plus the window-chrome colors `chatuiAppBg/Text/Chrome/ChromeText`,
`chatuiAppPillBg/Border/Text` (web/desktop) and the `chatuiTerm*` family
(terminal style). See `examples/x-tool-kinds/example-custom-theme.tex` for
a worked example.

## Customizing fonts

Two hooks control every font family in the package. Redefine them after
`\usepackage` (and after loading any font package you want to use):

```latex
\usepackage{fourier}                                % example serif font
\renewcommand{\chatuiFontSans}{\rmfamily}            % web/desktop bubbles, prose
\renewcommand{\chatuiFontMono}{\ttfamily}            % terminal + tool/code text
```

Only sizing (`\small`, `\scriptsize`) is fixed internally, tuned to each
box's proportions; the family is entirely yours to swap.

## Long conversations and page breaks

The outer `chatconversation` window is breakable and splits cleanly across
pages: the chrome (title bar, dots) only draws once, on the first page,
and the border/background continue seamlessly on later pages. Individual
messages, reasoning boxes, and tool calls are each a single atomic unit
(they don't break mid-box), so a page break always falls *between* two
messages, never through the middle of one, matching how a real chat UI
never splits a single message bubble. A message far longer than a full
page is an unsupported edge case. See
`examples/x-tool-kinds/example-long-conversation.tex`.

## Examples

Organized by style under `examples/`:

```
examples/
  desktop/       example-desktop-light.tex, example-desktop-dark.tex
  terminal/      example-terminal-light.tex, example-terminal-dark.tex
  web/           example-web-light.tex, example-web-dark.tex
  x-tool-kinds/  example-tool-kinds.tex  (cli/code/api tool calls, JSON, reasoning modes)
```

Dark theme uses the same palette across all three styles. Pass
`theme=dark` explicitly, or leave `theme` unset with `style=terminal`
(terminal defaults to dark; web/desktop default to light).

Each `.tex` file has a matching `.pdf` already built alongside it. To
recompile one yourself, point `TEXINPUTS` two levels up so `pdflatex` can
find `chatui.sty`:

```sh
cd examples/web
TEXINPUTS=../..: pdflatex example-web-light.tex
```

## Requirements

`tcolorbox` (`[most]` libraries), `tikz`, `etoolbox`, `kvoptions`, `xcolor`,
`pifont`. All standard, on any full TeX Live / MiKTeX install.

## Citation

If `chatui` is useful in a paper, report, or other published work, please
cite it:

```bibtex
@software{chatui2026,
  author  = {Verma, Nilesh},
  title   = {{chatui}: A LaTeX Package for Typesetting AI Chat Transcripts},
  year    = {2026},
  version = {1.0.0},
  url     = {https://github.com/TechyNilesh/chatui},
  note    = {LaTeX Project Public License (LPPL) 1.3c}
}
```

A machine-readable citation is also available in `CITATION.cff` (GitHub
surfaces this automatically via the "Cite this repository" button).

## License

LPPL 1.3c. See `LICENSE`.
