1- name : build game
1+ name : Build & Release
2+
23on :
34 release :
45 types : [published]
6+ workflow_dispatch :
7+ inputs :
8+ version :
9+ description : " Version tag for manual build (e.g. v0.1.0-test)"
10+ required : false
11+ default : " dev"
12+
13+ permissions :
14+ contents : write
15+
16+ defaults :
17+ run :
18+ shell : bash
519
620jobs :
7- build :
21+ # ─────────────────────────────────────────────────────────────────────────────
22+ # Desktop builds: Windows / macOS / Linux
23+ # ─────────────────────────────────────────────────────────────────────────────
24+ build-desktop :
25+ name : Desktop (${{ matrix.os }})
26+ runs-on : ${{ matrix.os }}
27+ env :
28+ VERSION : ${{ github.event.release.tag_name || inputs.version || 'dev' }}
29+ strategy :
30+ fail-fast : false
31+ matrix :
32+ os : [windows-latest, macos-latest, ubuntu-latest]
33+
34+ steps :
35+ - name : Checkout (with LFS)
36+ uses : actions/checkout@v4
37+ with :
38+ lfs : true
39+
40+ - name : Set up Python 3.12
41+ uses : actions/setup-python@v5
42+ with :
43+ python-version : " 3.12"
44+
45+ - name : Install uv
46+ uses : astral-sh/setup-uv@v4
47+
48+ - name : Install game dependencies
49+ run : uv sync
50+
51+ - name : Install PyInstaller
52+ run : uv pip install pyinstaller
53+
54+ # ── Icon conversion ────────────────────────────────────────────────────
55+ - name : Convert icon to ICO (Windows)
56+ if : runner.os == 'Windows'
57+ run : |
58+ uv pip install Pillow
59+ python -c "
60+ from PIL import Image
61+ img = Image.open('assets/fall_in_icon.png').convert('RGBA')
62+ img.save('assets/fall_in_icon.ico', sizes=[(16,16),(32,32),(48,48),(256,256)])
63+ "
64+
65+ - name : Convert icon to ICNS (macOS)
66+ if : runner.os == 'macOS'
67+ run : |
68+ mkdir -p assets/fall_in_icon.iconset
69+ for size in 16 32 128 256 512; do
70+ sips -z $size $size assets/fall_in_icon.png \
71+ --out assets/fall_in_icon.iconset/icon_${size}x${size}.png
72+ done
73+ iconutil -c icns assets/fall_in_icon.iconset \
74+ --out assets/fall_in_icon.icns
75+
76+ # ── ffmpeg setup ───────────────────────────────────────────────────────
77+ - name : Install ffmpeg (macOS)
78+ if : runner.os == 'macOS'
79+ run : brew install ffmpeg
80+
81+ - name : Install ffmpeg (Windows)
82+ if : runner.os == 'Windows'
83+ run : choco install ffmpeg -y
84+
85+ # ── BGM WAV → OGG ─────────────────────────────────────────────────────
86+ # Converts only bgm/ (68 MB → ~20 MB). sfx/ stays as WAV (5.7 MB).
87+ # OGG files are picked up automatically by asset_loader._resolve_sound_path().
88+ - name : Convert BGM WAV to OGG
89+ run : |
90+ for f in assets/sounds/bgm/*.wav; do
91+ ffmpeg -i "$f" -codec:a libvorbis -q:a 4 "${f%.wav}.ogg" -y
92+ rm "$f"
93+ done
94+
95+ # ── PyInstaller build ──────────────────────────────────────────────────
96+ - name : Build with PyInstaller
97+ run : uv run pyinstaller fall_in.spec
98+
99+ # ── Archive ───────────────────────────────────────────────────────────
100+ - name : Archive (Windows)
101+ if : runner.os == 'Windows'
102+ run : cd dist && zip -r "../fall-in-${VERSION}-windows.zip" fall-in/
103+
104+ - name : Archive (macOS)
105+ if : runner.os == 'macOS'
106+ run : cd dist && zip -r "../fall-in-${VERSION}-macos.zip" "Fall In.app/"
107+
108+ - name : Archive (Linux)
109+ if : runner.os == 'Linux'
110+ run : cd dist && tar -czf "../fall-in-${VERSION}-linux.tar.gz" fall-in/
111+
112+ # ── Upload artifact (always, for inspection) ──────────────────────────
113+ - name : Upload build artifact
114+ uses : actions/upload-artifact@v4
115+ with :
116+ name : fall-in-${{ runner.os }}-${{ env.VERSION }}
117+ path : fall-in-${{ env.VERSION }}-*
118+ retention-days : 7
119+
120+ # ── Upload to GitHub Release (release trigger only) ───────────────────
121+ - name : Upload to GitHub Release
122+ if : github.event_name == 'release'
123+ uses : softprops/action-gh-release@v2
124+ with :
125+ files : fall-in-${{ env.VERSION }}-*
126+
127+ # ─────────────────────────────────────────────────────────────────────────────
128+ # Web build: Pygbag (WebAssembly)
129+ # NOTE: Requires async game loop before this job succeeds.
130+ # GameManager.run() must use `await asyncio.sleep(0)`.
131+ # ─────────────────────────────────────────────────────────────────────────────
132+ build-web :
133+ name : Web (Pygbag)
8134 runs-on : ubuntu-latest
135+ env :
136+ VERSION : ${{ github.event.release.tag_name || inputs.version || 'dev' }}
137+
9138 steps :
10- - name : Checkout
139+ - name : Checkout (with LFS)
11140 uses : actions/checkout@v4
12- - name : Set up Python
13- uses : actions/setup-python@v4
14141 with :
15- python-version : ' 3.12'
142+ lfs : true
143+
144+ - name : Set up Python 3.12
145+ uses : actions/setup-python@v5
146+ with :
147+ python-version : " 3.12"
148+
149+ - name : Install uv
150+ uses : astral-sh/setup-uv@v4
151+
152+ - name : Install game dependencies
153+ run : uv sync
154+
155+ - name : Install Pygbag
156+ run : pip install pygbag
157+
158+ # ── BGM WAV → OGG ─────────────────────────────────────────────────────
159+ - name : Convert BGM WAV to OGG
160+ run : |
161+ for f in assets/sounds/bgm/*.wav; do
162+ ffmpeg -i "$f" -codec:a libvorbis -q:a 4 "${f%.wav}.ogg" -y
163+ rm "$f"
164+ done
165+
166+ # ── Stage assets next to game code ────────────────────────────────────
167+ # Pygbag requires assets to be reachable from the game folder.
168+ # _find_project_root() in config.py searches parent dirs of config.py,
169+ # so copying assets/ and data/ into src/fall_in/ makes them discoverable.
170+ - name : Stage assets for Pygbag
171+ run : |
172+ cp -r assets src/fall_in/assets
173+ cp -r data src/fall_in/data
174+
175+ # ── Pygbag build ──────────────────────────────────────────────────────
176+ - name : Build web (Pygbag)
177+ run : python -m pygbag --build src/fall_in
178+
179+ # ── Archive ───────────────────────────────────────────────────────────
180+ - name : Archive web build
181+ run : |
182+ cd src/fall_in/build
183+ zip -r "../../../fall-in-${VERSION}-web.zip" web/
184+
185+ # ── Upload artifact (always, for inspection) ──────────────────────────
186+ - name : Upload build artifact
187+ uses : actions/upload-artifact@v4
188+ with :
189+ name : fall-in-web-${{ env.VERSION }}
190+ path : fall-in-${{ env.VERSION }}-web.zip
191+ retention-days : 7
192+
193+ # ── Upload to GitHub Release (release trigger only) ───────────────────
194+ - name : Upload to GitHub Release
195+ if : github.event_name == 'release'
196+ uses : softprops/action-gh-release@v2
197+ with :
198+ files : fall-in-${{ env.VERSION }}-web.zip
0 commit comments