Files
LlamaCasty/docs/ai/commercial.md
T
gramps 1e3a4f7fe0 feat(entitlement): pre-release switch so Release builds can test 60 fps
The frame-rate boundary is correct as a product rule, but it only bites in a
Release build, where DevBuild.IsDevelopment is false and DeveloperMode cannot
unlock anything — exactly the build whose performance numbers are worth reading
(see docs/ai/environment.md: Debug pixel paths are several times slower). 60 fps
could not be tested at all.

OutputProfile.EntitlementEnforced is false: every shipped tier is selectable by
any build, and HasProOutput — the one property the tier setter, the dropdown's
strikethrough and the locked-item style all read — answers yes regardless of
ownership. static readonly rather than const, so the consumed `||` does not fold
into unreachable operand code (same reason as DevBuild.IsDevelopment).

The licence indicator row is suppressed while the switch is off: it exists to
explain what the boundary costs, and claiming "Steam ID Limit: 60fps" to an
unowned build would be a false statement. Docs corrected in place — the enforced
rule is unchanged, only its state is recorded.

Tests: one integration case covers both switch states (unowned build reaches
1080p60 with the switch off, 1080p30 with it on), so flipping at launch leaves no
red test behind. The two suites that anchor on the pinned licence row early-return
while it is absent; EntitlementTests covers that state meanwhile.

667 pass, build 0 warnings.
2026-11-12 07:50:59 -08:00

