Monetization policy locked + dev pause recorded (docs changeset, 2026-08-14): the one paid line becomes an annual subscription — early access $49.99/yr → $99/yr list at GA, grandfather-while-subscribed with lapse → list on renewal (no escalation matrix); free tier unchanged (branding flash is the free tier's billboard + no Alerts, which is the one paid feature); billing NOT locked to itch.io (hunted fact: itch.io has no native subscription billing — candidates Gumroad, whose native affiliate program is the tiebreaker, and Lemon Squeezy); support = in-app bug-report → git issues with a when-I-get-around-to-it cadence + emergency patches. ai.md Monetization section rewritten + stale paid-unlock seams fixed (L115 subscription-entitlement wording, the About hub's tabled billing PremiumUrl seam); TASKS.md gains TASK 23 (Monetization — billing provider decision, unlock mechanism with lapse→flash-returns enforcement, in-app bug-report loop, Unlock Premium seam lighting, Alerts gating, and line-item pointers for the early-access strategy, affiliate/ads phase 2, and the channel revival); HANDOFF.md records the decisions + the development pause (resume streaming = pair-programming dev streams via OBS + The Division 2 under the gramps/GOAT persona, 67 and gaming since 1981, 3D-printing content retired; dogfood switch to ytLlive once TASK 5 lands; resume point = TASK 5). Stale itch.io assertions corrected across comments and indexes (MainViewModel.cs PremiumUrl/IsPremium seams, MainWindow.xaml tooltip, AboutHubTests comment, ViewModels/index.md, TASK 9 out-of-scope note). Build 0 warnings, 196 tests passing
This commit is contained in:
@@ -112,7 +112,7 @@ C# / WPF (.NET 8) following MVVM:
|
||||
### Current limitations / TODOs
|
||||
|
||||
- `Helpers/OAuthCredentials.cs` contains the real ClientId/ClientSecret. Auth is complete and the session **persists via Windows DPAPI** (`Helpers/TokenStore.cs` → `%APPDATA%\ytLlive\ytLlive.auth`, CurrentUser scope), reloaded best-effort at startup with a proactive refresh of a near-expiry access token. Sign-in/Change Account lives **inside the Start Stream dialog** (two-state flow — no separate Connect button). A **graceful End Livestream signs out**: `StopStream()` clears the session + token, so the next go-live needs a fresh sign-in; a crash never runs End, so the token survives and the creator stays signed in. `YouTubeAuthService` takes an optional `HttpClient` + `sessionChanged` callback (test seam + save hook; services are still constructed in `MainViewModel`)
|
||||
- Scene/source/asset layout + the social bar persist (SQLite, schema v8); the OAuth session persists (DPAPI); the paid-unlock state does not (yet — itch.io key verification pending)
|
||||
- Scene/source/asset layout + the social bar persist (SQLite, schema v8); the OAuth session persists (DPAPI); the paid-unlock state does not (yet — subscription entitlement verification pending, TASK 23)
|
||||
- `YouTubeStreamService` uses hardcoded `1080p`/`60fps` and per-broadcast streams — must switch to the v3 `variable` reusable stream
|
||||
- Webcam capture is shipped (milestone 1); the live desktop/game backdrop is shipped (ship task #1); **the output compositor (TASK 4 ship step 1) is SHIPPED**, **the FFmpeg locator (TASK 4 ship step 2) is SHIPPED**, **the encoder + RTMP push (TASK 4 ship step 3) is SHIPPED**, **WASAPI audio capture (TASK 4 ship step 4) is SHIPPED** — full plan in `TASKS.md`; the frame-pipeline wiring follows (its own PR)
|
||||
- `StreamConfig` defaults (`TargetBitrate=6000`, `Resolution="1920x1080"`) are stale — the live dropdown drives `StreamHealth.CurrentBitrate`/`FPS` instead
|
||||
@@ -558,10 +558,10 @@ guardrails below — written down so a future "quick fix" never reintroduces a G
|
||||
release blocker). Queued early is wrong; the release pass owns it.
|
||||
- **Break the in-app About requirement** — since TASK 21 the About overlay is the app's in-app creator
|
||||
hub: the real logo, the creator links (YouTube channel, Mastodon, Buy me a coffee, and the greyed
|
||||
"Unlock Premium" seam whose itch.io URL is tabled), and a **Licenses & legal** sub-panel that loads
|
||||
"Unlock Premium" seam whose billing URL is tabled), and a **Licenses & legal** sub-panel that loads
|
||||
`THIRD-PARTY-NOTICES.txt` from the executable directory and renders it in a scrolling panel —
|
||||
**never the OS viewer, no Notepad, no browser tab**. The premium/coffee link constants live in
|
||||
`MainViewModel` (`PremiumUrl`, `CoffeeUrl`, `ChannelUrl`, `MastodonUrl`); filling in the itch.io URL
|
||||
`MainViewModel` (`PremiumUrl`, `CoffeeUrl`, `ChannelUrl`, `MastodonUrl`); filling in the billing URL
|
||||
lights up the premium button. Do not reintroduce an "open the notices in Notepad" button.
|
||||
|
||||
## Design Principle
|
||||
@@ -576,9 +576,8 @@ Apply this to every UI decision:
|
||||
|
||||
## Monetization (design decision — the branding flash is the sword)
|
||||
|
||||
Free forever: all streams unlimited, no time caps, no subscription, no per-feature paywalls. The
|
||||
**one paid line is a one-time unlock** (delivered via itch.io — they handle hosting, payment, and key
|
||||
delivery; we never own a server or a key shop):
|
||||
Free forever: all streams unlimited, no time caps, no per-feature paywalls. The **one paid line is an
|
||||
annual subscription** (settled 2026-08-14 — replaces the earlier "one-time unlock" shape):
|
||||
|
||||
- **Free:** a periodic full-frame branding flash — "made with ytLlive!" rendered big and centered at
|
||||
~25% opacity for about one second (soft 250ms fade in/out), repeated every 300s, on the live output
|
||||
@@ -586,8 +585,23 @@ delivery; we never own a server or a key shop):
|
||||
(`MainWindow.xaml` CanvasGrid) + `BrandFlashTimer` in `MainViewModel` — cadence 300s, first flash
|
||||
~5s after go-live, only while live or recording. An always-on watermark can be cropped or covered;
|
||||
an intermittent full-frame flash can't be cropped and is impractical to edit around on a live feed.
|
||||
- **Paid (one-time):** branding flash removed (flips `BrandFlashEnabled` off) + **Alerts**
|
||||
(Super Chat / membership / subscribe pop-ins).
|
||||
**The flash is also the free tier's billboard** — every free stream advertises ytLlive to its own
|
||||
viewers; the free tier is distribution, not compromise.
|
||||
- **Paid (annual subscription):** branding flash removed (flips `BrandFlashEnabled` off) + **Alerts**
|
||||
(Super Chat / membership / subscribe pop-ins). Alerts is the recurring-value engine — a live-API
|
||||
feature we maintain forever, which is the strongest argument for a yearly bill.
|
||||
- **Pricing:** early-access founders rate **$49.99/yr** → **$99/yr list at GA** (v1). **Grandfathering:
|
||||
early adopters keep $49.99/yr for as long as the subscription is maintained**; a lapse means renewal
|
||||
at list. That's the whole policy — no escalation matrix (a realistic product lifetime is a few years;
|
||||
keep the promise simple).
|
||||
- **Billing:** NOT locked to itch.io (creator's call 2026-08-14). Hunted fact — **itch.io has no native
|
||||
subscription billing** (no annual/recurring product billing; only pay-what-you-want, pre-orders,
|
||||
early-access, keys, and a Patreon integration). Candidates for annual subs + license-key verification:
|
||||
**Gumroad** (its native affiliate program is a tiebreaker if the affiliate angle in TASK 23 matters)
|
||||
and **Lemon Squeezy**. Decision deferred to TASK 23.
|
||||
- **Support (creator's model):** in-app bug-reporting mechanism → issues into git; most queries are
|
||||
how-tos / feature requests / manual-skimmers. Maintenance cadence = "when I get around to it" with
|
||||
emergency patches; not a 24/7 service promise.
|
||||
|
||||
Deliberately rejected: always-on watermark (obscurable — replaced by the flash), hard stream-time
|
||||
cutoffs (the worst dead end — a stream dying mid-broadcast reads as broken, and YouTube streams
|
||||
|
||||
Reference in New Issue
Block a user