Thanks for your interest in contributing! This guide covers the most common ways to contribute.
Themes live in src/themes/{theme-id}/config.json (built-in) or ~/.claude-pet/themes/{theme-id}/config.json (user-created).
Create a folder with a config.json:
{
"name": "My Theme",
"type": "emoji",
"colors": {
"bgStart": "#1a1a2e",
"bgEnd": "#101020",
"accent": "100, 100, 255",
"text": "#e0e0ff"
},
"states": {
"idle": { "emoji": "🦊" },
"read": { "emoji": "📚" },
"write": { "emoji": "✏️" },
"bash": { "emoji": "💥" },
"search": { "emoji": "🔎" },
"task": { "emoji": "🤖" },
"web": { "emoji": "🌍" },
"success": { "emoji": "🎉" },
"error": { "emoji": "💔" },
"notification": { "emoji": "🔔" },
"stop": { "emoji": "💤" },
"unknown": { "emoji": "❓" }
}
}Colors (all optional — omit to use defaults):
| Key | Description | Default |
|---|---|---|
bgStart |
Background gradient start | #2a1810 |
bgEnd |
Background gradient end | #1a1008 |
accent |
Accent color as RGB values | 217, 119, 74 |
text |
Bubble text color | #e8c4a8 |
Use "type": "image" and provide image files:
{
"name": "Pixel Cat",
"type": "image",
"colors": { ... },
"states": {
"idle": { "src": "idle.gif" },
"read": { "src": "read.png" },
"write": { "src": "write.gif" },
"bash": { "src": "bash.gif" },
"search": { "src": "search.gif" },
"task": { "src": "task.gif" },
"web": { "src": "web.gif" },
"success": { "src": "success.png" },
"error": { "src": "error.png" },
"notification": { "src": "notification.gif" },
"stop": { "src": "stop.png" }
}
}Image files go in the same folder as config.json.
Image specs:
- Size: ~80x80px recommended (displayed at 40px, doubled for retina)
- Format: PNG for static, GIF for animated
- Background: transparent
Add a font field to use a custom font:
{
"font": "Arial"
}Or bundle a font file in the same theme folder:
{
"font": { "family": "MyPixelFont", "src": "my-font.ttf" }
}Place the .ttf/.woff2 file next to config.json in your theme folder.
- Create your theme in
src/themes/{theme-id}/ - Test it locally (it should appear in the right-click → Theme menu)
- Open a PR with your theme folder
UI translations are JSON files in src/locales/.
- Copy
src/locales/en.jsontosrc/locales/{code}.json(e.g.,ja.json) - Translate all values (keep the keys as-is)
- Add your language to
src/locales/index.json:
[
{ "code": "en", "name": "English" },
{ "code": "ko", "name": "한국어" },
{ "code": "ja", "name": "日本語" }
]- Open a PR
- Copy
README.mdtoREADME.{code}.md(e.g.,README.ja.md) - Translate the content
- Update the Translations line at the top of every existing README to include yours:
**Translations**: [English](./README.md) · [한국어](./README.ko.md) · [日本語](./README.ja.md)- Open a PR
git clone https://github.com/IMMINJU/claude-pet.git
cd claude-pet
npm install
npm run dev| Directory | Language | Description |
|---|---|---|
src/ |
JS/CSS/HTML | Frontend — UI, themes, i18n, state management |
src-tauri/src/ |
Rust | Backend — TCP server, hook sender, theme file loading |
| File | Purpose |
|---|---|
main.rs |
Entry point, Tauri builder |
hook_sender.rs |
--hook mode: stdin → TCP |
hook_setup.rs |
Auto-register hooks in ~/.claude/settings.json |
server.rs |
TCP listener → Tauri event emitter |
themes.rs |
Theme discovery, image loading (base64) |
| File | Purpose |
|---|---|
main.js |
Init, Tauri event listener, context menu, window drag |
sessions.js |
Session management, display rendering |
states.js |
Tool → state mapping (emoji, animation, stateId) |
themes.js |
Theme loading, colors, fonts, image cache |
i18n.js |
Translation loading, t() helper |
- JS: no build step, vanilla ES modules, no framework
- Rust: standard
cargo fmtformatting - Keep it simple — this is a tiny app, avoid over-engineering
Open an issue on GitHub.