220 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Price (creator ruling 2026-11-05)
- **Launch price $79** — one-time purchase, lifetime licence, no subscription, no account, no tracking.
- **Promotion ends 30 days after the store page goes live** (revised 2026-11-05 — the earlier fixed date,
April 1 2027, depended on Valve's review queue, which is outside our control); after that the price is
**$99, locked for life**.
- Free tier: livestream and record at **30 fps**. Paid unlocks **60 fps** for both.
- The numbers live in `ViewModels/MainViewModel.Overlays.cs` (`LaunchPrice`, `StandardPrice`,
`LaunchPriceEndsLabel`) so the About box, the site copy and this file cannot drift apart. Change them
there first, then here.
# Commercial: pricing, entitlement, channels, support
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, depot, SteamPipe upload):
[`Distribution.md`](../../Distribution.md).
## Model — one purchase, one price
- **Free tier — every feature, every scene, every overlay**, free forever, no account, no
watermark, nothing nagged inside the output. It is not a trial.
- **Pro is the paid Steam app; the free Demo is associated with it.** The paid app is **$79 during
the announced launch period, then $99** on the announced date. No subscription or third-party
checkout.
- **The only delta is frame rate.** Features are never gated; every supported resolution is free at
30 fps, and 60 fps is paid. Resolution does not decide entitlement.
- **No watermark, ever**, in either edition. The branding flash is retired as a paid delta and
stays off (`ShowBrandFlash`, default `false`).
- **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
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.
## Output profile — the one entitlement rule
The product rule is frame rate, not pixel count or a resolution label:
| | Free | Pro |
|---|---|---|
| Pixels | any supported tier | any supported tier |
| Frame rate | ≤ **30 fps** | up to **60 fps** |
| Landscape | 1280×720 @30 · 1920×1080 @30 | all Free tiers + 1280×720 @60 · 1920×1080 @60 |
| Vertical 9:16 | 1080×1920 @30 | all Free tiers + 1080×1920 @60 |
- **Pre-release: the boundary is not enforced yet (2026-11-12).** `OutputProfile.EntitlementEnforced`
is `false`, so every shipped tier — 60 fps included — is selectable by any build until the paid
edition ships. It is needed because 60 fps can only be performance-tested in a **Release** build,
where `DevBuild.IsDevelopment` is false and `DeveloperMode` cannot unlock anything. Flip the switch
at launch: the rule, the resolver and their tests already implement the enforced state, and the
`EntitlementTests` case asserts both states so it does not go red on the flip.
- **Records too.** The frame-rate rule governs the file the creator keeps as well as the stream;
otherwise free 60-fps recording is a re-upload hole. **There is one ffmpeg process with two output blocks**
(FLV to RTMP, MP4 to disk) fed by one `EncoderOptions`, and the profile is resolved once when
those options are built (`MainViewModel.Streaming.Operations.cs` → `Models/OutputProfile.cs`).
There is no second encoder to keep in step and therefore no second check to forget.
- **Fail closed.** Unresolved, unreadable or unvalidated entitlement = free tier. Never Pro.
- **The development override exists and never ships.** `MainViewModel.DeveloperMode` bypasses the
entitlement gate in a Debug build only; the Settings row that toggles it is **excluded from the Release
compile** (`ytLive.csproj` removes its Page and code-behind), and the setter refuses the value
when `Helpers/DevBuild.IsDevelopment` is false. Not a hidden row — an absent one.
- **Never downgrade a running stream.** The gate applies to the next start; pulling 60 fps out of a
live broadcast is a worse bug than one session starting at an unentitled frame rate.
- **The greyed menu entry is the sales surface.** It stays clickable; locked 60-fps tiers are marked
as paid. Selecting a locked tier opens the in-app About panel; the browser opens only if the
creator then clicks its llamacasty.com link.
- **Ownership is checked at app startup** and cached in `IsAppOwned` for that run. Purchases and
refunds are reflected on the next app start; there is no subscription lapse or sign-out path.
- **Bitrate follows the selected profile** — free users may choose any supported 30-fps tier; paid
users may choose supported 60-fps tiers.
## Entitlement — one source
**Paid-app ownership is the one entitlement.** Steam sells one paid app; its associated free demo is
the purchase funnel. Both use the same code. The demo checks whether the current Steam account owns
the paid app, then exposes the higher output tiers. The app-wide `IsAppOwned` value is the binary
ownership result used by later feature checks.
- **Steamworks status (2026-11-05):** partner account created; **identity verification pending** and the
tax interview is in Valve's queue (they quote up to **30 business days**). No app IDs are assigned and
no store page exists yet, so the Release build still fails closed on entitlement — by design. Earliest
realistic launch is early-to-mid February 2027; the 2027-04-01 launch-price deadline therefore has
~7 weeks of buffer. Detail: [`Distribution.md`](../../Distribution.md) §2.
- **Steam owns the purchase.** The demo calls `BIsSubscribedApp(paidAppId)` after `SteamAPI.Init`,
behind `IEntitlement` (`Services/Entitlement/`). It is a local check against Steam's own state —
no server, key, lease, or LlamaCasty account.
- **Fail closed:** no paid app ID configured, `SteamAPI.Init()` false (no client), a
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.
- **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.
- **Development builds fake ownership as true.** `FakeEntitlement` is excluded from Release builds.
- **No licence key exists**, so nothing to paste, email, lose or reclaim. A refunded purchase stops
reporting ownership on the next Steam check.
- **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.
⛔ **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
re-derived.
## Channels — Steam only
**Steam is the distributor.** One paid app and its associated free Demo; no direct download,
GitHub binary, winget, Scoop/Chocolatey, or Microsoft Store. The store page is the single
authoritative source for the download, stats, and reviews.
- **The paid app is one-time purchase.** The demo's App ID is separate, but it shares the code and
checks ownership of the paid app (`ISteamApps::BIsSubscribedApp`). No in-app checkout or license
server.
- **The website sends people to Steam.** It publishes the model and links the store page; it takes
no payment, collects no email, and hosts no binaries. One shop, one price, one receipt.
- **No in-app checkout of ours, ever.** Steamworks requires in-app purchases to use the Steam
Wallet, so the only purchase surface is Steam's own store overlay.
- **Boot shape:** the app ships `steam_api64.dll` beside the exe and calls `SteamAPI.Init`. Launched
without Steam running, the app falls back to the **free profile** and says so; it never refuses 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 is trivially satisfied** — there is no off-Steam price to keep in step.
**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.
**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 — not needed for the Steam channel
- **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
**Email. Best effort. No SLA. Refunds granted on request, without argument.**
- **There is no training service.** "I want people to succeed" is not "I will train them". The app
teaches itself — one-click go-live, five scenes, nothing to configure. A how-to question means
the app or its docs fell short; the answer is a fix or a video, not a conversation.
- **No helpdesk.** No ticketing system, no live chat, no onboarding calls, no hand-holding.
- **A repeated question is a video, not a ticket** — see `MARCOM.md` → support → content loop. The
training channel is the support surface.
- **The issue tracker is a filter, deliberately.** Bugs go to the public releases repo on GitHub,
which requires an account; Steam Discussions stay pinned and unread; Announcements carry known
issues and release notes. Steam refunds are Valve's own (2 h / 14 days) and cost us nothing.
- **Nobody is locked out of streaming.** If Steam ownership is unavailable or not owned, the app
remains usable at the free output profile; no modal or account portal.
## The introductory price — the only promotion
Cash cost **$0**. With one SKU there is no coupon, no founder tier, no pass and no reminder cadence.
- **$79 until a stated date, then $99.** The date is announced at launch on the store page, the
site and the in-app upgrade panel, and it is honoured — an introductory price that never rises
makes the next announcement worthless.
- **No launch discount stacked on top.** Two overlapping stories ("introductory" plus "15% off")
muddy both, and the increase afterwards triggers Steam's 30-day discount cooldown.
- **No coupons, no keys, no founder badges.** A one-time Steam purchase has nothing to administer.
## Costs
| Item | Cost |
|---|---|
| Domain | ~$15/yr |
| Droplet | $0 — serves the existing site |
| Steam Direct | **$100 once**, recoupable after $1,000 AGR |
| Steam revenue share | 30% → **$79 nets $55.30**, **$99 nets $69.30** |
| Polar | **$0 — dormant.** No subscription at launch |
| Steamworks, public issue repo, Gitea | $0 |
| Azure Artifact Signing — **not needed** | Steam installs don't meet SmartScreen |
| Microsoft Store — **not used** | — |
Fixed year one ≈ **$115** (domain + Steam Direct, one time). At $79, **three sales cover the year**.
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
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
**Any check that runs on the user's machine can be removed.** The goal is a crack that is
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.
- **Steam DRM is optional and not needed.** The app ownership check is 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.
- **Steam is the ownership state** — a refunded purchase stops reporting ownership on the next
check. The app holds no customer account or license key.
⛔ **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.
None of them make a licence enforceable; the first three add failure modes without buying
anything, the fourth needs the server this plan exists to avoid, and the fifth is Store policy
10.2.2.