Click-to-pin an open window as the full-bleed Live backdrop, via the existing
window:<hwnd> capture path (same render layer as game/desktop). Session-scoped:
window:/picker: keys heal to auto on reload (HWND-recycle hazard); pin wins
while the window enumerates, then auto-fallbacks (game → desktop → static); a
dead window's capture session heals to auto, no dead ends.
Fix: ScreenCaptureSourceFactory.Resolve hex-parsed "window:0x<Hwnd>" WITHOUT
stripping the 0x prefix — NumberStyles.HexNumber rejects it, so every pin
resolved null ("No capture target for this key") and the heal silently rolled
back. Same flaw in IsAliveWindowPin (pin-wins guard was dead). Both fixed.
Commit also carries an out-of-scope prerequisite: PillRadioTests.cs:105 had a
committed stray token ("...PrimaryStartButtonLabel soil;", CS1003) blocking the
whole test-project compile — token removed.
Plus the previous session's uncommitted pricing docs (one-time $29/$49) that
share TASKS.md/ai.md/HANDOFF.md.
3.7 KiB
TASK 10 — Monetization: watermark-only one-time license + Polar billing
Catalog:
TASKS.md— status and requirements live here.
Goal: a one-time perpetual license via Polar.sh that removes the branding watermark. All features
are free — the only difference between free and paid is the watermark. (Model changed 2026-09-21 from
annual subscription to one-time "own it": $29 founder / $49 list lifetime. See MONETIZATION.md →
Pricing for the reasoning.)
Related work — monetization awareness (2026-09-01, ungated, free): this task's billing is the
payer side; the product also carries built-in, ungated monetization awareness for every creator —
reward-event capture (all 7 liveChatMessage reward event types → canonical RewardEvent → SQLite
persistence), per-session/broadcast reports (members, Super Chat $, stickers, gifts, milestones — the
in-app replacement for the emailed "stream activity report"), and a journey tracker (position % +
ETA vs. versioned, date-aware YPP thresholds; the Tier-2 bar doubles for new applicants 2027-02-01).
Details and design notes: ai.md → Monetization. This is tracked as related work under this task's
narrative, not a separate task number — it ships in its own code slices with one integration test each.
Scope: v1 (2026-09-01 complete-v1 ruling — there is no v1.x): slice order = reward-event capture →
session report → journey tracker → Alerts (TASK 3 item 20).
Business details (pricing, Polar product/checkout/discounts) in MONETIZATION.md (gitignored).
Polar product: d105dfa1-497e-423b-8cd4-e0ee2e3abbc0 (LlamaCasty, ⚠️ currently configured as
$99/yr subscription — must be re-created as a one-time product: $29 founder / $49 list lifetime)
Checkout: llamacasty.com → Polar hosted page (~80% configured)
Discounts: LLAMAFOUNDER (100% off, 50 uses, once), LLAMA50 (50% off, once)
Org ID: c05fb364-b967-4f6c-adf2-8a144e46d085 (org-scoped OAT — organization_id can be omitted from API calls)
Key prefix: LCYT-
Validate endpoint: POST https://api.polar.sh/v1/customer-portal/license-keys/validate (no auth required for client-side validation)
Status: 🔶 In progress — steps 1–7 shipped, Velopack update URL pending
- ✅ Billing provider — Polar (polar.sh) chosen and configured. Product, price, license key benefit, discounts, checkout link all created.
- ✅ License key entry + verification UI — About overlay swap panel (same pattern as Licenses panel). Text input + "Activate" button + status message. "Enter License Key" button in the hub.
- ✅ Offline entitlement —
LayoutStoreSettings table:LicenseKey,LicenseValidatedAt,IsPremium. 14-day offline grace period. Startup re-validates online, falls back to cache. - ✅ BrandFlash → watermark toggle —
IsPremiumproperty setter flipsBrandFlashEnabled = !value. Flash stops immediately on premium activation. Flash asset VideoFrame rendering deferred to TASK 4 compositor. - ✅ Remove social slot locks — all 6 social bar slots open to everyone (no
IsPremiumgating on slots 3-6) — shipped as TASK 10c - ✅ "Unlock Premium" button —
PremiumUrlset to Polar checkout;IsPremiumAvailableis true; button lights up in the About hub. - ✅ Licensing model — startup re-validates against Polar API. Perpetual key (2026-09-21): the
license never expires,
IsPremiumnever lapses, and the flash does not return. The former renewal/lapse path is dead. Offline grace period (14 days) still applies to the validation call only. - 🔶 Velopack auto-updates — NuGet packages + bootstrap in
App.xaml.cs. Update URL self-hosted on DO droplet (pending configuration).