Skip to content

Commit 761f6f6

Browse files
eblackrpsclaude
andcommitted
Initial release of NPCJason Desktop Pet v1.0.0
Pixel art desktop companion with system tray, dance animation, speech bubbles, and a full Windows installer build pipeline (PyInstaller + Inno Setup). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0 parents  commit 761f6f6

11 files changed

Lines changed: 995 additions & 0 deletions

.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# PyInstaller output
2+
dist/
3+
build/
4+
*.spec.bak
5+
6+
# Python cache
7+
__pycache__/
8+
*.pyc
9+
*.pyo
10+
*.pyd
11+
12+
# Generated icon (reproducible via generate_icon.py)
13+
npcjason.ico
14+
15+
# Inno Setup output (installers go in releases, not repo)
16+
NPCJason_Setup_*.exe
17+
18+
# Virtual environments
19+
venv/
20+
.venv/
21+
env/
22+
23+
# IDE / editor
24+
.vscode/
25+
.idea/
26+
*.sublime-project
27+
*.sublime-workspace
28+
29+
# OS artifacts
30+
Thumbs.db
31+
desktop.ini
32+
.DS_Store

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 NPCJason
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# NPCJason - Desktop Pet Companion
2+
3+
A pixel art NPC that lives on your Windows desktop and system tray.
4+
Click him to make him dance. He says random things throughout the day.
5+
6+
> **Screenshot:** *(add screenshots here)*
7+
8+
---
9+
10+
## Features
11+
12+
- **Pixel art character** rendered in real-time on your desktop
13+
- **System tray icon** - minimize to tray, access menu from notification area
14+
- **Dance animation** - click Jason to watch him bust a move
15+
- **Random sayings** - a mix of NPC humor, motivational quotes, and tech jokes
16+
- **Draggable** - move him anywhere on your desktop
17+
- **Speech bubbles** - floating popups with his wisdom
18+
- **Auto-sayings** - Jason speaks up every 3-8 minutes on his own
19+
20+
---
21+
22+
## For Users: Install the Easy Way
23+
24+
1. Download `NPCJason_Setup_1.0.0.exe` from the [Releases](../../releases) page
25+
2. Run the installer and follow the wizard
26+
3. NPCJason will appear on your desktop - no Python required!
27+
28+
The installer lets you choose:
29+
- Start Menu shortcut (always created)
30+
- Desktop shortcut (default: on)
31+
- Run on Windows startup (default: off)
32+
33+
To uninstall, use **Add or Remove Programs** in Windows Settings.
34+
35+
---
36+
37+
## For Developers: Build from Source
38+
39+
### Prerequisites
40+
41+
- Python 3.8+
42+
- pip
43+
- Windows 10/11
44+
45+
### Run from source
46+
47+
```bash
48+
pip install -r requirements.txt
49+
python npcjason.py
50+
```
51+
52+
### Build the standalone EXE
53+
54+
```bat
55+
build.bat
56+
```
57+
58+
This installs PyInstaller, generates the icon, and produces `dist\NPCJason.exe`.
59+
60+
### Build the installer (EXE + Inno Setup installer)
61+
62+
1. Install [Inno Setup 6](https://jrsoftware.org/isinfo.php)
63+
2. Run:
64+
65+
```bat
66+
build_installer.bat
67+
```
68+
69+
This produces both `dist\NPCJason.exe` and `NPCJason_Setup_1.0.0.exe` in the project root.
70+
71+
You can also compile the installer manually:
72+
73+
```bat
74+
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
75+
```
76+
77+
### Build files
78+
79+
| File | Purpose |
80+
|------|---------|
81+
| `generate_icon.py` | Creates `npcjason.ico` from pixel art (run before PyInstaller) |
82+
| `npcjason.spec` | PyInstaller spec file (reproducible builds) |
83+
| `installer.iss` | Inno Setup 6 installer script |
84+
| `build.bat` | One-click: install deps, generate icon, build EXE |
85+
| `build_installer.bat` | One-click: build EXE + compile Inno Setup installer |
86+
| `version_info.txt` | Windows EXE version metadata (embedded by PyInstaller) |
87+
88+
---
89+
90+
## Controls
91+
92+
| Action | What Happens |
93+
|--------|-------------|
94+
| Left-click | Jason dances + says something |
95+
| Right-click | Context menu (Dance, Say Something, Quit) |
96+
| Click + Drag | Move Jason anywhere on the desktop |
97+
| System tray icon | Show/Hide, Dance, Say Something, Quit |
98+
99+
---
100+
101+
## Customization
102+
103+
### Add your own sayings
104+
105+
Edit the `SAYINGS` list in `npcjason.py`:
106+
107+
```python
108+
SAYINGS = [
109+
"Your custom line here.",
110+
...
111+
]
112+
```
113+
114+
### Change the pixel art
115+
116+
Edit `FRAME_IDLE`, `FRAME_DANCE1`, `FRAME_DANCE2`, `FRAME_DANCE3` in `npcjason.py`.
117+
Each character maps to a color in the `PALETTE` dict. Use `.` for transparent pixels.
118+
119+
### Adjust timing
120+
121+
| Setting | Location | Default |
122+
|---------|----------|---------|
123+
| Dance frame speed | `_animation_loop`, `after(150, ...)` | 150 ms/frame |
124+
| Auto-saying interval | `_schedule_random_saying` | 3-8 min |
125+
| Speech bubble duration | `SpeechBubble.__init__`, `after(4000 + ...)` | ~4 sec + text |
126+
127+
---
128+
129+
## License
130+
131+
MIT - see [LICENSE](LICENSE)

build.bat

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@echo off
2+
echo === NPCJason EXE Build ===
3+
echo.
4+
5+
echo [1/3] Installing dependencies...
6+
pip install pyinstaller pystray Pillow --quiet
7+
if errorlevel 1 (
8+
echo ERROR: pip install failed. Make sure Python is on PATH.
9+
pause
10+
exit /b 1
11+
)
12+
13+
echo [2/3] Generating icon...
14+
python generate_icon.py
15+
if errorlevel 1 (
16+
echo ERROR: Icon generation failed.
17+
pause
18+
exit /b 1
19+
)
20+
21+
echo [3/3] Building EXE with PyInstaller...
22+
pyinstaller npcjason.spec --clean --noconfirm
23+
if errorlevel 1 (
24+
echo ERROR: PyInstaller build failed.
25+
pause
26+
exit /b 1
27+
)
28+
29+
echo.
30+
echo ============================================
31+
echo Build complete: dist\NPCJason.exe
32+
echo ============================================
33+
echo.
34+
pause

build_installer.bat

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
@echo off
2+
echo === NPCJason Full Build (EXE + Installer) ===
3+
echo.
4+
5+
echo [1/4] Installing dependencies...
6+
pip install pyinstaller pystray Pillow --quiet
7+
if errorlevel 1 (
8+
echo ERROR: pip install failed. Make sure Python is on PATH.
9+
pause
10+
exit /b 1
11+
)
12+
13+
echo [2/4] Generating icon...
14+
python generate_icon.py
15+
if errorlevel 1 (
16+
echo ERROR: Icon generation failed.
17+
pause
18+
exit /b 1
19+
)
20+
21+
echo [3/4] Building EXE with PyInstaller...
22+
pyinstaller npcjason.spec --clean --noconfirm
23+
if errorlevel 1 (
24+
echo ERROR: PyInstaller build failed.
25+
pause
26+
exit /b 1
27+
)
28+
29+
echo [4/4] Building installer with Inno Setup...
30+
set ISCC=
31+
if exist "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" (
32+
set ISCC=C:\Program Files (x86)\Inno Setup 6\ISCC.exe
33+
) else if exist "C:\Program Files\Inno Setup 6\ISCC.exe" (
34+
set ISCC=C:\Program Files\Inno Setup 6\ISCC.exe
35+
)
36+
37+
if not defined ISCC (
38+
echo.
39+
echo WARNING: Inno Setup 6 not found in default locations.
40+
echo EXE is ready at: dist\NPCJason.exe
41+
echo.
42+
echo To build the installer manually:
43+
echo 1. Install Inno Setup 6 from https://jrsoftware.org/isinfo.php
44+
echo 2. Run: "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
45+
echo.
46+
pause
47+
exit /b 0
48+
)
49+
50+
"%ISCC%" installer.iss
51+
if errorlevel 1 (
52+
echo ERROR: Inno Setup compilation failed.
53+
pause
54+
exit /b 1
55+
)
56+
57+
echo.
58+
echo ============================================
59+
echo EXE: dist\NPCJason.exe
60+
echo Installer: NPCJason_Setup_1.0.0.exe
61+
echo ============================================
62+
echo.
63+
pause

generate_icon.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""
2+
generate_icon.py - Creates npcjason.ico from pixel art.
3+
Produces a proper multi-resolution ICO file (16, 32, 48, 64, 256px).
4+
Run this before building with PyInstaller.
5+
"""
6+
7+
from PIL import Image, ImageDraw
8+
9+
10+
def make_npcjason_image(size: int) -> Image.Image:
11+
"""Draw the NPCJason pixel art face scaled to the given square size."""
12+
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
13+
draw = ImageDraw.Draw(img)
14+
15+
# All coordinates are defined for a 64x64 canvas, then scaled.
16+
s = size / 64.0
17+
18+
def r(x1, y1, x2, y2, fill, outline=None, width=1):
19+
coords = [x1 * s, y1 * s, x2 * s, y2 * s]
20+
if outline:
21+
draw.rectangle(coords, fill=fill, outline=outline, width=max(1, int(width * s)))
22+
else:
23+
draw.rectangle(coords, fill=fill)
24+
25+
# Hair
26+
r(14, 4, 50, 16, "#4a3728", "#1a1a2e", 1)
27+
# Head / skin
28+
r(16, 8, 48, 40, "#e8c170", "#1a1a2e", 2)
29+
# Eyes
30+
r(22, 20, 28, 26, "#16213e")
31+
r(36, 20, 42, 26, "#16213e")
32+
# Eye whites (small highlight)
33+
r(23, 21, 25, 23, "#ffffff")
34+
r(37, 21, 39, 23, "#ffffff")
35+
# Mouth / smile
36+
r(26, 30, 38, 35, "#c84b31")
37+
# Body / shirt
38+
r(20, 40, 44, 56, "#3a86c8", "#1a1a2e", 1)
39+
# Legs / pants
40+
r(22, 56, 30, 64, "#2d4263")
41+
r(34, 56, 42, 64, "#2d4263")
42+
43+
return img
44+
45+
46+
def generate_ico(output_path: str = "npcjason.ico"):
47+
sizes = [16, 32, 48, 64, 256]
48+
images = [make_npcjason_image(s) for s in sizes]
49+
50+
# Save as proper multi-resolution ICO.
51+
# Pillow uses the first image as the base; sizes kwarg embeds all resolutions.
52+
images[0].save(
53+
output_path,
54+
format="ICO",
55+
sizes=[(s, s) for s in sizes],
56+
append_images=images[1:],
57+
)
58+
print(f"Icon saved: {output_path} ({', '.join(str(s) for s in sizes)}px)")
59+
60+
61+
if __name__ == "__main__":
62+
generate_ico()

0 commit comments

Comments
 (0)