Files
LlamaCasty/TASKS/task-10-monetization.md
gramps 4e0915a36e feat(backdrop): Capture Window… in-app window pin (TASK 38, Good Dog ONE test)
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.
2026-09-22 07:00:47 -07:00

3.7 KiB
Raw Permalink Blame History

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

  1. ✅ Billing provider — Polar (polar.sh) chosen and configured. Product, price, license key benefit, discounts, checkout link all created.
  2. ✅ 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.
  3. ✅ Offline entitlement — LayoutStore Settings table: LicenseKey, LicenseValidatedAt, IsPremium. 14-day offline grace period. Startup re-validates online, falls back to cache.
  4. ✅ BrandFlash → watermark toggle — IsPremium property setter flips BrandFlashEnabled = !value. Flash stops immediately on premium activation. Flash asset VideoFrame rendering deferred to TASK 4 compositor.
  5. ✅ Remove social slot locks — all 6 social bar slots open to everyone (no IsPremium gating on slots 3-6) — shipped as TASK 10c
  6. ✅ "Unlock Premium" button — PremiumUrl set to Polar checkout; IsPremiumAvailable is true; button lights up in the About hub.
  7. ✅ Licensing model — startup re-validates against Polar API. Perpetual key (2026-09-21): the license never expires, IsPremium never 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.
  8. 🔶 Velopack auto-updates — NuGet packages + bootstrap in App.xaml.cs. Update URL self-hosted on DO droplet (pending configuration).