How to turn a commit into something a creator can install.
pip install -r requirements-build.txt
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130
python scripts/build_installer.py
The torch line is not optional and not in requirements.txt. It cannot be:
the Windows wheel on PyPI is CPU-only, so the CUDA build is chosen by the index
you install from, and whichever one this machine happens to have is the one
that ships. Building on the default wheel produces an installer that works and
has no GPU support whatsoever. The build refuses to start in that case, and
warns if the CUDA is too old for current cards, but the reliable fix is to run
the line above.
One command, and it stops at the first failure with an explanation. Expect
about two and a half hours: 149 minutes at 0.1.0, nearly all of it
compressing 10 GB of payload twice, once into the .7z and once into the
.zip, and around 30 GB of free disk while it works.
The first run also downloads what the installer bundles but the repo does not
store. FFmpeg, the Ollama runtime and the Whisper weights, roughly 3 GB into
vendor/. That happens once; later builds find them and skip it. To refresh
one deliberately, run its script with --force:
python scripts/fetch_ffmpeg.py --force
python scripts/fetch_ollama.py --force # also re-run after bumping OLLAMA_VERSION
python scripts/fetch_whisper.py --force
--skip-backend and --skip-ui reuse the previous run's output. Use them
when only the icon or the packaging config changed, but never when
Python code changed, or you will ship a stale engine.
Everything lands in release/:
Measured at 0.1.0, the first build carrying the bundled runtime and weights:
| File | Size | What it is |
|---|---|---|
nsis-web/ClipsStudio-Web-Setup-<v>.exe |
813 KB | What people download. Fetches the payload and installs it. |
nsis-web/clips-studio-<v>-x64.nsis.7z |
5.88 GiB | The payload the setup downloads. |
nsis-web/latest.yml |
586 B | Version + SHA512 of both. The update checker reads this. |
ClipsStudio-<v>-x64.zip |
6.90 GiB | Offline alternative: unzip, run Clips Kitty.exe. |
Installed, that unpacks to about 10 GB. Roughly 4 GB of the growth is the bundled Ollama runtime and the two Whisper models; the rest is CUDA PyTorch, which was always the bulk of it.
Two destinations, and which file goes where is not a preference.
A GitHub release asset is capped at 2 GiB. The payload passed that before anything was bundled (2.09 GiB at 0.1.0) and carrying Ollama and the Whisper weights roughly doubles it. Uploading it to a release does not work, and no amount of retrying changes that.
So the big files live in a Hugging Face repository, which has no such cap,
costs nothing and serves from a CDN. This project already pushes to Hugging
Face for the website (see MIRRORS.md); this is a second repo,
ColinGPT9/clips-studio-releases, for release payloads.
| Where | What |
|---|---|
Hugging Face clips-studio-releases |
clips-studio-<v>-x64.nsis.7z, latest.yml, ClipsStudio-<v>-x64.zip |
| GitHub release | ClipsStudio-Web-Setup-<v>.exe and the release notes |
Tag the GitHub release to match the version in ui/package.json (v0.1.0 for
0.1.0).
The setup and its payload must go up together. The Web Setup fetches
clips-studio-<v>-x64.nsis.7zby name, from the URL in thepublishblock ofui/electron-builder.yml. Publish the setup before the payload has finished uploading and every download fails partway through with a confusing error, because the installer is a downloader with nothing to download.
Files that big need Git LFS on the Hugging Face side, or the hf CLI, which
handles the chunking itself:
hf upload ColinGPT9/clips-studio-releases release/nsis-web/ . --repo-type=model
huggingface-cli no longer works. It was deprecated and now exits with
"use hf instead" rather than uploading anything, so the old command in this
file silently did nothing. Upload one file at a time if you want to control the
order, which matters here. See the warning above about latest.yml.
Then paste the card. docs/hf-release-card.md is the README for that model
repo, and nothing uploads it: no workflow references the file at all. Copy it
into the Hugging Face web editor by hand after the upload. It is worth the
thirty seconds, because that card is what Hugging Face search and Google index
for the repo, and it drifts silently when skipped.
Expect it to be faster than the file sizes suggest. Hugging Face deduplicates against what is already in the repo, and consecutive releases share most of their bundled runtime, so a 6 GB payload can be a couple of hundred MB of genuinely new data.
The app never reads the GitHub releases API. electron-updater fetches one
YAML file from the Hugging Face repo and compares versions, so an update
exists the moment that file is uploaded, before you have written a single
line of release notes, and whether or not the GitHub release is still a draft.
Upload the payload first and the feed file last.
Channels are separate files rather than GitHub's pre-release flag, which only the GitHub provider understood:
| Channel in the app | Fetches | Falls back to |
|---|---|---|
| Stable (default) | latest.yml |
: |
| Beta | beta.yml |
latest.yml |
| Alpha | alpha.yml |
latest.yml |
The fallback is what keeps the old promise that alpha and beta users also see finished releases. It also means a pre-release channel with no file is not an error: between pre-releases those users quietly get the stable feed.
To ship something stable users must not be pulled onto, upload it as
alpha.yml or beta.yml and leave latest.yml alone.
All nine "Download for Windows" buttons across site/ link to
releases/download/v<version>/ClipsStudio-Web-Setup-<version>.exe, so they
have to be bumped with the version. The CI website job checks that internal
paths resolve; it cannot tell that an external GitHub URL now points at a
release that does not exist.
The two pages hosted on Vercel carry the version as well: VERSION in
whop-app/lib/content.ts (the Whop page) and in web/lib/content.ts (Clips
Kitty Web, the browser version). Each builds its download link from that value.
Bump both together, and only after the payload is on Hugging Face. Nothing
checks them: the browser version stayed on 1.1.3 through 1.1.4, 1.2.0 and 2.0.0.
The version-free releases/latest/download/... form would avoid this, but
GitHub's "latest" skips pre-releases, while the project ships alphas, that
URL 404s. Switch to it when a release goes out without the pre-release flag.
Check after publishing:
- Payload, zip and feed file uploaded to Hugging Face; Web Setup on the GitHub release
- Nothing over 2 GiB was attached to the GitHub release
- Tag matches
ui/package.json -
VERSIONbumped inwhop-app/lib/content.tsandweb/lib/content.ts - Feed file uploaded last, after the payload finished
- Named
alpha.yml/beta.ymlif stable users should not get it - Release notes mention the SmartScreen warning (see below)
- Release notes written for creators: they appear inside the app, in the update bar's "What's new"
- Downloaded the Web Setup on a machine that has never run Clips Kitty, and installed it end to end
A development machine has Python, FFmpeg and Ollama lying around, so it will pass an install test it should fail. The claim being made. Install one thing and nothing else: can only be checked somewhere none of that exists.
Windows Sandbox is the cheap way to get that: a throwaway Windows that boots clean and is destroyed on close.
-
BIOS: enable virtualization. On AMD it is called SVM Mode, usually under Advanced → CPU Configuration; on Intel, VT-x.
systeminforeportsVirtualization Enabled In Firmware: Yesonce it is on. -
Feature, in an admin PowerShell:
Enable-WindowsOptionalFeature -Online -FeatureName Containers-DisposableClientVM -All -
Launch
scripts/test-install.wsb:& "$env:WINDIR\System32\WindowsSandbox.exe" scripts\test-install.wsbDouble-clicking often does nothing: enabling the feature does not always register a handler for
.wsb, and Windows then has no idea what the file is. Launching the exe explicitly sidesteps it.The Web Setup lands on the sandbox desktop. Only
release/sandbox-testis mapped, which holds the installer and nothing else: mappingrelease/nsis-webwould put the payload beside it, and an installer that finds its payload locally never downloads one, which is the entire thing being tested.
What to confirm in there:
- The setup downloads its payload: this is the only real proof the Hugging Face URL baked into the exe is correct
- The wizard never asks you to install anything
- The model pull starts by itself and reports progress
- A clip renders end to end
Two things the sandbox cannot tell you. CUDA does not work in it, so the app will report no GPU and run on CPU: expected there, and no reflection on a real install. And everything is destroyed on close, including the ~6 GB it downloaded, so do not close the window mid-run.
No virtualization available? A second Windows user account is a weaker
substitute: it gives a clean %LOCALAPPDATA%, so the first-run wizard and the
per-user install are genuinely exercised, but system-wide Python and any Ollama
on the default port are still visible and the "nothing else needed" claim goes
untested.
Included: the Electron app, the frozen Python engine, every Python dependency, CUDA PyTorch, FFmpeg, the Ollama runtime, and the YOLO, TalkNet and Whisper weights. No Python install, no second installer, no PATH edits, no terminal. A creator installs Clips Kitty and nothing else.
The bundled Ollama listens on 127.0.0.1:11435, not its default 11434, so
it cannot collide with one the creator already runs. Electron starts it, tells
the engine where it is via CLIPS_STUDIO_OLLAMA_HOST, and kills the process
tree on quit. Its models go to %LOCALAPPDATA%\Clips Studio\data\models,
except on installs where 1.1.3 or 1.1.4 already downloaded them to
%LOCALAPPDATA%\Clips Kitty\data\models, which keep using that folder.
Not included: the language model itself. Not for packaging reasons. It would fit, but licensing ones: Gemma and friends ship under terms the person downloading has to accept, and bundling them would mean accepting on their behalf. It is also 5 GB whose right size depends on their VRAM. The app pulls it on first launch behind a progress bar, which works because Ollama's pull API reports progress; that is the same reason the Whisper weights are bundled, since their download has no such hook and looked exactly like a hang.
The app reports anything missing at GET /health/preflight, in words a
creator can act on.
Installed copies keep videos, clips and the database in
%LOCALAPPDATA%\Clips Studio\data, never inside Program Files. Uninstalling
leaves that alone: removing a program must not delete someone's footage.
The installer is not code-signed, so Windows shows "Windows protected your PC" on first run and the user has to click More info → Run anyway. Say so plainly in the release notes; a creator who was not warned assumes it is a virus and stops.
This clears once a certificate is bought (an OV certificate warns until it
builds reputation; an EV certificate does not warn at all). Signing is off
in ui/electron-builder.yml, and turning it back on is documented there.
Version lives in ui/package.json only. Bump it, commit, then build. The
artifact names and latest.yml follow from it.
The app ships a copy of Awesome Clips Kitty's index,
plugins/catalog_index.json: what the Marketplace shows before the app has been
online, and the copy it takes labels from. Before building, run
python scripts/sync_catalog_index.py and commit the file if it changed, so the
release carries the list as it is then.
Everything above is the standalone installer, which is the primary channel and the one this document is about. Two others exist and are deliberately separate so a problem in either cannot affect it.
python scripts/build_msix.py produces an appx from the same source. It is a
different wrapper, not a different app: the only runtime differences are that a
Store copy is updated by the Store rather than by electron-updater, and its
donate button opens the system browser. Both are decided at runtime in
ui/src/main/distribution.ts.
The package version is not the app version. The Store forbids a major of
0, so 0.1.2 ships as package 1.1.2.0. The script computes that; do not set it
by hand.
Full process in MSSTORE.md, and a tick-list for the first submission in msstore-checklist.md. Later releases use Start update on the existing Partner Center product: never a new product, which would discard the ratings and the Store URL.
packaging/winget/ points at the installer this
document already produces, so there is nothing extra to build. Each release
needs the version, URL and SHA256 updated in the manifest and a pull request to
microsoft/winget-pkgs. No account, no certificate, no certification.
| Rebuild needed | Where | |
|---|---|---|
| Installer | yes | GitHub release + Hugging Face payload |
| Microsoft Store | yes, separate appx | Partner Center → Start update |
| winget | no | manifest PR with the new URL and hash |