Packaging InsightUX as a downloadable installer
Turns the cloned-repo-plus-venv workflow into a single Windows installer
(InsightUX-Setup-<version>.exe) that bundles Python, torch, mediapipe,
onnxruntime, opencv, and pywebview β end users need nothing pre-installed.
One-time setup (per machine you build from)
- In the project venv:
pip install pyinstaller - Install Inno Setup 6 (free) β provides
ISCC.exe, the command-line compilerinstaller.issneeds. Not required just to build the app itself, only to build the final installer. - (Optional but recommended) Download Microsoft's WebView2 bootstrapper
(
MicrosoftEdgeWebview2Setup.exe) from Microsoft's evergreen bootstrapper page and place it in thispackaging/folder before compiling the installer βinstaller.issbundles and silently runs it if present, as a safety net for machines missing the WebView2 Runtime (usually already present on modern Windows 10/11, but not guaranteed on older/locked-down machines). If you skip this, the installer still builds fine, just without that safety net.
Build
From the repo root:
pyinstaller packaging\InsightUX.spec --noconfirm
Output: dist\InsightUX\ (a folder β InsightUX.exe + _internal\). Run
dist\InsightUX\InsightUX.exe directly first to confirm it actually starts
before building the installer β much faster to debug a missing-DLL/missing-
data-file error at this stage than after wrapping it in an installer.
Expect to iterate on the first build. mediapipe, torch, and onnxruntime
all ship native binaries and non-.py data files that PyInstaller's default
hooks don't always fully catch β see the comments at the top of
InsightUX.spec for what's already collected and where to look if the
frozen exe fails to start.
Then build the installer:
iscc packaging\installer.iss
Output: packaging\dist_installer\InsightUX-Setup-<version>.exe.
Release checklist
Every time you ship a code change as an update:
- Bump
VERSIONin browser_session.py. - Bump
AppVersion/MyAppVersionin installer.iss to match. - Rebuild (
pyinstaller ...theniscc ...). - Update version.json at the repo root β
"latest"to the new version,"url"to the new installer's HF download URL. git lfstracks*.exealready (see.gitattributes) β add and push the new installer +version.jsonto theorigin(Hugging Face) remote.
That's it β nothing about publishing a release is automated. What's
automated is the checking: every running copy of InsightUX pings
version.json once at startup (check_for_update() in browser_session.py)
and shows a clickable "Update available" pill in the toolbar if "latest"
is newer than its own VERSION. Clicking it opens "url" in the user's
default browser β still a manual download+run, just automated the "is there
something new" question. No internet, or any failure fetching the file, is
silent (no banner, never an error).
Why these choices
- Onedir, not onefile β onefile re-extracts the whole ~1.5-2.5GB bundle to a temp directory on every launch. With torch/mediapipe already this heavy, that's a genuinely bad startup-time hit. Onedir just runs directly from the installed folder.
- Per-user install (
{localappdata}), not Program Files β no admin/UAC prompt, and avoids Program Files' write-permission restrictions forcalibration.pkl/sessions/, which the running app writes directly into its own folder (seeRESOURCE_DIR/DATA_DIRin browser_session.py). - Fixed
AppIdGUID in installer.iss β this is what makes a new installer upgrade the existing install in place instead of creating a second copy. Never regenerate it. - torch is bundled (not excluded) β its fine-tuning step measurably improves calibration accuracy (169-204px mean error vs. 275px without it, per calibrate.py's own numbers). Confirmed with the project owner as worth the larger download.