docs: purge the dead $29/$49 + Polar model from every tracked file, add the Y1 forecast
The pricing ruling landed twice (2026-09-21 one-time, then 2026-09-27 Store IAP $10/mo + $400 lifetime) and the map never caught up. Six tracked files still told a future session that billing was Polar and the price was $29/$49. A stale memory map is worse than a stale comment: it is the file every session trusts, and this one was actively steering work toward a deleted provider. MONETIZATION.md (gitignored, so not in this commit) was rebuilt first: - "Revenue projections" now carries a modelled Year 1 forecast — pessimistic $4.0K / base $15.4K / optimistic $53.3K net, ~$22K weighted. Funnel is installs -> 35-45% activate -> 1.5-3% of active users pay. - Three findings recorded: Year 1 is ~97% lifetime transactions (subs net $392 of $15.4K, so MRR is not a Year-1 planning input); conversion dominates price (~1pp of conversion = ~$7K net, and ADA 6(h) locks $10 anyway); subscriber churn moves Year 1 by under $200 and is a Year-2 problem. - Break-even restated for $400: $25K net = 74 lifetime buyers, not 862. The price cut the volume requirement ~10x and raised the skill requirement to match. - Market sizing willingness-to-pay row rewritten. The 100K-400K TAM was price-bound to $29-49 and is wrong at $400; revised ~20K-60K, flagged as an estimate rather than a sourced number. - Flagged a real contradiction: $500K ARR needs ~4,900 concurrent subscribers, so the Exit section's ARR multiples do not describe what Years 1-3 produce. The defensible asset there is lifetime cash flow, not ARR. Tracked files corrected to match: - ai.md: paid-delta, pricing and billing bullets rewritten; Polar product id, org id, LCYT- key prefix and LLAMAFOUNDER/LLAMA50 marked as deleted; 15% share + net-after-tax recorded with the ADA 6(b)(i) citation. - TASKS.md: catalog row retitled as a teardown; the "still to verify — the price is not decided" note closed (it contradicted the ruling 20 lines below it); the OverlayHost "Polar unlocks alerts" open question marked resolved; Polar file-hosting deliverable removed from the release build. - task-10: reframed as a teardown. Steps 4-5 marked as surviving, 1-2-3-6-7 as deleting, 8 as a compliance action (Velopack downloads AND executes, which Store policy 10.2.2 does not permit). - task-36 item 5 (license-expiry reminders) struck — no key, no expiry, no lapse under Store IAP, so there is nothing to remind anyone about. - Distribution.md 4.2 / 4.4 / 4.5 marked obsolete; 4.5's "already implemented" corrected, since PolarLicenseService is being deleted rather than shipped. - README: "one-time license" -> "paid tier". Historical Polar sections are retained deliberately — the reasoning is reusable (merchant-of-record, fee comparison), only the conclusions are dead. Each is now labelled so it cannot be mistaken for the plan. No code touched.
This commit is contained in:
+37
-10
@@ -318,9 +318,17 @@ Single-file means everything is inside the `.exe`. No DLLs, no runtime dependenc
|
||||
|
||||
**Caveat:** Self-contained single-file means ~80-120MB due to bundled .NET runtime. For smaller size, use framework-dependent publishing (requires .NET 8 runtime on user machines) — drops to ~5-10MB.
|
||||
|
||||
### 4.2 Distribution via Polar
|
||||
### 4.2 Distribution via Polar — ⛔ OBSOLETE (2026-09-27)
|
||||
|
||||
**Product setup on Polar:**
|
||||
> **Superseded by Microsoft Store MSIX + Store IAP** (ruling in
|
||||
> `TASKS/task-48-distribution-msix.md` item 0). The Store re-signs, hosts, updates, and takes
|
||||
> payment — so file hosting, license keys, checkout, the customer portal, device deactivation and
|
||||
> key rotation are **all** handled by Microsoft and none of it needs building. Retained below as a
|
||||
> record of the model that was designed and abandoned. ⚠️ **The `$29`/`$49` one-time prices in this
|
||||
> section are dead** — the settled pricing is **`$10/mo` or `$400` lifetime**, net of a verified
|
||||
> 15% Store share.
|
||||
|
||||
**Product setup on Polar (as designed, never shipped):**
|
||||
|
||||
1. Create a product: "LlamaCasty" — **one-time purchase** (perpetual license; $29 founder / $49 list).
|
||||
2. Add two benefits:
|
||||
@@ -345,6 +353,11 @@ Single-file means everything is inside the `.exe`. No DLLs, no runtime dependenc
|
||||
- If a key is compromised, customer or merchant can rotate it via Polar.
|
||||
- Previous key stops validating immediately. Status, usage, limits, expiry preserved.
|
||||
|
||||
**What the Store does instead:** the customer installs from the Store listing, pays through Store
|
||||
checkout, and the app reads the entitlement the OS already holds. There is no key to enter, no
|
||||
activation call, no portal to visit, and no offline-grace period to maintain — which also retires
|
||||
the whole "network flaky → app thinks I'm expired" bug class in §4.5.
|
||||
|
||||
### 4.3 Code Signing
|
||||
|
||||
> ⚠️ **The cert choice below is a live decision, and the old plan's EV recommendation is
|
||||
@@ -393,7 +406,13 @@ Set-AuthenticodeSignature -FilePath "LlamaCasty.exe" `
|
||||
|
||||
**Storage:** Certificate `.pfx` file stored in GitHub Secrets (or Azure DevOps secure files). Never committed to the repo.
|
||||
|
||||
### 4.4 Update Mechanism
|
||||
### 4.4 Update Mechanism — ⛔ OBSOLETE (2026-09-27)
|
||||
|
||||
> **Superseded by Store updates.** Microsoft delivers and updates the app from the listing, so
|
||||
> there is nothing to check and no manifest to host. The Velopack updater currently in
|
||||
> `App.xaml.cs` **downloads *and executes***, which Store policy **10.2.2** does not permit — its
|
||||
> removal is a **compliance action**, not optional cleanup (TASK 48 item 3). The Polar-native design
|
||||
> below is retained as a record of the approach that was rejected; it is not an option.
|
||||
|
||||
**Polar-native approach (no custom infrastructure):**
|
||||
|
||||
@@ -428,10 +447,18 @@ public class UpdateCheckService
|
||||
- Download link points to Polar's customer portal (not direct download).
|
||||
- This adds one external dependency (GitHub) but keeps Polar as the source of truth.
|
||||
|
||||
### 4.5 Licensing Logic (already implemented)
|
||||
### 4.5 Licensing Logic — ⛔ BEING DELETED (2026-09-27)
|
||||
|
||||
> ⚠️ **"Already implemented" was true as of 2026-09-21 and is no longer.** `PolarLicenseService`
|
||||
> and `Helpers/PolarLicense.cs` are being **removed** as part of the TASK 10 teardown (TASK 48 item 0).
|
||||
> Store IAP replaces the whole validation hop: `IsPremium` is derived from the **OS-supplied Store
|
||||
> entitlement**, so there is no network call, no key, and — importantly — **no 14-day offline-grace
|
||||
> machine to protect**, which retires the entire "network flaky → app thinks I'm expired" bug class.
|
||||
> What survives is only `IsPremium` → `BrandFlashEnabled = !value`. Retained below as the record of
|
||||
> what shipped and why it no longer applies.
|
||||
|
||||
```csharp
|
||||
// Services/PolarLicenseService.cs — already ships
|
||||
// Services/PolarLicenseService.cs — shipped under Polar; being deleted
|
||||
// Calls Polar's customer-portal validation endpoint (no auth required)
|
||||
// Survives obfuscation — property names excluded via [Obfuscation(Exclude = true)]
|
||||
[Obfuscation(Exclude = true)]
|
||||
@@ -444,11 +471,11 @@ public class LicenseValidationResult
|
||||
}
|
||||
```
|
||||
|
||||
**What's already done:**
|
||||
- `PolarLicenseService` validates keys against Polar API.
|
||||
- `OrganizationId` is hardcoded (safe — it's public knowledge, tied to our Polar account).
|
||||
- License state persists in `LayoutStore.Settings` (SQLite) with offline grace period.
|
||||
- `PremiumUrl` points to Polar checkout.
|
||||
**What shipped under Polar (now being deleted):**
|
||||
- `PolarLicenseService` validated keys against the Polar API.
|
||||
- `OrganizationId` was hardcoded.
|
||||
- License state persisted in `LayoutStore.Settings` (SQLite) with an offline grace period.
|
||||
- `PremiumUrl` pointed to Polar checkout.
|
||||
|
||||
**What survives obfuscation:** The validation logic in `Services.dll` is obfuscated. An attacker who decompiles the exe sees only the UI calling an interface — the actual Polar API call is in the obfuscated DLL.
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ text sources, chat on-stream, the social bar, mic/desktop audio with auto-duck a
|
||||
recording, variable quality tiers with auto step-down, one-click go-live + scheduling, stream
|
||||
resilience (auto-reconnect inside YouTube's grace, one-click back on air), built-in monetization
|
||||
awareness (reward capture, session reports, YPP journey tracker), Alerts — all free and ungated;
|
||||
the one-time license only removes the branding flash.
|
||||
the paid tier only removes the branding flash.
|
||||
|
||||
## Structure
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
| 07 | Meter scaling amplification | ✅ Done | [`TASKS/task-07-meter-scaling.md`](TASKS/task-07-meter-scaling.md) |
|
||||
| 08 | Audio milestone | ✅ SHIPPED 2026-08-14 | [`TASKS/task-08-audio-milestone.md`](TASKS/task-08-audio-milestone.md) |
|
||||
| 09 | YouTube Live Stream Management | ⏳ In progress — items 1–3, 4 shipped; item 5 open; item 6 locked (TASK 36) | [`TASKS/task-09-live-stream-management.md`](TASKS/task-09-live-stream-management.md) |
|
||||
| 10 | Monetization: watermark-only one-time license + Polar billing | 🔶 In progress — steps 1–7 shipped; **now a TEARDOWN: Polar is deleted in favour of Store IAP (2026-09-27)** | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) |
|
||||
| 10 | Monetization: watermark-only paid delta (branding flash) | 🔶 **TEARDOWN, not a build** — Polar deleted in favour of Store IAP (2026-09-27); `$10/mo` + `$400` lifetime, no annual | [`TASKS/task-10-monetization.md`](TASKS/task-10-monetization.md) |
|
||||
| 11 | Post-pause polish batch (creator's 8 review issues) | ✅ SHIPPED 2026-08-15 | [`TASKS/task-11-polish-batch.md`](TASKS/task-11-polish-batch.md) |
|
||||
| 12 | Master limiter on the live mix | ☐ Queued | [`TASKS/task-12-master-limiter.md`](TASKS/task-12-master-limiter.md) |
|
||||
| 13 | Social media launch kit | 🔶 Scoped — queued after v1 | [`TASKS/task-13-social-launch-kit.md`](TASKS/task-13-social-launch-kit.md) |
|
||||
@@ -120,8 +120,9 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw
|
||||
- **Shipping / release build (creator-queued 2026-09-26)** — no publish config exists yet:
|
||||
the csproj has only `OutputType=WinExe` + `TargetFramework`, so a plain `dotnet publish`
|
||||
is **framework-dependent** (customer needs the .NET 8 Desktop Runtime preinstalled).
|
||||
`Distribution.md` targets a self-contained ~80–120MB `LlamaCasty.exe` uploaded to Polar
|
||||
as a File Download benefit. Two deliverables:
|
||||
`Distribution.md` targets a self-contained ~80–120MB `LlamaCasty.exe`. ⛔ **The Polar
|
||||
File-Download benefit is dead** — the Store hosts and updates the app, so there is no upload
|
||||
step (TASK 48). Two deliverables:
|
||||
1. **`scripts/publish.sh`** wrapping
|
||||
`dotnet publish ytLive.csproj -c Release -r win-x64 --self-contained true -o ./publish/win-x64`,
|
||||
and **asserting the output contains no test/xunit artifacts**. (The compile side needs
|
||||
@@ -235,9 +236,12 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw
|
||||
- **Unchanged:** the watermarks posture. Free gets everything; the branding flash stays the
|
||||
ONLY paid delta (TASK 36 item 2). Store IAP changes how the bit is *obtained*, never what
|
||||
it *gates*.
|
||||
- **Still to verify (does not block packaging):** current Store revenue-share terms — ⚠️ do
|
||||
not assume any percentage, verify before setting a price; and the one-time vs
|
||||
subscription shape of the IAP tier (the storefront is decided, the price is not).
|
||||
- **Both formerly-open questions are now CLOSED (2026-09-27).** Store revenue share is
|
||||
**verified at 15%, subscriptions included** (ADA v8.10 §6(b)(i) — read from the PDF, not a
|
||||
search excerpt), and the IAP tier shape is **decided: `$10/mo` subscription + `$400`
|
||||
lifetime, no annual**, declared in Partner Center as two products. Full detail in
|
||||
`TASKS/task-48-distribution-msix.md` item 0. ⚠️ Do **not** re-open the fee question without
|
||||
re-reading the ADA, and do not *assume* 15% if the terms ever move.
|
||||
- **✅ item 1 SHIPPED 2026-09-28 — bundle ffmpeg instead of downloading it.** The app no
|
||||
longer fetches an executable at runtime (Store policy 10.2.2, and the pin 404'd on the
|
||||
creator's first real recording on 2026-09-01). `scripts/fetch-ffmpeg.sh` populates a
|
||||
@@ -310,8 +314,10 @@ second encoder path needing a "redirect". Record+simulcast is one ffmpeg with tw
|
||||
- Still queued from earlier: `scripts/publish.sh` (self-contained win-x64, no test artifacts,
|
||||
Debug-only `InternalsVisibleTo`, no WPF trimming), and the `LlamaCasty.exe` assembly rename
|
||||
(three pack URIs incl. `MainWindow.xaml:14` — do not rename `%APPDATA%\ytLlive`).
|
||||
- Decide the open business question: `OverlayHost.xaml` copy says Polar unlocks *alerts* too, but
|
||||
alerts are not gated by `IsPremium`. Either fix the copy or gate the alerts — do not leave it.
|
||||
- ✅ **RESOLVED — do not re-open.** The `OverlayHost.xaml` copy claimed Polar unlocked *alerts*;
|
||||
alerts were never gated by `IsPremium`. The file is **deleted outright** by the TASK 10 teardown
|
||||
(TASK 48 item 0), so the copy is gone with it. The "or gate the alerts" option is **permanently
|
||||
closed** — there is no feature gating, ever.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,12 +1,36 @@
|
||||
# TASK 10 — Monetization: watermark-only one-time license + Polar billing
|
||||
# TASK 10 — Monetization: watermark-only paid delta (branding flash)
|
||||
|
||||
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
|
||||
|
||||
**Goal:** a **paid tier that removes the branding flash and nothing else.** Every feature is free
|
||||
— Alerts, social bar slots, voice filters, TRAX, recording, analytics. The free tier is the *full*
|
||||
app. ⛔ **There is no feature gating, ever** — revenue argument, not taste: the free tier's reach
|
||||
is the funnel, and the flash is an ad running inside other people's content, so a free user with a
|
||||
flash every 30–60s is already paying in exposure.
|
||||
|
||||
**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.)
|
||||
**⚠️ STATUS: THIS IS A TEARDOWN, NOT A BUILD (2026-09-27).** The billing provider is
|
||||
**Microsoft Store IAP**, not Polar. Everything below describing Polar is **dead** and is retained
|
||||
only as history. **Do not resurrect any of it.** The teardown's file-by-file list lives in
|
||||
[`TASKS/task-48-distribution-msix.md`](task-48-distribution-msix.md) item 0 — **work from there,
|
||||
not from this file.**
|
||||
|
||||
**Pricing — ✅ DECIDED 2026-09-27: `$10/mo` subscription, or `$400` lifetime. No annual.**
|
||||
|
||||
| Tier | Price | Net after 15% | Role |
|
||||
|---|---|---|---|
|
||||
| Free | $0 | — | Everything, plus the branding flash. The funnel. |
|
||||
| **Pro monthly** | **$10/mo** | ~$8.50/mo | The default. Low-risk entry. |
|
||||
| **Pro lifetime** | **$400** | ~$340 | The hedge. Committed / subscription-hostile buyers. |
|
||||
|
||||
- **15% Store revenue share, subscriptions included** — verified from the ADA v8.10 PDF, §6(b)(i).
|
||||
Net receipts are after VAT/GST, so commission is not paid on pass-through tax.
|
||||
- **Break-even is month 40**, so the two tiers barely compete — which is why lifetime is safe to
|
||||
offer at launch rather than saving it for later.
|
||||
- ⛔ **No annual tier** — Microsoft does not pro-rate and the developer cannot refund the
|
||||
forfeited remainder. ⛔ **No `.99` prices.** ⛔ **No discounted upgrade SKU.**
|
||||
- **ADA §6(h): raising the price disables auto-renew ⇒ `$10` is effectively locked for life.**
|
||||
- ⛔ **Superseded pricing, do not cite:** the 2026-09-21 one-time model (`$29` founder → `$49`
|
||||
list lifetime) and the earlier `$49.99/yr → $99/yr` subscription.
|
||||
|
||||
**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 —
|
||||
@@ -19,26 +43,32 @@ narrative, not a separate task number — it ships in its own code slices with o
|
||||
**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).**
|
||||
**Business details (pricing, Partner Center product declaration) 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: 🔶 TEARDOWN — steps 1–7 shipped under Polar, all now to be removed
|
||||
|
||||
### 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).
|
||||
Steps 1–7 below are a **record of what was built**, not a description of what ships. The Polar
|
||||
licensing path is being deleted because Store IAP supplies the same bit from the OS entitlement.
|
||||
|
||||
1. ⛔ **Billing provider** — was Polar (polar.sh). **DELETED.** The product, checkout link, and the
|
||||
discount codes `LLAMAFOUNDER` / `LLAMA50` no longer exist. Store IAP products are declared in
|
||||
**Partner Center**, not Polar.
|
||||
2. ⛔ **License key entry + verification UI** — was the About-overlay swap panel
|
||||
("Enter License Key"). **DELETING.**
|
||||
3. ⛔ **Offline entitlement** — was `LayoutStore` Settings (`LicenseKey`, `LicenseValidatedAt`,
|
||||
`IsPremium`) + a 14-day offline grace period + startup re-validation. **DELETING.** The OS
|
||||
supplies license state, so the entire offline-grace machine goes with it — along with the whole
|
||||
"network flaky → app thinks I'm expired" bug class.
|
||||
4. ✅ **BrandFlash → watermark toggle** — `IsPremium` setter flips `BrandFlashEnabled = !value`, so
|
||||
the flash stops the moment the entitlement flips. **This survives the teardown.** Under Store IAP
|
||||
`IsPremium` is derived from the Store entitlement rather than a remote HTTP call. One bit,
|
||||
locally cached, refreshed by the OS. ⚠️ **This is the whole product surface of the paid tier.**
|
||||
5. ✅ **Remove social slot locks** — all 6 social bar slots open to everyone. **Survives.**
|
||||
6. ⛔ **"Unlock Premium" button** — `PremiumUrl` pointed at Polar checkout. **DELETING**; the Store
|
||||
handles purchase. Paid users see zero license UI.
|
||||
7. ⛔ **Licensing model / renewal-lapse path** — already dead before the Store ruling (a perpetual
|
||||
key never expires). Now superseded again: **Store IAP has no keys at all.**
|
||||
8. 🔶 **Velopack auto-updates** — NuGet packages + bootstrap in `App.xaml.cs`. **TEARDOWN is a
|
||||
compliance action, not cleanup:** the updater downloads *and executes*, and Store policy 10.2.2
|
||||
does not permit it. Tracked as [`TASKS/task-48-distribution-msix.md`](task-48-distribution-msix.md)
|
||||
item 3; the Store updates the app instead.
|
||||
@@ -39,7 +39,7 @@ The tasks below are ordered by dependency and risk. Each task builds on the prev
|
||||
|
||||
1. ✅ **TASK 9.4** — Live chat (right panel) — wire `YouTubeChatService.Start()`, parse messages, render in panel. Foundation for chat box source.
|
||||
2. ✅ **TASK 3.18** — Chat box source — renders chat ON the stream. Depends on TASK 9.4 (same message parsing).
|
||||
3. ✅ **TASK 10** — Polar billing — license key entry + watermark toggle + Velopack auto-updates (steps 1-7 shipped; Velopack update URL pending).
|
||||
3. ✅ **TASK 10** — watermark-only paid delta (brand flash). Steps 1–7 shipped under **Polar**, which is **now deleted in favour of Microsoft Store IAP** (2026-09-27) — TASK 10 is a **teardown**, and the Velopack updater goes with it (Store policy 10.2.2).
|
||||
4. ✅ **TASK 19/23** — Control Surface UX — director's control room: thumbnails above central monitor, transitions (Cut/Fade/Move), edit mode offline only, left panel two-state (layers/props ↔ chat), right panel eliminated. Verified shipped 2026-08-24.
|
||||
5. ✅ **TASK 20** — Hotkeys — global keyboard shortcuts. Shipped 2026-08-26: F1-F9 defaults + config UI with modifier chords, persistence, conflict detection, unbinding.
|
||||
5b. ✅ **Broadcast metadata pull-out + launch geometry** — shipped 2026-08-24 (row 29 above). Live-screen "Text" tab → broadcast form, persistence + remote update; window default/minimums bumped (1920×1040 / 1366×768) with size+position restore.
|
||||
|
||||
@@ -17,10 +17,11 @@ may be done opportunistically mid-development — each item has a lock/comment p
|
||||
real mp4 decode/loop/pacing (TASK 21 picker must have landed), real recording file opens +
|
||||
plays (fragmented MP4), a real private go-live end-to-end, GUI/RealApp test classes green on
|
||||
the desktop (they've only ever run against fakes).
|
||||
5. ☐ **License-expiry reminders** — T-14 / T-7 / T-1 toasts via the existing notification stack
|
||||
("renews <date> — manage here" → `PremiumUrl`); lapsed: flash returns (the product itself is the
|
||||
notice) + one Info toast; active paid users see ZERO license UI. Research: does Polar's
|
||||
validate response carry `expires_at` reliably — cite before building.
|
||||
5. ⛔ **STRUCK — License-expiry reminders are dead.** This item assumed a Polar license with an
|
||||
`expires_at` we could warn about. Under **Store IAP** there is no key, no expiry, and no lapse:
|
||||
the lifetime entitlement never ends and the subscription is renewed by Microsoft. **Nothing to
|
||||
remind anyone about — do not build.** (The `expires_at` question is moot for the same reason:
|
||||
`PolarLicenseService` is being deleted.)
|
||||
6. ☐ **Release engineering** (the `Distribution.md` plan, 644 lines, finally tasked): code signing
|
||||
(HARD blocker — an unsigned installer is a SmartScreen scarewall), installer + Velopack update URL
|
||||
(TASK 10 item 8), EULA draft/review, THIRD-PARTY-NOTICES license-texts gate (TASK 4 req 9).
|
||||
|
||||
@@ -1506,7 +1506,8 @@ Apply this to every UI decision:
|
||||
|
||||
## Monetization (design decision — the branding flash is the sword)
|
||||
|
||||
Full pricing, discount codes, and Polar product details in `MONETIZATION.md` (gitignored).
|
||||
Full pricing and the Year 1 revenue forecast in `MONETIZATION.md` (gitignored). ⚠️ **No Polar
|
||||
product, discount code, or license key exists any more** — billing is Microsoft Store IAP.
|
||||
Brand palette and assets in `MARCOM.md` (gitignored). This section covers the in-app model.
|
||||
|
||||
Free forever: **all features unlocked for everyone** — no feature lock between free and paid.
|
||||
@@ -1554,30 +1555,40 @@ crooked.
|
||||
credit — `Advance` both *opens* the presentation and *ages* it by the same delta, so a single
|
||||
5.1s step blows clean through the 2s window. Always step in 1/30s increments like the real timer
|
||||
(the `Step` helpers in `BrandFlashOutputTests`).
|
||||
- **Paid (one-time perpetual license):** branding flash removed. `BrandFlashEnabled` is now a
|
||||
**derived, non-assignable** `!IsPremium` and the presenter's own `Enabled` gate is re-checked on
|
||||
every frame, so a key entered (or revoked) mid-credit cuts the advertisement on the next tick
|
||||
rather than letting it finish. That's it. No feature gating. Alerts, social bar slots, voice
|
||||
filters, TRAX, recording — everything is free.
|
||||
- **Pricing (2026-09-21 — switched from subscription to one-time "own it"):** **$29 lifetime** founder's
|
||||
price (launch → 90 days) → **$49 lifetime** list at GA. The key is **perpetual** (`IsPremium` never
|
||||
lapses; the old renewal/lapse path is dead). Rationale: a local app with no per-user server cost and a
|
||||
renewal-averse, free-surrounded audience — minimize commitment size, don't charge rent. Accessibility is
|
||||
the driver: the free tier is the *full* app (only the watermark differs), so a broke new streamer pays $0;
|
||||
the low one-time price is the "no recurring bill" entry. Full reasoning, and the dropped $49.99/yr →
|
||||
$99/yr subscription model, in `MONETIZATION.md`.
|
||||
- **Billing:** **Polar (polar.sh)** — open-source MoR (Apache 2.0), handles payments, **one-time orders**,
|
||||
license keys, and global tax compliance. Startup Program gives Scale plan free for 12 months.
|
||||
Product: `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` (⚠️ currently a $99/yr *subscription* product — must be
|
||||
re-created as a one-time product for the new model). Checkout: `llamacasty.com` → Polar hosted page.
|
||||
Org ID: `c05fb364-b967-4f6c-adf2-8a144e46d085` (org-scoped OAT — `organization_id` omitted from API calls).
|
||||
Key prefix: `LCYT-`. Discounts: `LLAMAFOUNDER` (100% off, 50 uses), `LLAMA50` (50% off, 12 months). Details in `MONETIZATION.md`.
|
||||
- **Paid:** branding flash removed. `BrandFlashEnabled` is now a **derived, non-assignable**
|
||||
`!IsPremium` and the presenter's own `Enabled` gate is re-checked on every frame, so the
|
||||
entitlement changing mid-credit cuts the advertisement on the next tick rather than letting it
|
||||
finish. That's it. No feature gating. Alerts, social bar slots, voice filters, TRAX, recording —
|
||||
everything is free. **How `IsPremium` is obtained is a billing concern and has changed twice;
|
||||
what it gates has not.**
|
||||
- **Pricing (✅ DECIDED 2026-09-27 — supersedes the 2026-09-21 one-time "own it" model):**
|
||||
**`$10/mo` subscription, or `$400` lifetime. No annual. No `.99` prices.** ⛔ The old `$29`
|
||||
founder → `$49` list lifetime ruling is **dead — do not cite it.** Two tiers, one delta: they
|
||||
break even at **month 40**, so they barely compete, which is why lifetime is safe to offer at
|
||||
launch instead of saving it for later. The free tier is the *full* app (only the watermark
|
||||
differs), so accessibility is preserved without pricing down. ⛔ No annual tier: Microsoft does
|
||||
not pro-rate and **the developer cannot refund** the forfeited remainder — verbatim the
|
||||
grievance that drove the ruling. **ADA §6(h): raising the price disables auto-renew, so `$10` is
|
||||
effectively locked for the product's life.** Full reasoning in `MONETIZATION.md` → Pricing.
|
||||
- **Billing: ⛔ Polar is DELETED — Microsoft Store IAP, Microsoft as merchant of record** (ruling
|
||||
2026-09-27; teardown in `TASKS/task-48-distribution-msix.md` item 0). **Revenue share 15%,
|
||||
subscriptions included** — verified from the ADA v8.10 PDF, §6(b)(i); the agreement's own v8.0
|
||||
changelog says *"85/15 revenue share for non-Game subscriptions"*. ⇒ net **~$8.50/mo**,
|
||||
**~$340** lifetime. Microsoft handles VAT/GST/sales tax, refunds, chargebacks, the customer
|
||||
portal, and device deactivation — the strongest argument for the switch. Net receipts are after
|
||||
tax, so commission is not paid on pass-through tax. Payouts monthly, $50 threshold.
|
||||
⚠️ **No Polar product, org ID, key prefix, or discount code exists any more** — `d105dfa1-…`,
|
||||
`c05fb364-…`, `LCYT-`, `LLAMAFOUNDER`/`LLAMA50`, the customer-portal validate endpoint, and the
|
||||
14-day offline-grace machine are all being deleted. Products are declared in **Partner Center**
|
||||
instead: one auto-renewing monthly subscription + one non-expiring lifetime IAP.
|
||||
⛔ A discounted subscriber→lifetime upgrade SKU is **not** approved.
|
||||
- **Support (creator's model, corrected 2026-09-01):** support = email + GitHub issues — the
|
||||
once-planned in-app bug-reporter is **out of product** (TASKS.md → closed list). 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. The only license chatter is the paid-user **expiry
|
||||
reminder — now moot** (perpetual keys never expire, one-time model 2026-09-21); paid users see zero
|
||||
license UI. TASK 36 item 5 (expiry reminder) is superseded.
|
||||
reminder — now moot** (superseded twice: keys are moot because the lifetime entitlement never
|
||||
expires, and the entire license-key system is moot because Store IAP has no keys); paid users see
|
||||
zero license UI. TASK 36 item 5 (expiry reminder) is struck.
|
||||
|
||||
**Monetization awareness (built-in, ungated, free — 2026-09-01; v1 SCOPE per the complete-v1
|
||||
ruling — build order: capture → report → journey → Alerts):** the app is monetization-aware by
|
||||
|
||||
Reference in New Issue
Block a user