docs(commercial): one price — $79 Steam DLC rising to $99, subscription retired

Creator ruling 2026-11-01. One SKU, one price, Steam does the selling.

- Pro is a one-time Steam DLC on the free app: $79 introductory, $99 on a stated date, announced
  where the price is shown and actually raised.
- The subscription is retired. The reasoning is in decisions.md: no service behind a monthly fee
  (no servers, no cloud, no content), ~1-3 subscribers per 1,000 installs against 5-8% churn, and
  it carried the most expensive code in the product.
- Polar goes dormant. Its customer-portal design is recorded, not built. The "freemium on Steam,
  convert on Polar, Valve gets nothing" proposal is rejected: in-app purchases must use the Steam
  Wallet, so it risks the listing to save ~$24 a sale.
- Entitlement collapses to `steamDlcOwned`. No lease, no key, no portal, no device limit; the
  greyed tier opens the Steam store overlay, so every purchase stays inside Valve's own surface.
- The site publishes the model and links the store page. It takes no payment and hosts no binaries.
- The $400 lifetime died with the subscription it anchored. Founding 200 died with the coupons and
  passes it needed.

Costs: $115 fixed year one; $79 nets $55.30 after Steam, so three sales cover the year.
This commit is contained in:
2026-11-01 15:40:44 -08:00
parent 1c2eedcaba
commit 5d836aecbb
3 changed files with 76 additions and 86 deletions
+3 -3
View File
@@ -58,10 +58,10 @@ persisted; renderer mirrors `Services/ChatBoxRenderer.cs`.
| 50 | ☐ | One-button publish of the local recording (resumable upload) | [`task-50`](TASKS/task-50-publish-recording.md) | | 50 | ☐ | One-button publish of the local recording (resumable upload) | [`task-50`](TASKS/task-50-publish-recording.md) |
| 53 | ☐ | Output-format contract: pin every tier with a geometry test, prove 9:16 end-to-end, recorded file matches output | [`task-53`](TASKS/task-53-output-formats.md) | | 53 | ☐ | Output-format contract: pin every tier with a geometry test, prove 9:16 end-to-end, recorded file matches output | [`task-53`](TASKS/task-53-output-formats.md) |
| 54 | 🔶 | Freemium: EULA + privacy shipped; **no licence path built** — needs the entitlement seam, the output-profile cap and the licence UI below; site copy still says free forever | [`task-54`](TASKS/task-54-marcom-free-merch.md) | | 54 | 🔶 | Freemium: EULA + privacy shipped; **no licence path built** — needs the entitlement seam, the output-profile cap and the licence UI below; site copy still says free forever | [`task-54`](TASKS/task-54-marcom-free-merch.md) |
| — | 🔶 | **Steamworks entitlement** — `IEntitlement` + `SteamEntitlement` (Steamworks.NET) + fake **done**; needs the DLC app id from Steamworks, then the ownership path is live | [`commercial`](docs/ai/commercial.md) | | — | 🔶 | **Steamworks entitlement** — `IEntitlement` + `SteamEntitlement` (Steamworks.NET) + fake **done**; needs the DLC app id from Steamworks. **Polar path retired** — one-time Steam DLC only | [`commercial`](docs/ai/commercial.md) |
| — | ☐ | **Entitlement seam** — Polar customer-portal path for the monthly (org ID public, org token never in the app), `conditions: {channel_id}`, 7–14 day lease, `--activate` CLI. **No claim page, no server** | [`commercial`](docs/ai/commercial.md) | | — | ❌ | **Polar subscription path** — retired 2026-11-01 with the one-price model. Design kept in `decisions.md`, not built | [`decisions`](docs/ai/decisions.md) |
| — | 🔶 | **OutputProfile gate** — resolver + `EncoderOptions` wiring **done** (`Models/OutputProfile.cs`, one ffmpeg/two outputs, dev override); remaining: greyed tier entries in the dropdown, entitlement wiring | [`commercial`](docs/ai/commercial.md) | | — | 🔶 | **OutputProfile gate** — resolver + `EncoderOptions` wiring **done** (`Models/OutputProfile.cs`, one ffmpeg/two outputs, dev override); remaining: greyed tier entries in the dropdown, entitlement wiring | [`commercial`](docs/ai/commercial.md) |
| — | ☐ | **Licence UI** — four states, 7/1/0-day notices, "monthly is on the website, not Steam" line, portal link, licence ID in About | [`commercial`](docs/ai/commercial.md) | | — | ☐ | **Licence UI** — two states only: owned → Pro · not owned → greyed tiers + "unlock on Steam" (opens the store overlay). No key entry, no notices, no portal | [`commercial`](docs/ai/commercial.md) |
| — | ☐ | **System messages** — `SystemMessage` + `MessageCenter`, strip above the dock, dedupe by key, short history, never composited | [`ui-surface`](docs/ai/ui-surface.md) | | — | ☐ | **System messages** — `SystemMessage` + `MessageCenter`, strip above the dock, dedupe by key, short history, never composited | [`ui-surface`](docs/ai/ui-surface.md) |
| — | ☐ | **Steam packaging** — rename, `publish` output + `steam_api64.dll`, depot, `steamcmd` upload, store page + assets, DLC app | [`Distribution.md`](Distribution.md) | | — | ☐ | **Steam packaging** — rename, `publish` output + `steam_api64.dll`, depot, `steamcmd` upload, store page + assets, DLC app | [`Distribution.md`](Distribution.md) |
| — | ☐ | **Training-video series** — capture the first 8–10 recurring questions as videos on `@llamacasty`; each is documentation, channel content and monetization at once | MARCOM → support→content loop | | — | ☐ | **Training-video series** — capture the first 8–10 recurring questions as videos on `@llamacasty`; each is documentation, channel content and monetization at once | MARCOM → support→content loop |
+47 -83
View File
@@ -6,15 +6,19 @@ storefront, support or promo work. Cause of death for every retired path:
[`decisions.md`](decisions.md). Release mechanics (build, depot, SteamPipe upload): [`decisions.md`](decisions.md). Release mechanics (build, depot, SteamPipe upload):
[`Distribution.md`](../../Distribution.md). [`Distribution.md`](../../Distribution.md).
## Model ## Model — one purchase, one price
- **Free tier — every feature, every scene, every overlay**, free forever, no account, no - **Free tier — every feature, every scene, every overlay**, free forever, no account, no
watermark, nothing nagged inside the output. It is not a trial. watermark, nothing nagged inside the output. It is not a trial.
- **Pro — $10/month or $400 lifetime.** No annual tier. - **Pro is a one-time Steam purchase: a DLC on the free app.**
**$79 introductory → $99** on a stated date before launch. No subscription, no lifetime SKU, no
third-party checkout.
- **The only delta is output quality.** Features are never gated; a payment buys pixels. - **The only delta is output quality.** Features are never gated; a payment buys pixels.
- **No watermark, ever**, in either edition. The branding flash is retired as a paid delta and - **No watermark, ever**, in either edition. The branding flash is retired as a paid delta and
stays off (`ShowBrandFlash`, default `false`). stays off (`ShowBrandFlash`, default `false`).
- **Clean numbers, no `.99`**, no discount codes, no countdowns, no fake scarcity. - **Clean numbers, no `.99`**, no discount codes, no countdowns. **The one dated exception** is the
introductory price: it is announced in advance, shown where the price is shown, and actually
raised on the date — otherwise the next announcement is worthless.
- **The site publishes the model, never the numbers** — "free forever, every feature unlocked, a - **The site publishes the model, never the numbers** — "free forever, every feature unlocked, a
paid edition with higher output quality at launch". Price, tier name, cap and frame rate are paid edition with higher output quality at launch". Price, tier name, cap and frame rate are
published by the **app**, at the point of sale, not by the page. published by the **app**, at the point of sale, not by the page.
@@ -49,64 +53,30 @@ 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. (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. - **Bitrate follows the profile** — a capped user is not offered a 1080p bitrate.
## Entitlement — two sources, one profile ## Entitlement — one source
**Pro is `steamDlcOwned || polarKeyValid`.** Both resolve to the same `OutputProfile`; neither **Pro is `steamDlcOwned`, and nothing else.** It resolves to the `OutputProfile`; it never touches a
touches a feature. Fail closed: anything unresolved is the free tier. feature. Fail closed: anything unresolved is the free tier.
### Steam (lifetime) - **Steam owns the SKU.** `BIsDlcInstalled(dlcAppId)` after `SteamAPI.Init`, behind
- **Steam owns the lifetime SKU.** `BIsDlcInstalled(dlcAppId)` after `SteamAPI.Init`, behind
`IEntitlement` (`Services/Entitlement/`). It is a local check against Steam's own state — no `IEntitlement` (`Services/Entitlement/`). It is a local check against Steam's own state — no
server, no key, no lease. server, no key, no lease, no account, no email.
- **Fail closed, four ways:** no DLC app id configured, `SteamAPI.Init()` false (no client), - **Fail closed, four ways:** no DLC app id configured, `SteamAPI.Init()` false (no client), a
a thrown native load (missing `steam_api64.dll`), and "not owned" all resolve to the free tier. thrown native load (missing `steam_api64.dll`), and "not owned" all resolve to the free tier.
None of them may crash the app or grant Pro. None of them may crash the app or grant Pro.
- **Steam down or not running** → free profile, with a line explaining why, never a refusal to - **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. 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. A refunded DLC - **No licence key exists**, so nothing to paste, email, lose or reclaim. A refunded DLC simply
simply stops reporting ownership on the next start. stops reporting ownership on the next start.
- **The upgrade path is the Steam store overlay** (`ActivateGameOverlayToStore`) from the greyed
tier menu — Valve's own surface, so the purchase stays inside the Steam Wallet rules. Never a
checkout of ours, never an external payment page.
- **No leases, no dunning, no portal, no device limits.** A one-time purchase has one state:
owned or not.
### Polar (monthly, sold off-Steam) ⛔ **Subscriptions and third-party checkout are retired for launch** — see
[`decisions.md`](decisions.md). Polar stays dormant; its design is recorded there so it is not
**Polar is the merchant of record and the only source of truth** for the monthly plan. It takes the re-derived.
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.
- **The client talks to Polar directly.** The customer-portal endpoints authenticate on the **key
itself** plus the `organization_id` (a public identifier). The **org access token must never
ship in the app** — it is only needed to create products, not to activate them.
- **Bound to the buyer's YouTube channel ID** (`UC…` from `channels.list?mine=true` — the
signed-in channel, never the `@handle`) through Polar's **`conditions`**, not through a browser
flow: `activate` is called with `conditions: { "channel_id": "UC…" }`, and every later `validate`
passes the same object. Polar compares them server-side, so the binding is enforced without us
hosting anything.
- **Two activations**, any machine, one channel (`limit_activations: 2` on the benefit). A second
channel is a second key. Two keys for one channel is never sold — it doubles the support surface
and invites "give one to a friend".
- **Runtime rule:** Pro requires `licence.channelId == connected.channelId`. Equal → Pro.
Anything else → free tier, working normally, with *"This licence belongs to another channel"*
and a link to the Polar customer portal. Never an error wall, never a blocked stream.
- **Lease, not a permanent cache:** validate on launch and daily; **7–14 days offline grace**;
no network past grace = free tier until Polar answers. Never lock a paying user out on a DNS
failure.
- **Device management is Polar's** — the customer portal already lists and deactivates
activations, so we build no UI for it. A subscription key is **auto-revoked when the
subscription ends**, which is what makes a lapse a real state on the monthly SKU.
- **Four states, and nothing else:** valid → Pro · expired/revoked → free with a banner ·
activation limit reached → "manage devices" portal link · mismatch or offline → free, explained.
- **CLI activation** — `--activate LCYT-…` so silent and fleet installs never meet a dialog.
Interactive entry in Settings is the secondary path.
- **Notice cadence** — 7 days out, 1 day out, and on the day, inline in the go-live panel with a
date and a portal link. Recording gets the banner only. Never modal, never blocking a Start,
never orange (orange is the dev-only label colour).
⛔ **`conditions` is agreement, not cryptography.** A patched client can send someone else's
channel ID. That is accepted: the free tier is the defence, the licence is a lease, and a
determined crack buys little. Do not propose a signed token, a hardware fingerprint or a server
to "fix" it.
## Channels — Steam only ## Channels — Steam only
@@ -114,13 +84,12 @@ to "fix" it.
no other vector: no direct download, no winget, no Scoop/Chocolatey, no Microsoft Store. The store 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. page is the single authoritative source for the download, the stats and the reviews.
- **Lifetime Pro = Steam DLC.** Bought on the **store page**; the app only reads ownership - **Pro = Steam DLC, one-time.** Bought on the **store page**; the app only reads ownership
(`ISteamApps::BIsDlcInstalled` / `UserHasLicenseForApp`). No purchase flow in the app, no Steam (`ISteamApps::BIsDlcInstalled`). No purchase flow, no Wallet code, nothing to reconcile.
Wallet code, nothing to reconcile. - **The website sends people to Steam.** It publishes the model and links the store page; it takes
- **The $10/month plan is sold outside Steam** and is **never purchasable inside a Steam build**. no payment, collects no email, and hosts no binaries. One shop, one price, one receipt.
Steamworks requires in-app purchases to go through the Steam Wallet — so the app *states* that - **No in-app checkout of ours, ever.** Steamworks requires in-app purchases to use the Steam
monthly plans exist on the site and does not sell them. If the app ever grows a checkout for it, Wallet, so the only purchase surface is Steam's own store overlay.
that is the policy violation.
- **Boot shape:** the app ships `steam_api64.dll` beside the exe and calls `SteamAPI.Init`. That - **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 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 ownership cannot be checked without it. Launched without Steam running, the app must fall back to
@@ -130,8 +99,7 @@ page is the single authoritative source for the download, the stats and the revi
- **Portable mode is no longer a distributable.** `portable.txt` remains as a feature for anyone who - **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. copies the installed folder; it is not a delivery mechanism.
- **Steam Direct** is **$100 per app**, recoupable after $1,000 adjusted gross revenue. - **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 parity is trivially satisfied** — there is no off-Steam price to keep in step.
price.
**Not channels, ever:** direct download, winget/Chocolatey/Scoop, the Microsoft Store, Patreon or **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 any subscription platform of our own, paywalled early access, a paid beta, a Discord. Content is
@@ -170,21 +138,16 @@ repo for bugs that survive the friction of needing an account.
- **Nobody is locked out over a licence.** A billing hiccup drops the app to the free profile with - **Nobody is locked out over a licence.** A billing hiccup drops the app to the free profile with
a banner and a portal link — never a blocked stream, never a modal. a banner and a portal link — never a blocked stream, never a modal.
## Founding 200 promo ## The introductory price — the only promotion
Cash cost **$0**; it is priced in support time and forgone list revenue. Cash cost **$0**. With one SKU there is no coupon, no founder tier, no pass and no reminder cadence.
- **90 days free** — a 100%-off Polar coupon, `duration = repeating, months = 3`. - **$79 until a stated date, then $99.** The date is announced at launch on the store page, the
- **Founder price lock** — their $10/month stays $10 permanently. site and the in-app upgrade panel, and it is honoured — an introductory price that never rises
- **Credits + in-app Founder badge** (opt-in channel name on the site). makes the next announcement worthless.
- **30-day passes** — unique keys carrying the issuer's channel, issued **one per 30 active days, - **No launch discount stacked on top.** Two overlapping stories ("introductory" plus "15% off")
max 3 held**, activation limit 1–2, expiring 30 days **after activation**. Earned, never handed muddy both, and the increase afterwards triggers Steam's 30-day discount cooldown.
out: a pass nobody uses teaches nothing. - **No coupons, no keys, no founder badges.** A one-time Steam purchase has nothing to administer.
- Optional **$250 lifetime** window in the first 90 days — converting a founder beats three
months of free.
- Reminders at day 75 and 85; the renewal cliff is where founders churn.
- Terms, one paragraph: one per person, passes expire 30 days after activation, no cash value,
revoked for resale or abuse, price lock void if the subscription lapses.
## Costs ## Costs
@@ -193,14 +156,14 @@ Cash cost **$0**; it is priced in support time and forgone list revenue.
| Domain | ~$15/yr | | Domain | ~$15/yr |
| Droplet | $0 — serves the existing site | | Droplet | $0 — serves the existing site |
| Steam Direct | **$100 once**, recoupable after $1,000 AGR | | Steam Direct | **$100 once**, recoupable after $1,000 AGR |
| Steam revenue share | 30% on the lifetime DLC → $400 nets **$280** | | Steam revenue share | 30% → **$79 nets $55.30**, **$99 nets $69.30** |
| Polar | 5% + 50¢ per sale → $10 nets $9.00 (monthly only) | | Polar | **$0 — dormant.** No subscription at launch |
| Steamworks, public issue repo, Gitea | $0 | | Steamworks, public issue repo, Gitea | $0 |
| Azure Artifact Signing — **not needed** | Steam installs don't meet SmartScreen | | Azure Artifact Signing — **not needed** | Steam installs don't meet SmartScreen |
| Microsoft Store — **not used** | — | | Microsoft Store — **not used** | — |
Fixed year one ≈ **$115** (domain + Steam Direct, one time). The Steam cut is the price of not Fixed year one ≈ **$115** (domain + Steam Direct, one time). At $79, **three sales cover the year**.
paying for a certificate, a storefront or an update path. The Steam cut is the price of not running a storefront, a certificate or an update path.
**Signing is now moot as a launch cost.** Steam installs never meet SmartScreen, so the certificate **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 that existed only to soften that wall has no job. Artifact Signing stays on the shelf for the day a
@@ -218,9 +181,10 @@ pointless and a leak that is traceable — not an unbreakable binary.
machine that never runs Steam. machine that never runs Steam.
- **The distribution is not a handout.** Steam deliveries go through Valve's client and account, so - **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. 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 - **Steam is the licence state** — a refunded DLC stops reporting ownership the next time Steam is
DLC stops reporting ownership the next time Steam is asked. asked, and the app drops to the free profile on the next start. Nothing to revoke by hand.
- **Licence ID in About** — a leaked build traces back to a purchase. - **The Steam purchase is in About** — a leaked build traces back to a Steam account, which Valve
can action; we hold nothing to trace.
⛔ **Rejected, do not re-propose:** a native helper DLL for "IP protection", obfuscation, hardware ⛔ **Rejected, do not re-propose:** a native helper DLL for "IP protection", obfuscation, hardware
locking, remote code that downloads and executes, and gating asset downloads as an auth check. locking, remote code that downloads and executes, and gating asset downloads as an auth check.
+26
View File
@@ -5,6 +5,32 @@ you are about to re-open one of them. **Live commercial rules (prices, entitleme
signing, support, promo) are in [`commercial.md`](commercial.md)**; the other live rules live in signing, support, promo) are in [`commercial.md`](commercial.md)**; the other live rules live in
the subsystem files. This is the graveyard with cause of death. the subsystem files. This is the graveyard with cause of death.
## The business model — one price, settled 2026-11-01
**$79 one-time, raising to $99 on a stated date. Sold only on Steam, as a DLC on the free app.**
The website publishes the model and links the store page; it never takes payment.
**What died the same day:**
- **The subscription.** $10/month for pixels, with no service behind it — no servers, no cloud, no
content library, updates free through Steam. Estimated 1–3 subscribers per 1,000 installs, at
5–8% monthly churn, against the most expensive code in the product (leases, activations,
revocation, portal, dunning). Retired for launch.
- **Polar as a live rail.** Dormant. Its customer-portal design (`conditions` binding, two
activations, 7–14 day lease) is preserved here only so it is not re-derived if a cheaper entry
tier is ever justified by real support traffic.
- **The $400 lifetime** — it was an anchor for a subscription that no longer exists, and above what
a beginner pays for a tool with a free incumbent.
- **Founding 200** — coupons, price locks, earned 30-day passes, founder badges: all machinery for
a recurring plan.
- **Off-Steam conversion of any kind.** The "freemium on Steam, convert on Polar, Valve gets
nothing" proposal was rejected: Steamworks requires in-app purchases to use the Steam Wallet, so
it is a listing-level risk to save ~$24 a sale.
**Kept:** the free tier is the whole app at a 720p30 output profile, the paid delta is output
quality only, and the app never sells anything itself — the greyed tier opens the Steam store
overlay.
## Commercial mechanics — died 2026-10-31 (same week they were written) ## Commercial mechanics — died 2026-10-31 (same week they were written)
- **The licence "claim page" is dead.** The binding was going to be an OAuth web page that wrote - **The licence "claim page" is dead.** The binding was going to be an OAuth web page that wrote