Metadata-Version: 2.4
Name: ttypal
Version: 0.1.0
Summary: Interactive braille art chatbot companion for your terminal
License-Expression: MIT
Requires-Python: >=3.10
Requires-Dist: numpy
Requires-Dist: opencv-python-headless
Requires-Dist: pillow
Provides-Extra: all
Requires-Dist: anthropic; extra == 'all'
Requires-Dist: flask; extra == 'all'
Requires-Dist: google-genai; extra == 'all'
Requires-Dist: openai; extra == 'all'
Requires-Dist: pyobjc-framework-quartz; (sys_platform == 'darwin') and extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic; extra == 'anthropic'
Provides-Extra: chat
Requires-Dist: google-genai; extra == 'chat'
Provides-Extra: gemini
Requires-Dist: google-genai; extra == 'gemini'
Provides-Extra: macos
Requires-Dist: pyobjc-framework-quartz; extra == 'macos'
Provides-Extra: openai
Requires-Dist: openai; extra == 'openai'
Provides-Extra: setup
Requires-Dist: flask; extra == 'setup'
Requires-Dist: google-genai; extra == 'setup'
Description-Content-Type: text/markdown

<div align="center">

# ttypal

**Your terminal companion that sees you.**

[![Python 3.10+](https://img.shields.io/badge/python-3.10+-3776AB?logo=python&logoColor=white)](https://python.org)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Platform: macOS](https://img.shields.io/badge/platform-macOS-000000?logo=apple&logoColor=white)](https://github.com)
[![Powered by Gemini](https://img.shields.io/badge/chat-Gemini-4285F4?logo=google&logoColor=white)](https://aistudio.google.com/apikey)

An anime character lives in your terminal — rendered as braille art, following your mouse,
blinking naturally, chatting with personality, and remembering you across sessions.

```
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⠤⣒⣒⣒⣶⣭⣭⣭⣭⣭⣭⣭⣹⣒⣒⣒⣒⣒⣒⣒⣒⠤⢄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⢤⣀⣴⣮⣭⣥⣤⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣭⣭⣍⡒⠈⠉⠐⠢⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡤⣶⣿⣶⣾⣷⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⡦⠀⠀⠠⣬⣁⠢⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⢖⣫⣷⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡙⢶⣌⣽⣿⣿⣷⣦⡙⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⢵⣺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⢷⣤⣹⣿⣿⣿⣿⣿⣿⣦⡈⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⣚⣽⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⡛⣨⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣌⢪⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⡡⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⡻⠁⠙⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⡜⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢁⢊⢜⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠻⣿⣿⣿⣿⠻⡼⣿⣿⣧⡁⢀⢳⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡐⢠⠀⢢⠚⠟⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡻⣿⣿⣿⣿⡿⠂⢹⣿⠃⠹⠀⣧⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⢁⣿⣧⠆⣠⣾⣁⣿⡿⠉⢿⣿⣿⣿⢿⣿⣿⣿⣿⣿⡟⢿⣿⣿⣿⠟⠟⠛⣿⣧⡹⣿⣷⢀⣈⣤⣦⣿⣏⣄⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡰⣌⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣏⣾⣿⣿⣾⣿⣿⣿⣿⢇⠀⢸⢡⠇⣆⣾⣿⣱⣿⢹⣼⡟⡸⡆⠙⣾⣧⠠⣄⢻⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠹⡓⢌⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⢋⣾⣿⣿⣿⣿⣿⣿⣿⣸⣾⣿⣿⣿⣿⣿⣿⣿⡇⠈⣿⣿⣷⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⢝⣆⠙⢈⠢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢡⠏⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡙⡦⡀⠃⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡁⢹⢸⣿⣿⣿⣿⣿⣿⣿⢻⣿⣿⣿⣿⣿⣿⡿⣿⣿⠀⠀⠀⠹⣿⡻⣿⣟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡘⡌⢣⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⢃⢸⣿⣿⣿⣿⣿⣿⣿⠤⣿⣿⣿⣿⣿⣿⡇⢿⣿⣤⣤⣤⠤⠬⠿⣬⠿⣧⡙⢿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢧⢹⡈⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡀⠘⣼⡟⣿⣿⣿⣿⣿⣿⣆⣌⢻⣿⠣⣻⣌⢧⠈⢻⡇⠀⢀⣀⡠⣄⣈⡑⠌⠳⢄⠈⠛⠷⣝⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⣉⠴⠒⡠⣌⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⣿⡼⢸⢱⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⣄⠈⢿⣾⣿⣿⣿⣿⣿⣿⠻⠷⣮⡳⡉⠣⡙⢆⠀⠙⢆⡳⠾⠛⢛⡿⢿⣿⣶⣶⣍⡀⠀⠀⠉⠀⣽⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⠿⠋⠀⠞⠓⠊⠀⠹⠘⡆⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢡⠃⢸⡸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⣸⠛⡎⣿⣻⣿⣿⣿⣆⢷⢿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⢻⣿⣯⠿⠿⠟⠃⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⡿⠃⢸⣿⠃⠀⡀⠏⠉⠉⡆⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢰⠁⢀⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⠁⢠⣣⠃⠙⣝⣿⣿⣿⠦⠷⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣬⠷⠬⠔⠛⠁⠀⠀⢀⣠⢟⣩⣿⣿⡿⣫⣾⠟⠀⠀⡸⠃⠀⣠⠞⠀⢀⠔⠃⠔⣡⣾⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⡽⡿⢩⢰⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡝⠁⠀⠀⡸⢫⣿⣻⠗⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢔⡶⠟⠋⣽⣽⠿⠋⢀⡟⠁⠀⠀⠀⠀⠀⠘⠋⠉⠉⠀⢀⣴⣾⣿⣿⣿⣿⣿⣿⣵⣿⣿⣼⣿⣿⣳⣟⣠⠅⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢇⠀⢀⠴⢃⢯⡾⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠋⠀⠀⢰⣽⠃⠀⠀⠈⢧⡀⠀⠀⠀⢀⡤⣤⣀⣠⣤⣾⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⡿⡿⡻⠋⢸⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⠸⣸⢻⠹⡝⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠣⠀⠀⠀⠈⢯⠀⠀⠀⠀⠀⠉⠀⠀⡴⠋⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣿⣿⡿⣻⠷⣹⡗⠁⠀⠘⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠀⠀⠀⠙⢾⣄⠹⣜⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠊⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⡾⡡⠊⠀⢳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣋⣦⡻⠃⠑⢙⠂⠐⠒⠒⠲⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢤⣀⣐⣡⠾⠋⢹⣿⣿⣿⣿⣿⣿⣿⣻⣿⠟⢿⠣⡇⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡴⠋⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠐⠀⠀⠀⠀⢀⠔⠉⠀⠀⠀⣀⣾⡽⢻⣿⣿⡿⣫⠟⢹⡇⠀⠈⠃⠉⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠘⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⠶⠚⠉⠀⠀⠀⠀⠀⢀⠔⠁⠀⠀⠀⠀⠉⢸⠋⠀⢸⣇⡟⢻⠁⠀⠈⠓⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⠤⠤⠤⠤⠖⠒⠊⠉⠁⠈⠻⡅⠀⠀⠀⠀⠀⢀⡤⠂⠁⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠈⢿⡀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⡄⠀⠀⡠⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡐⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
```

*Clawra — K-pop dreamer turned SF startup intern*

</div>

## Features

<table>
<tr>
<td width="50%">

**Eye Tracking**
25 pre-rendered views on a 5x5 directional grid.
Bilinear interpolation with smoothstep easing.
The character smoothly follows your cursor everywhere.

**Blink & Speak**
Natural blink timing with triangle-wave eyelid animation.
Mouth opens while the character talks.

**Multi-Provider Chat**
Press Enter to talk. Gemini, OpenAI, Claude, Ollama,
or OpenClaw — pick your LLM. Streaming responses with
markdown rendering. Personality from `soul.md`.

</td>
<td width="50%">

**Persistent Memory**
The character remembers you across sessions.
Tiered memory system (M0/M30/M90/M365) with
automatic fact extraction, daily diary, and
lessons learned.

**Create Your Own**
Bring reference images, write a `soul.md`, and
generate all 25 views + blinks via the browser UI.
Gemini can auto-generate personality from any character.

**Runs Anywhere**
Pure terminal — just Unicode braille (U+2800-U+28FF).
Views compressed to ~6MB npz. Auto-fits any terminal size.

</td>
</tr>
</table>

## Install

```bash
pip install ttypal[all]
```

<details>
<summary>Minimal installs</summary>

```bash
pip install ttypal              # Core only (rendering, no chat)
pip install ttypal[gemini]      # + Gemini chat
pip install ttypal[openai]      # + OpenAI / Ollama / OpenClaw chat
pip install ttypal[anthropic]   # + Claude chat
pip install ttypal[setup]       # + View generation UI (Flask + Gemini)
pip install ttypal[macos]       # + Global mouse tracking (Quartz)
```

</details>

<details>
<summary>Development (uv)</summary>

```bash
uv sync --all-extras
uv run ttypal
```

</details>

## Quick Start

```bash
ttypal
```

A setup wizard guides you through API key and character selection on first run.
Config is saved to `~/.ttypal/config.json`.

## Usage

```bash
ttypal                          # Start with default character
ttypal -c aska                  # Use a specific character
ttypal --no-chat                # Art-only mode (no chat panel)
ttypal --setup                  # Re-run setup wizard
ttypal --help                   # Show all options
```

```bash
ttypal-setup                    # Browser UI for generating views
ttypal-generate ref.png         # CLI batch view generation
ttypal-art                      # Terminal art showcase
```

**Controls:**

| Key | Action |
|-----|--------|
| `Enter` | Enter chat mode |
| `ESC` | Exit chat mode |
| `q` | Quit (outside chat) |
| `←` `→` | Move cursor in input |
| `↑` `↓` | Scroll chat history |
| `PgUp` `PgDn` | Scroll 5 lines |
| `Ctrl+U` | Clear input line |
| `Ctrl+W` | Delete last word |

## Preset Characters

| Character | Description |
|-----------|-------------|
| **Clawra** | K-pop trainee turned SF startup intern. Dances when nobody's watching. |
| **Aska** | Fierce EVA pilot from Berlin. Confident exterior, fragile interior. |
| **Reze** | The Bomb Girl from Chainsaw Man. Sweet surface, explosive depths. |

## Creating Custom Characters

```
1.  ttypal --setup → "Create custom character"
2.  Name + personality (auto-generate from existing character, or manual)
3.  Add reference images to characters/custom/<name>/refs/
4.  ttypal-setup -c <name> → generate & review 25 views + blinks
5.  Click "Finish & Pack NPZ" → calibrate gaze → done
```

<details>
<summary>Writing soul.md</summary>

`soul.md` is injected as the system prompt. Keep it under 200 words.

```markdown
You are Name.

[Backstory — 2-3 sentences. Age, origin, what shaped them.]

[Inner conflict — what drives them vs. what they fear.]

[Voice — HOW they talk. Tone, habits, quirks.
 "She rolls her eyes" > "She is sarcastic."]

[Rules — concrete do/don't for the LLM.]
```

Write in third person. Contradictions make characters feel real.
Voice matters more than lore.

</details>

## Architecture

```
                    ┌─────────────────────────────────┐
                    │          Terminal (stdout)        │
                    │  ┌───────────────────────────┐   │
                    │  │     Unicode Braille Art     │   │
                    │  │    (2x4 px → U+2800-28FF)  │   │
                    │  └─────────────┬─────────────┘   │
                    │                │                  │
                    │  ┌─────────────┴─────────────┐   │
                    │  │        Chat Panel           │   │
                    │  │    streaming + typing fx     │   │
                    │  └─────────────────────────────┘   │
                    └─────────────────────────────────┘

    Mouse Position ──→ ┌──────────────┐
    (Quartz/Terminal)  │  5x5 Grid    │──→ Bilinear Blend ──→ Frame
                       │  Interpolator │      + Blink/Mouth
                       └──────────────┘

    User Message ──→ ┌─────────┐ ──→ ┌──────────────┐
                     │ Gemini  │     │   Memory Mgr  │
                     │ Stream  │     │  ┌──────────┐ │
                     └─────────┘     │  │ soul.md  │ │ ← identity
                                     │  │ user.md  │ │ ← who you are
                                     │  │memory.md │ │ ← M0/M30/M90/M365
                                     │  │lessons.md│ │ ← patterns
                                     │  │ diary/   │ │ ← daily logs
                                     │  └──────────┘ │
                                     └──────────────┘
```

**Rendering pipeline:**

1. **Views** — 25 grayscale images (750x1000) generated via Gemini, covering all gaze directions
2. **Optical flow** — Dense flow fields between views, synthesizes missing midpoints
3. **Interpolation** — Bilinear blend on 5x5 grid + smoothstep easing + center dead zone
4. **Braille** — Otsu threshold → 2x4 pixel blocks → Unicode braille characters
5. **Memory** — Background extraction every 5 turns: facts, tiered memories with expiry, diary, lessons

## Project Structure

```
ttypal/
├── live.py                  # App class — runtime, rendering, interaction loop
├── config.py                # Setup wizard & config management
├── memory.py                # Tiered memory system (M0/M30/M90/M365)
├── generate_multiview.py    # Gemini-powered view generation (25 angles + blinks)
├── setup_views.py           # Flask browser UI for view generation
├── art.py                   # Terminal art showcase
└── characters/
    ├── preset/              # Built-in characters (read-only templates)
    │   ├── clawra/          #   soul.md + refs/ + views/views.npz
    │   ├── aska/
    │   └── reze/
    └── custom/              # User characters (copied from preset on first use)
        └── <name>/
            ├── soul.md      #   Personality definition
            ├── gaze.json    #   Gaze origin calibration
            ├── refs/        #   Reference images
            └── views/       #   views.npz (~6MB compressed)
```

## Requirements

- **Python** 3.10+
- **Terminal** with Unicode braille support (most modern terminals)
- **macOS** recommended — Quartz enables global mouse tracking across all apps. Other platforms use terminal-relative mouse events.
- **Gemini API key** (free) for chat and view generation — [get one here](https://aistudio.google.com/apikey)

## License

[MIT](LICENSE)
