docs(distribution): Steam is the only channel — the zip, winget and the Store are dead
The site said "Coming soon to Steam" while the app docs still said direct download plus winget primary with Steam parked. One of them had to move, and the creator's ruling is Steam exclusive: a free app on Steam with the paid edition as a Steam DLC, and the $10/month plan sold off-Steam by Polar. Records the constraint that shapes the code, not just the prose: - Steamworks requires in-app purchases to use the Steam Wallet (Microtransactions doc, quoted in commercial.md), so the monthly is *stated*, never *sold*, inside a Steam build; the lifetime is plain DLC bought on the store page and read with BIsDlcInstalled. - Entitlement is `steamDlcOwned || polarKeyValid`, both resolving to one OutputProfile. steam_api64.dll ships beside the exe and is a functional dependency, not the rejected "IP protection" native DLL — without it DLC ownership cannot be read. Launched without Steam, the app falls back to the free profile rather than refusing to start. - Signing is moot: Steam installs never meet SmartScreen. Artifact Signing stays on the shelf for the day a non-Steam download exists. Year-one fixed cost is ~$115. - The exe rename must land before the first depot upload — Steamworks warns about renaming a live exe. Distribution.md is rewritten to SteamPipe mechanics (publish output, depot, steamcmd, DLC wiring, clean-account purchase/refund test). product.md, decisions.md (a new "Steam exclusive" entry with every dead vector), TASKS.md (Steamworks entitlement row, Steam packaging row), ai.md, index.md and the TASK 48 banner follow. MyMistakes.md gains the Steam rules that cost real time today: installs skip SmartScreen, updates are free, the Wallet rule, and the recurring-billing caveat.
This commit is contained in:
+76
-60
@@ -3,7 +3,7 @@
|
||||
The single source of truth for what LlamaCasty charges, what a licence entitles, how it ships and
|
||||
what support it does and does not include. Read before any pricing, licensing, distribution,
|
||||
storefront, support or promo work. Cause of death for every retired path:
|
||||
[`decisions.md`](decisions.md). Release mechanics (build, zip, mirror, winget):
|
||||
[`decisions.md`](decisions.md). Release mechanics (build, depot, SteamPipe upload):
|
||||
[`Distribution.md`](../../Distribution.md).
|
||||
|
||||
## Model
|
||||
@@ -43,11 +43,24 @@ The cap is a pixel budget plus a frame rate, not the word "720p":
|
||||
(cancel, revoke, sign-out, channel switch) greys them again on the next refresh.
|
||||
- **Bitrate follows the profile** — a capped user is not offered a 1080p bitrate.
|
||||
|
||||
## Entitlement
|
||||
## Entitlement — two sources, one profile
|
||||
|
||||
**Polar is the merchant of record and the only source of truth.** It takes the money, remits
|
||||
VAT/GST, handles refunds and chargebacks, and holds the keys. **There is no server of ours in the
|
||||
loop** — no claim page, no callback endpoint, no key database.
|
||||
**Pro is `steamDlcOwned || polarKeyValid`.** Both resolve to the same `OutputProfile`; neither
|
||||
touches a feature. Fail closed: anything unresolved is the free tier.
|
||||
|
||||
### Steam (lifetime)
|
||||
|
||||
- **Steam owns the lifetime SKU.** `ISteamApps::BIsDlcInstalled(dlcAppId)` after `SteamAPI.Init`.
|
||||
It is a local check against Steam's own state — no server, no key, no lease.
|
||||
- **Steam down or not running** → free profile, with a line explaining why, never a refusal to
|
||||
start. A Steam build launched outside Steam is the common case for people who pin shortcuts.
|
||||
- **No licence key exists for the Steam SKU**, so nothing to paste, email or lose.
|
||||
|
||||
### Polar (monthly, sold off-Steam)
|
||||
|
||||
**Polar is the merchant of record and the only source of truth** for the monthly plan. It takes the
|
||||
money, remits VAT/GST, handles refunds and chargebacks, and holds the keys. **There is no server of
|
||||
ours in the loop** — no claim page, no callback endpoint, no key database.
|
||||
|
||||
- **Key** — `LCYT-` prefix; org `c05fb364-…` and the endpoints are in `CREDENTIALS.md`. No
|
||||
product is created yet.
|
||||
@@ -84,57 +97,51 @@ channel ID. That is accepted: the free tier is the defence, the licence is a lea
|
||||
determined crack buys little. Do not propose a signed token, a hardware fingerprint or a server
|
||||
to "fix" it.
|
||||
|
||||
## Channels
|
||||
## Channels — Steam only
|
||||
|
||||
**One artifact, several ways to get it.** A self-contained single-file `LlamaCasty.exe` plus the
|
||||
bundled `ffmpeg\` folder, zipped. No .NET install, no admin, no installer framework. Trimming
|
||||
stays off (WPF reflection), so expect ~110–150 MB.
|
||||
**Steam is the distributor.** One free app on the store, the paid edition as a Steam **DLC**, and
|
||||
no other vector: no direct download, no winget, no Scoop/Chocolatey, no Microsoft Store. The store
|
||||
page is the single authoritative source for the download, the stats and the reviews.
|
||||
|
||||
1. **Direct download** — `llamacasty.com` links the zip. **Binaries live in a second Gitea repo
|
||||
(`llamacasty-releases`), push-mirrored to a public GitHub repo**, so the source repo stays
|
||||
private and the handout repo contains nothing but a README, an issue template and the release
|
||||
assets. The mirror carries refs, not GitHub Release assets — the zip is uploaded with
|
||||
`gh release create`. Mechanics: [`Distribution.md`](../../Distribution.md).
|
||||
2. **winget — the primary install path.** Manifest in `microsoft/winget-pkgs`, `InstallerType:
|
||||
portable`, pinned SHA-256. That hash pin is the anti-tamper wall: the official channel delivers
|
||||
exactly the published artifact or fails. One `wingetcreate update` PR per release. Optional:
|
||||
Scoop and Chocolatey manifests over the same zip.
|
||||
3. **Steam — parked at $100.** Lifetime Pro as DLC only (Steam has no subscriptions), page public
|
||||
two weeks before release, 30% cut, and price parity with the site. It is the only channel with
|
||||
discovery *and* an install that never meets SmartScreen, and it updates itself — which is why it
|
||||
stays in the plan despite the cut.
|
||||
4. **Microsoft Store — parked, and now free.** Microsoft waived the **$19** individual developer
|
||||
fee (and removed the **$99** company fee in May 2026). It is the only storefront that bills a
|
||||
subscription natively *and* the only zero-cost route to a Microsoft-signed install with no
|
||||
SmartScreen warning, because Microsoft signs the MSIX. Bans self-updaters, so a Store build
|
||||
ships without one.
|
||||
- **Lifetime Pro = Steam DLC.** Bought on the **store page**; the app only reads ownership
|
||||
(`ISteamApps::BIsDlcInstalled` / `UserHasLicenseForApp`). No purchase flow in the app, no Steam
|
||||
Wallet code, nothing to reconcile.
|
||||
- **The $10/month plan is sold outside Steam** and is **never purchasable inside a Steam build**.
|
||||
Steamworks requires in-app purchases to go through the Steam Wallet — so the app *states* that
|
||||
monthly plans exist on the site and does not sell them. If the app ever grows a checkout for it,
|
||||
that is the policy violation.
|
||||
- **Boot shape:** the app ships `steam_api64.dll` beside the exe and calls `SteamAPI.Init`. That
|
||||
is a functional dependency, not the rejected "native helper DLL for IP protection" — Steam
|
||||
ownership cannot be checked without it. Launched without Steam running, the app must fall back to
|
||||
the **free profile** and say so, never refuse to start.
|
||||
- **Updates are Steam's.** The depot push is the update; the app keeps no updater and no version
|
||||
banner (the old "no self-updater" rule stays, for the same reason: it works differently).
|
||||
- **Portable mode is no longer a distributable.** `portable.txt` remains as a feature for anyone who
|
||||
copies the installed folder; it is not a delivery mechanism.
|
||||
- **Steam Direct** is **$100 per app**, recoupable after $1,000 adjusted gross revenue.
|
||||
- **Price parity:** if the lifetime is ever sold off-Steam, it may not be cheaper than the Steam
|
||||
price.
|
||||
|
||||
**Not channels, ever:** Patreon or any subscription platform of our own, paywalled early access,
|
||||
a paid beta, a Discord. Content is the funnel; the channel is only the checkout.
|
||||
**Not channels, ever:** direct download, winget/Chocolatey/Scoop, the Microsoft Store, Patreon or
|
||||
any subscription platform of our own, paywalled early access, a paid beta, a Discord. Content is
|
||||
the funnel; Steam is the checkout.
|
||||
|
||||
**Portable mode:** a `portable.txt` marker beside the exe keeps the layout DB and settings in
|
||||
`.\data\` instead of `%APPDATA%\ytLlive` — the USB-stick case, hung off `LayoutPathOverride`.
|
||||
It is the reason the zip survives even if Steam becomes the primary channel.
|
||||
**Support surfaces this creates:** the Steam store page's support contact, Steam **Announcements**
|
||||
for known issues and release notes, Steam Discussions left pinned and unread, and one public issue
|
||||
repo for bugs that survive the friction of needing an account.
|
||||
|
||||
## Signing — deferred until there is revenue
|
||||
## Signing — not needed for the Steam channel
|
||||
|
||||
- **Not bought at launch.** Artifact Signing is listed in the costs as **deferred**: it is paid for
|
||||
out of Pro revenue, and the trigger is **two subscribers**.
|
||||
- **What it actually buys:** a named publisher line, fewer antivirus false positives on a ~150 MB
|
||||
self-extracting exe, and tamper evidence for hand-downloaded zips. It does **not** remove the
|
||||
SmartScreen warning on day one — Microsoft deleted the EV instant-bypass in March 2024, so a new
|
||||
certificate has zero reputation and clears only with download volume.
|
||||
- **Azure Artifact Signing** (renamed from "Trusted Signing"), **$9.99/month Basic**, up to 5,000
|
||||
signatures, **requires a paid Azure subscription**. Individual identity validation exists and
|
||||
must be renewed before it expires; it is the slow (days-to-weeks) part, so start it *when the
|
||||
purchase is decided*, not before.
|
||||
- **Reputation accrues to the publisher, not the file.** Unsigned means the warning on **every**
|
||||
release, forever, because SmartScreen ties reputation to each file hash. Signing is the only exit
|
||||
from that per-release tax.
|
||||
- **The free alternative is the Store** (see Channels 4): a free developer account gets
|
||||
Microsoft-signed installs with no certificate of ours.
|
||||
- **No EV certificate, ever** — $400+/yr for what OV buys, and the bypass is gone.
|
||||
- Every signed release: same pass, SHA-256 in the winget manifest, licence ID visible in About.
|
||||
- **Steam installs never meet SmartScreen.** Valve's client delivers the files, so there is no
|
||||
browser download, no Mark-of-the-Web and no "unknown publisher" wall. The certificate that
|
||||
existed only to soften that wall has nothing to do.
|
||||
- **Artifact Signing** (renamed from "Trusted Signing") stays on the shelf: Azure Artifact
|
||||
Signing, $9.99/month Basic, requires a paid Azure subscription, individual identity validation
|
||||
is the slow part. Buy it the day a non-Steam download exists — the zip case, not this one.
|
||||
- **Never EV, never a certificate with an HSM.** Microsoft removed the EV SmartScreen instant-bypass
|
||||
in March 2024; it buys nothing.
|
||||
- **Steam does not sign our exe either** — it just never puts it through the browser gauntlet.
|
||||
Windows may still show a UAC prompt for the app; that is elevation, not publisher trust.
|
||||
|
||||
## Support
|
||||
|
||||
@@ -174,14 +181,19 @@ Cash cost **$0**; it is priced in support time and forgone list revenue.
|
||||
|---|---|
|
||||
| Domain | ~$15/yr |
|
||||
| Droplet | $0 — serves the existing site |
|
||||
| GitHub public repo (releases + issues), Gitea, winget, Scoop, Chocolatey | $0 |
|
||||
| Polar | 5% + 50¢ per sale → $10 nets $9.00, $400 nets $379.50 |
|
||||
| Azure Artifact Signing — **deferred** | $9.99/month (~$120/yr), bought at two subscribers |
|
||||
| Steam Direct (optional) | $100 once, recoupable after $1,000 AGR |
|
||||
| Microsoft Store (optional) | **$0** — the individual fee was waived |
|
||||
| Steam Direct | **$100 once**, recoupable after $1,000 AGR |
|
||||
| Steam revenue share | 30% on the lifetime DLC → $400 nets **$280** |
|
||||
| Polar | 5% + 50¢ per sale → $10 nets $9.00 (monthly only) |
|
||||
| Steamworks, public issue repo, Gitea | $0 |
|
||||
| Azure Artifact Signing — **not needed** | Steam installs don't meet SmartScreen |
|
||||
| Microsoft Store — **not used** | — |
|
||||
|
||||
Fixed year one ≈ **$15** while unsigned, ≈ **$135** once signing starts. **Break-even is two
|
||||
subscribers** (15 subscriber-months ≈ $135); one $400 lifetime sale covers nearly three years.
|
||||
Fixed year one ≈ **$115** (domain + Steam Direct, one time). The Steam cut is the price of not
|
||||
paying for a certificate, a storefront or an update path.
|
||||
|
||||
**Signing is now moot as a launch cost.** Steam installs never meet SmartScreen, so the certificate
|
||||
that existed only to soften that wall has no job. Artifact Signing stays on the shelf for the day a
|
||||
non-Steam download exists.
|
||||
|
||||
## Anti-piracy posture
|
||||
|
||||
@@ -190,9 +202,13 @@ pointless and a leak that is traceable — not an unbreakable binary.
|
||||
|
||||
- **The free tier is the real defence.** If the only delta is pixels above 921,600, a cracked
|
||||
build buys almost nothing and forfeits updates, support and the publisher's signature.
|
||||
- **Hash-pinned delivery, signed once revenue exists** — a patched build cannot arrive through
|
||||
winget, and a forged one is not signed as us. Until signing starts, the SHA-256 pin is the wall.
|
||||
- **Short leases** — a revoked or refunded key dies inside the grace window.
|
||||
- **Steam DRM is optional and not needed.** The DLC check is already the entitlement; adding
|
||||
Valve's DRM wrapper buys nothing a determined crack respects, and it can break an exe on a
|
||||
machine that never runs Steam.
|
||||
- **The distribution is not a handout.** Steam deliveries go through Valve's client and account, so
|
||||
there is no public zip for a mirror site to repackage, and no hash pin for us to maintain.
|
||||
- **Short leases** — a revoked or refunded Polar key dies inside the grace window; a refunded Steam
|
||||
DLC stops reporting ownership the next time Steam is asked.
|
||||
- **Licence ID in About** — a leaked build traces back to a purchase.
|
||||
|
||||
⛔ **Rejected, do not re-propose:** a native helper DLL for "IP protection", obfuscation, hardware
|
||||
|
||||
@@ -23,6 +23,30 @@ the subsystem files. This is the graveyard with cause of death.
|
||||
remote is Gitea). The route is a separate **`llamacasty-releases`** Gitea repo push-mirrored to a
|
||||
public GitHub repo: issues and assets public, code private, one publish direction.
|
||||
|
||||
## Distribution — Steam exclusive (2026-10-31, final)
|
||||
|
||||
**Steam is the only vector.** A free app on Steam with the paid edition as a Steam **DLC**; the
|
||||
monthly plan is sold outside Steam and never purchasable in a Steam build. Live rules:
|
||||
[`commercial.md`](commercial.md).
|
||||
|
||||
**Why the other vectors died, all on the same day:**
|
||||
|
||||
- **Direct download + winget** (the plan of that morning) — a zip on a second Gitea repo mirrored to
|
||||
public GitHub, hash-pinned into winget. Superseded because Steam supplies delivery, stats,
|
||||
discovery, install trust and updates in one move, and because an unsigned zip meets SmartScreen on
|
||||
every single release while a Steam install never meets it at all.
|
||||
- **Microsoft Store** — was free, and free is not the same as wanted. It was the last thing keeping
|
||||
a Microsoft account, an MSIX pipeline and a publisher line in the plan.
|
||||
- **Azure Artifact Signing** — never needed once Steam delivers the install. Kept on the shelf for
|
||||
the day a non-Steam download exists.
|
||||
- **The public `llamacasty-releases` repo** survives only as the **issue tracker**; it holds no
|
||||
binaries, no manifest and no version file.
|
||||
|
||||
**The constraint that shapes the app:** Steamworks requires in-app purchases to use the **Steam
|
||||
Wallet**. Therefore the monthly is *stated*, never *sold*, inside the Steam build — no checkout, no
|
||||
price, no payment fields. The lifetime is plain DLC bought on the store page, so it needs no
|
||||
transaction code at all.
|
||||
|
||||
## Support — decided 2026-10-31
|
||||
|
||||
- **No training service, no helpdesk, no SLA.** Email, best effort, refunds on request without
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ Read the file whose row matches the task. There is no required reading order.
|
||||
| [`output.md`](output.md) | The bundled `ffmpeg.exe` and the encoder subprocess (args, probe order, seams), local recording (REC/ON-AIR, filenames, private-broadcast close-out), and the WASAPI capture → filter → mix → named-pipe audio chain (TRAX, sync offset, ducking, limiter) | Touching ffmpeg args/bundling, encoder or recording behaviour, REC/ON-AIR, the audio mix and its meters, or loudness/sync problems |
|
||||
| [`environment.md`](environment.md) | LAN hosts/IPs/SSH and the Gitea push recipe, the Windows `dotnet.exe` build + run commands, the test suite map, and the hermetic real-`MainWindow` test rule | Before building, running, adding a test, or reaching any box on the LAN |
|
||||
| [`product.md`](product.md) | Brand/naming split, AI transparency, the licensing prohibitions, the freemium posture, auth/account assumptions, and packaging behaviour | Branding, naming, packaging, or a legal/third-party obligation |
|
||||
| [`commercial.md`](commercial.md) | The live commercial policy: model and prices, the output-profile cap (stream **and** recording), Polar entitlement via `conditions` (no server, no claim page), the channels (releases repo → winget → Steam → Store), signing (deferred), the Founding 200 promo, costs, **support policy**, anti-piracy posture | Any question about money or support: pricing, licence keys, what free gets, how it ships, what a sale costs |
|
||||
| [`commercial.md`](commercial.md) | The live commercial policy: model and prices, the output-profile cap (stream **and** recording), entitlement (`steamDlcOwned \|\| polarKeyValid`; Steam DLC for lifetime, Polar for the monthly, no server), **Steam as the only channel**, signing (moot), the Founding 200 promo, costs, **support policy**, anti-piracy posture | Any question about money or support: pricing, licence keys, what free gets, how it ships, what a sale costs |
|
||||
| [`youtube-api.md`](youtube-api.md) | Go-live ordering + the broadcast-binding fix, the private-only lock, health parsing, end-stream pre-flight, Test mode, and chat-insert shape | Touching go-live, broadcast lifecycle, health polling, streaming close-out, or the chat service |
|
||||
| [`overlays.md`](overlays.md) | The social bar, the native alert box (six animations, alert clip, ticker) and the chat box conventions — everything composited over the frame | Adding or changing anything drawn on top of the output |
|
||||
| [`decisions.md`](decisions.md) | Retired paths with cause of death: the paid-tier history and pricing, the free-forever era, Store IAP, the Store ordering, rejected monetization and anti-piracy ideas, and the permanent out-of-product list | You are about to re-open a decision that was already settled |
|
||||
|
||||
+37
-49
@@ -189,46 +189,40 @@ YouTube channel, they go to YouTube first. This assumption is explicit and must
|
||||
replaced by an in-app account-creation step. Zero state = the Start Stream dialog's "Sign in to
|
||||
YouTube" button; going live is unreachable until an account is connected.
|
||||
|
||||
## Windows packaging & distribution (winget primary; Steam + Store parked)
|
||||
## Windows packaging & distribution (Steam only)
|
||||
|
||||
Live channel policy, the artifact and signing costs: [`commercial.md`](commercial.md). Build
|
||||
mechanics (publish flags, the releases repo mirror, the winget manifest):
|
||||
[`Distribution.md`](../../Distribution.md). Retired routes and cause of death:
|
||||
Live channel policy, the artifact and costs: [`commercial.md`](commercial.md). Build and depot
|
||||
mechanics: [`Distribution.md`](../../Distribution.md). Retired routes and cause of death:
|
||||
[`decisions.md`](decisions.md).
|
||||
|
||||
**The channels, in order:** direct download from `llamacasty.com` (binaries in a separate
|
||||
`llamacasty-releases` repo, push-mirrored to public GitHub) → **winget**, the primary install path →
|
||||
Steam (parked, $100, lifetime Pro as DLC only; the only channel with discovery *and* an install
|
||||
that never meets SmartScreen) → Microsoft Store (parked, **free** account since the $19 individual
|
||||
fee was waived — the only zero-cost route to a Microsoft-signed install).
|
||||
**One vector: Steam.** A free app on Steam with the paid edition as a Steam **DLC**; the monthly
|
||||
plan is sold outside Steam and is never purchasable inside a Steam build (Steamworks requires the
|
||||
Steam Wallet for in-app purchases). No direct download, no winget, no Microsoft Store.
|
||||
|
||||
**Consequences that are architecture, not packaging detail:**
|
||||
|
||||
- **⛔ There is no self-updater, by policy as well as by history.** Velopack was removed on
|
||||
2026-10-22 (TASK 48 slice 3) because it downloaded *and executed*, which Store policy 10.2.2
|
||||
forbids — and the same rule would close the Store for good if it came back. Updates arrive
|
||||
through the package manager (`winget upgrade`) plus an in-app "newer version exists" banner read
|
||||
from a version file in the releases repo. `ytLive.Tests/StorePackagingTests.cs` must keep
|
||||
asserting that no self-updater returns.
|
||||
- **The MSIX package stays buildable** via `scripts/package-msix.sh` (TASK 48 slice 2) — publish
|
||||
`Release -r win-x64 --self-contained` into `artifacts/msix-stage`, copy
|
||||
`Packaging/Package.appxmanifest` in as `AppxManifest.xml` + `Packaging/Assets/`, then
|
||||
`makeappx pack` → `artifacts/LlamaCasty.msix` (159 MB, gitignored; `MSIX_PFX` signs it for a
|
||||
local install). It is the Store channel's artifact, unsubmitted until that account exists. The
|
||||
manifest is a **full-trust `packagedClassicApp` at `mediumIL`** with `runFullTrust` + webcam +
|
||||
microphone. `Square310x310Logo`/`Wide150x150Logo` traps are in `MyMistakes.md`. Logos come from
|
||||
the app's own artwork via `scripts/make-store-logos.py`.
|
||||
- **⛔ Bundle ffmpeg — no runtime downloads** (was Store policy 10.2.2; still right for a direct
|
||||
download, and it fixes the 2026-09-01 404). See [`output.md`](output.md) → "FFmpeg locator".
|
||||
- **⛔ There is no self-updater, and now no version banner either.** Steam delivers updates; the
|
||||
app keeps nothing that downloads or executes, for the same Store-policy reason it always had.
|
||||
`ytLive.Tests/StorePackagingTests.cs` must keep asserting that no self-updater returns.
|
||||
- **⛔ `steam_api64.dll` is a functional dependency**, not the rejected "native helper DLL for IP
|
||||
protection" — Steam DLC ownership cannot be read without it. The app must start without Steam
|
||||
running and fall back to the free profile.
|
||||
- **The MSIX package stays buildable but is now unused** — `scripts/package-msix.sh` (TASK 48
|
||||
slice 2) still produces `artifacts/LlamaCasty.msix` from `Packaging/Package.appxmanifest` +
|
||||
`Packaging/Assets/`. It was the Store channel's artifact; with Steam exclusive there is no
|
||||
submission target. The full-trust `packagedClassicApp` findings below remain true and are still
|
||||
worth reading before any packaged build is attempted.
|
||||
- **⛔ Bundle ffmpeg — no runtime downloads** (was Store policy 10.2.2; still right for a Steam
|
||||
depot, and it fixes the 2026-09-01 404). See [`output.md`](output.md) → "FFmpeg locator".
|
||||
- **⛔ 64-bit Windows only (creator ruling 2026-10-09).** Both csproj files set
|
||||
`<PlatformTarget>x64</PlatformTarget>` (the test project too — an AnyCPU test project
|
||||
referencing an x64 app raises MSB3270 and breaks the 0-warning gate). Why: the bundled ffmpeg
|
||||
is the win64 build, ONNX Runtime 1.31 ships no win-x86 native (only win-x64/win-arm64), and a
|
||||
32-bit address space can't hold the 1080p frame buffers. Windows 11 is 64-bit-only anyway.
|
||||
Public copy says "64-bit Windows 10 or 11".
|
||||
- **Portable mode is the distributable's shape:** `portable.txt` beside the exe keeps the layout DB
|
||||
and settings in `.\data\` (hung off `LayoutPathOverride`), so a USB stick carries someone's
|
||||
scenes. The `winget` install and the hand-to-a-friend zip are the same artifact.
|
||||
- **Portable mode is a feature, not a channel:** `portable.txt` beside the exe keeps the layout DB
|
||||
and settings in `.\data\` (hung off `LayoutPathOverride`), so a copied install carries someone's
|
||||
scenes. Steam installs it; the marker is for afterwards.
|
||||
|
||||
**What does NOT change: no watermark and no feature gating.** The free tier is the whole app at a
|
||||
720p30 profile. `Monetization` above governs.
|
||||
@@ -252,32 +246,26 @@ trust. No `broadFileSystemAccess` capability is needed, and none should be added
|
||||
error.** A comment at `DefaultRecordFolder()` is owed **when the manifest lands** (TASK 48
|
||||
item 6) — not before; a comment describing a manifest that doesn't exist is worse than none.
|
||||
|
||||
### Signing — deferred until revenue; Azure Artifact Signing, never EV
|
||||
### Signing — not needed, because Steam installs the app
|
||||
|
||||
Microsoft **removed the SmartScreen instant-bypass for EV certificates in March 2024**, so EV
|
||||
($400+/yr) buys what OV (~$150–300/yr) buys; both need an HSM or hardware token and renew inside
|
||||
**460 days**. The 2026-10-31 ruling was **Azure Trusted Signing (~$9.99/month)**; the later ruling
|
||||
the same week is that it is **deferred until two subscribers exist**, because it never removes the
|
||||
warning on day one — only download volume does — and the storefront alternative is now free.
|
||||
Steam's client delivers the files, so there is no browser download, no Mark-of-the-Web and no
|
||||
SmartScreen wall. **The certificate has no job in this channel.** It stays on the shelf for the day
|
||||
a non-Steam download exists:
|
||||
|
||||
- **Renamed**: it is **Azure Artifact Signing** now. Basic is $9.99/month, 5,000 signatures, and it
|
||||
**requires a paid Azure subscription**; individual identity validation exists and must be
|
||||
renewed, and it is the slow (days-to-weeks) part — start it when the purchase is decided.
|
||||
- **Unsigned is a per-release tax**: SmartScreen ties reputation to the file hash, so an unsigned
|
||||
product warns on **every** release, forever. Signing is the only exit from that loop.
|
||||
- **The free exit is the Microsoft Store** — the individual developer account fee was waived, and
|
||||
Microsoft signs the MSIX, so a Store install never meets the wall.
|
||||
- **Never EV, never a certificate with an HSM**, for this product.
|
||||
Signing steps: [`Distribution.md`](../../Distribution.md). Costs: [`commercial.md`](commercial.md).
|
||||
- **Azure Artifact Signing** (renamed from "Trusted Signing") — $9.99/month Basic, up to 5,000
|
||||
signatures, **requires a paid Azure subscription**; individual identity validation is the slow
|
||||
part and must be renewed.
|
||||
- **Never EV** — Microsoft removed the EV SmartScreen instant-bypass in March 2024, so EV buys what
|
||||
OV buys. **Never a certificate with an HSM** for this product.
|
||||
- **Steam does not sign the exe.** A UAC prompt for the app is elevation, not publisher trust.
|
||||
|
||||
### Distribution and licensing are independent — the channel never decides billing
|
||||
|
||||
A **Store-distributed** app *may* still verify licences with **Polar** (Store policy 10.8.1
|
||||
explicitly permits a secure third-party purchase API for non-game PC products), so "which
|
||||
channel?" never implies "which billing?". **Polar is the live provider** (2026-10-31) because the
|
||||
2026-10-30 freemium ruling created something to sell; winget has no storefront at all, so the
|
||||
licence path is entirely ours there. The lesson worth keeping: the licensing choice rides on a
|
||||
**monetization** decision, not on a distribution decision.
|
||||
The Steam build sells the lifetime as **Steam DLC** and reads it with `BIsDlcInstalled`, while the
|
||||
monthly plan is billed by **Polar** outside Steam. Steamworks forbids taking payment inside the app
|
||||
with anything but the Steam Wallet, so the app states where the monthly lives and never sells it.
|
||||
The lesson worth keeping: the licensing choice rides on a **monetization** decision, not on a
|
||||
distribution decision.
|
||||
|
||||
### ⛔ "Only when the user says so" is enforced by Windows, not by us
|
||||
|
||||
|
||||
Reference in New Issue
Block a user