Skip to content

Commit 2d4e155

Browse files
Flossyclaude
andcommitted
Add cross-repo theme documentation and migration guide (fixes #268)
Adds cross-language theme sharing section to themes.md, a new MIGRATION.md guide for Java<->Python theme conversion, and a cross-repo link in README. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c03f972 commit 2d4e155

3 files changed

Lines changed: 211 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,10 @@ Make sure the terminal window has focus and you're running directly (not through
468468
- **[TESTING.md](TESTING.md)** - Unit testing guide
469469
- **[QUICKSTART.txt](QUICKSTART.txt)** - Quick reference card
470470

471+
## Related Projects
472+
473+
- **[curses-themes](https://github.com/FlossWare/curses-themes)** -- Python curses theme library that can load curses-java JSON themes directly via auto-detection. See [Migration Guide](docs/MIGRATION.md).
474+
471475
## 📄 License
472476

473477
Apache License 2.0 - See [LICENSE](LICENSE) file

docs/MIGRATION.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Theme Migration Guide: Java <-> Python
2+
3+
This guide covers converting themes between [curses-java](https://github.com/FlossWare/curses-java) (Java) and [curses-themes](https://github.com/FlossWare/curses-themes) (Python).
4+
5+
## Java Theme -> Python
6+
7+
**No manual work required.** Python auto-detects Java JSON format and converts on load:
8+
9+
```python
10+
from curses_themes import ThemeManager
11+
12+
# Load any Java-exported JSON theme directly
13+
theme = ThemeManager.load_from_file("themes/borland3d.json")
14+
theme.apply(stdscr)
15+
```
16+
17+
The adapter handles all format differences (color names, border ordering, 3D keys) transparently.
18+
19+
## Python Theme -> Java
20+
21+
Manual conversion is needed. Create a JSON file matching the [schema](../themes/schema.json):
22+
23+
```json
24+
{
25+
"name": "My Theme",
26+
"version": "1.0",
27+
"description": "Theme description",
28+
"colors": {
29+
"background": { "fg": "WHITE", "bg": "BLACK" },
30+
"button": { "fg": "CYAN", "bg": "BLACK" },
31+
"button_focused": { "fg": "BLACK", "bg": "CYAN" },
32+
"text_input": { "fg": "GREEN", "bg": "BLACK" },
33+
"border": { "fg": "WHITE", "bg": "BLACK" },
34+
"selection": { "fg": "BLACK", "bg": "WHITE" },
35+
"disabled": { "fg": "BLACK", "bg": "BLACK" }
36+
},
37+
"borders": {
38+
"single": "+-+||+-+"
39+
}
40+
}
41+
```
42+
43+
Then load in Java:
44+
45+
```java
46+
ThemeManager.getInstance().loadThemeFromJson("path/to/my-theme.json");
47+
```
48+
49+
### Converting Python RGB to Java Color Names
50+
51+
Map your Python RGB values to the nearest ncurses name:
52+
53+
| ncurses Name | RGB Equivalent |
54+
|-------------|----------------|
55+
| `BLACK` | (0, 0, 0) |
56+
| `RED` | (255, 0, 0) |
57+
| `GREEN` | (0, 255, 0) |
58+
| `YELLOW` | (255, 255, 0) |
59+
| `BLUE` | (0, 0, 255) |
60+
| `MAGENTA` | (255, 0, 255) |
61+
| `CYAN` | (0, 255, 255) |
62+
| `WHITE` | (255, 255, 255)|
63+
64+
## Key Differences
65+
66+
| Aspect | Java (curses-java) | Python (curses-themes) |
67+
|--------|-------------------|----------------------|
68+
| **Color values** | ncurses names: `"CYAN"`, `"BLUE"` | RGB tuples: `(0, 255, 255)` |
69+
| **Border char order** | TL, T, TR, L, **BL, B, BR**, R | TL, T, TR, L, **R, BL, B**, BR |
70+
| **3D shadow key** | `shadow_color` | `shadow` |
71+
| **3D highlight key** | `highlight_color` | `highlight` |
72+
| **3D lowlight key** | `lowlight_color` | `lowlight` |
73+
| **3D offset** | `shadow_offset: { "x": 2, "y": 1 }` | `shadow_offset_x: 2`, `shadow_offset_y: 1` |
74+
| **Color structure** | `colors` object with component pairs | `colors` (semantic) + `components` (pairs) |
75+
76+
### Border Character Order Detail
77+
78+
Java uses an 8-character string: `TL T TR L BL B BR R`
79+
80+
```
81+
Position: 0 1 2 3 4 5 6 7
82+
Java: TL T TR L BL B BR R
83+
Python: TL T TR L R BL B BR
84+
```
85+
86+
Example -- the string `"+-+||+-+"`:
87+
- **Java reads:** `+` `-` `+` `|` `|` `+` `-` `+` (positions 4-5 = BL, B)
88+
- **Python reads:** `+` `-` `+` `|` `|` `+` `-` `+` (positions 4-5 = R, BL)
89+
90+
The Python adapter swaps positions 4/7 and 5/6 automatically when loading Java JSON.
91+
92+
## Creating Themes That Work in Both
93+
94+
Write your theme in **Java JSON format** (the source-of-truth format). Both libraries can consume it:
95+
96+
- **Java**: loads it natively via `loadThemeFromJson()`
97+
- **Python**: auto-detects and converts via `load_from_file()`
98+
99+
Minimal example:
100+
101+
```json
102+
{
103+
"name": "Shared Theme",
104+
"version": "1.0",
105+
"colors": {
106+
"background": { "fg": "WHITE", "bg": "BLACK" },
107+
"button": { "fg": "CYAN", "bg": "BLACK" },
108+
"button_focused": { "fg": "BLACK", "bg": "CYAN" },
109+
"text_input": { "fg": "GREEN", "bg": "BLACK" },
110+
"border": { "fg": "WHITE", "bg": "BLACK" },
111+
"selection": { "fg": "BLACK", "bg": "WHITE" },
112+
"disabled": { "fg": "BLACK", "bg": "BLACK" }
113+
},
114+
"borders": {
115+
"single": "+-+||+-+"
116+
}
117+
}
118+
```
119+
120+
For 3D support, add the `3d` block:
121+
122+
```json
123+
{
124+
"3d": {
125+
"shadow_color": { "fg": "BLACK", "bg": "BLACK" },
126+
"highlight_color": { "fg": "WHITE", "bg": "CYAN" },
127+
"lowlight_color": { "fg": "BLACK", "bg": "CYAN" },
128+
"shadow_offset": { "x": 2, "y": 1 },
129+
"rendering_style": "RAISED"
130+
}
131+
}
132+
```
133+
134+
## Schema Reference
135+
136+
The shared JSON schema is at [`themes/schema.json`](../themes/schema.json). It defines:
137+
138+
- **Required fields:** `name`, `version`, `colors`, `borders`
139+
- **Color values:** ncurses name strings or RGB arrays `[r, g, b]`
140+
- **Border strings:** exactly 8 characters (TL, T, TR, L, BL, B, BR, R)
141+
- **3D block:** optional, requires `shadow_color`, `highlight_color`, `lowlight_color`, `shadow_offset`
142+
143+
Validate a theme file against the schema:
144+
145+
```bash
146+
# Using ajv-cli
147+
npx ajv validate -s themes/schema.json -d themes/my-theme.json
148+
149+
# Using Python jsonschema
150+
python3 -c "
151+
import json, jsonschema
152+
schema = json.load(open('themes/schema.json'))
153+
theme = json.load(open('themes/my-theme.json'))
154+
jsonschema.validate(theme, schema)
155+
print('Valid')
156+
"
157+
```

docs/themes.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,3 +1098,53 @@ Themes are part of the curses-java library and are distributed under the same li
10981098
---
10991099

11001100
For more information about curses-java, visit the main project documentation.
1101+
1102+
## Cross-Language Theme Sharing
1103+
1104+
curses-java themes are portable. The Java library exports all 12 themes as JSON files in `/themes/`, and the Python [curses-themes](https://github.com/FlossWare/curses-themes) library can consume them directly.
1105+
1106+
### How It Works
1107+
1108+
1. Java is the **source of truth** -- themes are defined as Java classes and exported to JSON via `ThemeLoader`
1109+
2. Python's `ThemeManager.load_from_file()` auto-detects the Java JSON format and converts it at load time
1110+
3. No manual conversion step is needed
1111+
1112+
### Using Java Themes in Python
1113+
1114+
```python
1115+
from curses_themes import ThemeManager
1116+
1117+
# Load a single Java-exported theme
1118+
theme = ThemeManager.load_from_file("path/to/dark.json")
1119+
theme.apply(stdscr)
1120+
1121+
# Load all themes from a directory
1122+
ThemeManager.load_themes_from_directory("path/to/themes/")
1123+
```
1124+
1125+
### Format Differences Handled Automatically
1126+
1127+
The Python adapter transparently handles these conversions when loading Java JSON:
1128+
1129+
| Aspect | Java JSON Format | Python Native Format |
1130+
|--------|-----------------|---------------------|
1131+
| Colors | ncurses names (`"CYAN"`, `"BLUE"`) | RGB tuples (`(0, 255, 255)`) |
1132+
| Border char order | TL, T, TR, L, **BL, B, BR**, R | TL, T, TR, L, **R, BL, B**, BR |
1133+
| 3D keys | `shadow_color`, `highlight_color`, `lowlight_color` | `shadow`, `highlight`, `lowlight` |
1134+
| 3D offsets | `shadow_offset: { x, y }` | `shadow_offset_x`, `shadow_offset_y` |
1135+
| Color structure | `colors` (component pairs only) | `colors` (semantic) + `components` (pairs) |
1136+
1137+
### API Mapping
1138+
1139+
| Java | Python | Description |
1140+
|------|--------|-------------|
1141+
| `ThemeManager.getInstance().useTheme(name)` | `ThemeManager.load(name)` | Load built-in theme by name |
1142+
| `ThemeManager.getInstance().getAvailableThemes()` | `ThemeManager.list_themes()` | List available theme names |
1143+
| `ThemeManager.getInstance().loadThemeFromJson(path)` | `ThemeManager.load_from_file(path)` | Load theme from JSON file |
1144+
| `ThemeManager.getInstance().loadThemesFromDirectory(path)` | `ThemeManager.load_themes_from_directory(path)` | Load all themes in a directory |
1145+
1146+
### See Also
1147+
1148+
- [curses-themes (Python)](https://github.com/FlossWare/curses-themes) -- Python curses theme library with Java theme auto-detection
1149+
- [Migration Guide](MIGRATION.md) -- detailed Java-to-Python and Python-to-Java theme conversion
1150+
- [Theme JSON Schema](../themes/schema.json) -- shared schema for cross-language themes

0 commit comments

Comments
 (0)