# Distribution & release mechanics How the build becomes an install on someone's PC. **Policy — prices, entitlement, why Steam is the only channel, support — is [`docs/ai/commercial.md`](docs/ai/commercial.md).** This file is the how. > Superseded twice on 2026-10-31. The 736-line Polar/MSIX/obfuscation plan is in > `git log -- Distribution.md`; the zip-plus-winget plan written earlier the same day is in the > same place. The reasoning that survives lives in `commercial.md` and `docs/ai/decisions.md`. ## 1. The artifact A self-contained win-x64 publish plus the bundled `ffmpeg\` folder, uploaded to a Steam depot. No installer, no admin rights, no zip for anyone to mirror. ```bash dotnet publish ytLive.csproj -c Release -r win-x64 --self-contained true \ -p:PublishSingleFile=true \ -p:IncludeNativeLibrariesForSelfExtract=true \ -p:EnableCompressionInSingleFile=true \ -p:PublishReadyToRun=true -o artifacts/steam-stage ``` - **`PublishTrimmed` stays OFF.** Trimming breaks WPF's XAML reflection (`Binding`, `DataTemplate`, `StaticResource`). Expect ~110–150 MB in the depot; that is the cost of "no .NET install". - **ffmpeg stays outside the exe** — `ffmpeg\` beside it (the app's locator contract, see [`output.md`](output.md) → "FFmpeg locator"). - **`steam_api64.dll` ships beside the exe** and is loaded at startup; without it the app cannot read DLC ownership. Its absence must degrade to the free profile, never to a crash. - **WebView2 is the one machine dependency.** Valve's Common Redistributables configure the Evergreen bootstrapper as a prerequisite, so the depot declares it instead of us shipping it. - **`AssemblyName` is still `ytLive`** → the exe is `ytLive.exe` today. The rename to `LlamaCasty.exe` is queued (three pack URIs break — see `product.md`), and **must land before the first depot upload**, because Steam's docs are explicit that renaming a live exe is painful. - **Portable mode** (`portable.txt` → `.\data\`) survives as a feature for a copied install; it is not a delivery vector. ## 2. Steamworks setup, once 1. **Steamworks account** → onboarding (NDA, identity, company details, tax interview, payout bank, then the **$100 Steam Direct fee** per app). The store page cannot be configured before the fee. 2. **App IDs.** One **base app** (free) and one **DLC app** (the lifetime Pro). Note both numbers: the DLC app ID is what the app passes to `BIsDlcInstalled`. 3. **Depot.** One depot holding the publish output; the base app and the DLC share the install directory, and the DLC package grants no files of its own — it is entitlement only. 4. **Steamworks SDK.** Drop `steam_api64.dll` (+ `steam_appid.txt` for local runs) into the publish output; the managed side is a thin wrapper (`Steamworks.NET` or hand-written interop) behind `IEntitlement`. 5. **Store page** configured and made public **two weeks before release** — Valve's rule, and it is the window where wishlists accumulate. ## 3. Release ``` publish → steam-stage → steamcmd + app_build.vdf → build upload → set live → announcement ``` 1. **Upload the depot** with `steamcmd +login +run_app_build ..\scripts\app_build_.vdf +quit`. The VDF names the app, depot, content root and branch. 2. **Set the build live** in Steamworks → *Builds* → the new build → **Set Build Live** on the default branch. That *is* the release; there is no artifact to hash and no manifest to submit. 3. **Announce** with Steam Events (release notes appear in the library and on the store page). 4. **Verify**: install from a clean Steam account, confirm `BIsDlcInstalled` returns false, buy the DLC (or use a test licence), confirm the high tiers unlock, then refund the test purchase. **Updates** are the same upload with a higher build ID. The app keeps **no self-updater and no version banner** — Steam is the update path, and that policy has not changed. ## 4. Entitlement wiring - `IEntitlement` has two implementations: **Steam DLC** (lifetime, local) and **Polar** (monthly, network + 7–14 day lease). Resolution is `Pro = steamDlc || polarValid`; anything unresolved is the free profile. - **Never sell the monthly inside the Steam build.** Steamworks requires in-app purchases to use the Steam Wallet; the app may *state* that monthly plans exist on the site, with no checkout, no price and no payment field. Confirm the wording with Steamworks support before shipping it. - **Never gate a feature.** The only delta is the output profile. ## 5. Release checklist - Build clean, 0 warnings (`./scripts/verify.sh`), tests green. - `steam_api64.dll` present; app starts **without** Steam and falls back to the free profile. - DLC ownership false → free profile; true → every tier offered. - `LlamaCasty.exe` rename landed (never rename a live exe). - Clean Steam install on a second machine, then an update pushed and observed. - Store page public for the full two weeks; support contact and announcements configured. - Portable mode: `portable.txt` present → data lands in `.\data\`. ## 6. Legal and takedown - **`LICENSE`** (EULA) forbids redistribution, resale, reverse-engineering and circumvention, and disclaims warranty. - **`PRIVACY.md`** must name any third party the app contacts — Google/YouTube today, **Polar** the day licence validation ships. Steam itself is named by Valve's own policy, not ours. - **`THIRD-PARTY-NOTICES.txt`** stays shipped and shown in About; the ffmpeg pin stays `lgpl-shared`; no GPL component may be linked (see `product.md` → "Licensing"). - **DMCA**: a takedown needs only the notice — host, link, good-faith statement, signature. Statutory damages need a registration ($65). Worth doing once there is something to pirate. - **What actually protects the product** is in `commercial.md` → "Anti-piracy posture": a free tier good enough that a crack buys nothing, Steam's own delivery, short Polar leases, and a licence ID in About. **Not obfuscation, not a native DLL, not hardware locking.** ## 7. Effort, once | Step | Effort | |---|---| | Steamworks onboarding + $100 fee | 0.5–1 day, mostly waiting on verification | | Publish profile + `steam_api64.dll` + `IEntitlement` Steam path | 1 day | | Depot + first `steamcmd` upload | 0.5 day, then ~15 min per release | | Store page + assets (screenshots, capsule art) | 1–2 days | | Clean-account install + DLC purchase/refund test | 0.5 day |