feat: BRB backdrop seed + docs refresh + Polar org ID

- Add brb-backdrop.jpg asset, SeedBrbBackdrop() mirrors Starting pattern
- Update HANDOFF.md (was stale), TASKS.md (TASK 10 ready, TASK 15 2/5), ai.md (org ID)
- Polar org ID c05fb364 obtained via OAT, recorded in CREDENTIALS.md
This commit is contained in:
2026-08-19 15:01:23 -07:00
parent 26828ccdd7
commit f40ec83e69
6 changed files with 94 additions and 43 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

+35 -21
View File
@@ -1,21 +1,25 @@
# HANDOFF — Session State # HANDOFF — Session State
## Branch ## Branch
`main` — dirty (social slot lock removal + doc updates) `main` — dirty (BRB backdrop + Polar org ID + doc updates, uncommitted)
## What shipped this session ## What shipped this session
- **Branding palette + assets recorded** — `ai.md` Brand section (references `MARCOM.md`), `MARCOM.md` gets the full hex palette and asset inventory - **BRB backdrop seeded on every load** — `Assets/brb-backdrop.jpg` (user-provided image, Gemini-generated),
- **AI transparency statement** — `ai.md` Brand section documents AI-assisted pair-programming added as `<Resource>` in csproj; `SeedBrbBackdrop()` in MainViewModel mirrors the Starting pattern
- **Monetization model updated** — `ai.md` Monetization section rewritten: no feature lock, only watermark difference; all features free for everyone (idempotent, skips if Background already exists). Runs on every startup outside the
- **TASKS.md updated** — TASK 10 re-scoped (Polar billing, watermark-only), tasks 15-18 added (stock bg images, infinity display fix, web source WebView2, local recording) `Scenes.Count == 0` guard.
- **TASK 10c shipped** — social slot locks removed: `SocialsDialogViewModel` no longer takes `isPremium` parameter, slots 3-6 always available, tests updated - **UI rename: Screens → Layers → Properties** — 16 UI text changes across MainWindow.xaml + MainViewModel.cs
- **v1 feature completeness** — competitive gap analysis completed; 5 new tasks added (19-23) for table-stakes features: scene transitions, hotkeys, media source, audio sync offset, studio mode (section headers, tooltips, context menus, empty hints, onboarding text, fallback display name).
- **MONETIZATION.md updated** — v1 feature completeness section added with competitive context Code identifiers unchanged.
- **ai.md updated** — v1 task queue documented in Current limitations/TODOs section - **Polar org ID obtained** — `c05fb364-b967-4f6c-adf2-8a144e46d085` (Llama Chile Shop, slug: llamacasty).
Organization Access Token (OAT) stored in `Downloads/llamacasty-polar-code.txt`.
OATs are org-scoped — `organization_id` can be omitted from API calls.
- **CREDENTIALS.md updated** — Polar org ID + validate endpoint + key prefix (`LCYT-`) recorded.
## Polar.sh resources (from earlier session) ## Polar.sh resources
| Resource | ID | | Resource | ID |
|---|---| |---|---|
| Org ID | `c05fb364-b967-4f6c-adf2-8a144e46d085` |
| Product | `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` | | Product | `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` |
| Price | `7c1b6f70-cf8c-46df-9bc8-6703f9fa64d0` | | Price | `7c1b6f70-cf8c-46df-9bc8-6703f9fa64d0` |
| Benefit | `80f66bc1-d5a3-44a1-b9ea-1709ae508535` | | Benefit | `80f66bc1-d5a3-44a1-b9ea-1709ae508535` |
@@ -23,6 +27,8 @@
| LLAMAFOUNDER | `01a8c29f-9bb8-4e96-9cbe-417a6a5cec9b` | | LLAMAFOUNDER | `01a8c29f-9bb8-4e96-9cbe-417a6a5cec9b` |
| LLAMA50 | `8cff803e-053f-49b4-8d12-d74d468f2943` | | LLAMA50 | `8cff803e-053f-49b4-8d12-d74d468f2943` |
| Checkout URL | `https://buy.polar.sh/polar_cl_ueMy8AyAClO0o0yo19IroZwKTbD587gzUsjEW3bFapw` | | Checkout URL | `https://buy.polar.sh/polar_cl_ueMy8AyAClO0o0yo19IroZwKTbD587gzUsjEW3bFapw` |
| Customer-portal validate | `POST https://api.polar.sh/v1/customer-portal/license-keys/validate` |
| Key prefix | `LCYT-` |
## Build ## Build
```bash ```bash
@@ -31,18 +37,25 @@ taskkill.exe /F /IM ytLive.exe # if running
"/mnt/c/Program Files/dotnet/dotnet.exe" vstest "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.Tests\bin\Debug\net8.0-windows10.0.19041.0\ytLive.Tests.dll" "/mnt/c/Program Files/dotnet/dotnet.exe" vstest "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.Tests\bin\Debug\net8.0-windows10.0.19041.0\ytLive.Tests.dll"
``` ```
## Known issues
- `Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback` integration test is flaky — hangs when
run via `vstest` (likely tries to acquire WASAPI devices in headless CI). Exclude with
`--TestCaseFilter:"FullyQualifiedName!~Mix_HonorsProviderGains"` if needed.
- Build often fails when ytLive.exe is running — `taskkill.exe /F /IM ytLive.exe` first.
## Next steps ## Next steps
1. **Build + test** — verify social slot lock removal compiles and tests pass 1. **TASK 10 + Velopack** — license validation + auto-updates (1 full session). Polar org ID + OAT
2. **TASK 9 item 4** — live chat (poll + render + badges) — already coded, just needs wiring now available; all infra ready. Phases: LicenseService, license key UI, brand flash gating,
3. **TASK 20** — hotkeys (global keyboard shortcuts) — small scope, huge UX impact Velopack integration, tests.
4. **TASK 19** — scene transitions (Cut/Fade/Move/Custom) — already scoped 2. **TASK 20** — hotkeys (global keyboard shortcuts) — small scope, huge UX impact
5. **TASK 17** — web source WebView2 (enables alert ecosystem) 3. **TASK 19** — scene transitions (Cut/Fade/Move/Custom) — already scoped
6. **TASK 18** — local recording (independent) 4. **TASK 17** — web source WebView2 (enables alert ecosystem)
7. **TASK 21** — media source (video file playback) — pairs with TRAX for non-Live scenes 5. **TASK 18** — local recording (independent)
8. **TASK 22** — audio sync offset — small, quality-of-life 6. **TASK 21** — media source (video file playback) — pairs with TRAX for non-Live scenes
9. **TASK 23** — studio mode (lightweight preview) 7. **TASK 22** — audio sync offset — small, quality-of-life
10. **TASK 15** — wait for user to provide stock scene background images 8. **TASK 23** — studio mode (lightweight preview)
11. **TASK 16** — kill infinity display (depends on TASK 15) 9. **TASK 15** — stock bg images — Starting and BRB seeded; Live, Chat, Ending still waiting on user images
10. **TASK 16** — kill infinity display (depends on TASK 15 for Live/Chat/Ending images)
## v1 vision ## v1 vision
> A streaming tool that's intuitive and ready to go out-the-gate with nothing held back. > A streaming tool that's intuitive and ready to go out-the-gate with nothing held back.
@@ -52,3 +65,4 @@ taskkill.exe /F /IM ytLive.exe # if running
- Polar checkout page ~80% configured — needs logo upload via dashboard - Polar checkout page ~80% configured — needs logo upload via dashboard
- Logo upload API was broken (Polar server 500 on `/v1/files/{id}/uploaded`) — upload via dashboard instead - Logo upload API was broken (Polar server 500 on `/v1/files/{id}/uploaded`) — upload via dashboard instead
- Full codebase rename (ytLlive → LlamaCasty) still pending - Full codebase rename (ytLlive → LlamaCasty) still pending
- BRB backdrop image is user-provided (Gemini-generated) — may need replacement with branded image
+25 -20
View File
@@ -704,17 +704,20 @@ free — the only difference between free and paid is the watermark.
**Polar product:** `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` (LlamaCasty, $99/yr, currently `private`) **Polar product:** `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0` (LlamaCasty, $99/yr, currently `private`)
**Checkout:** `llamacasty.com` → Polar hosted page (~80% configured) **Checkout:** `llamacasty.com` → Polar hosted page (~80% configured)
**Discounts:** `LLAMAFOUNDER` (100% off, 50 uses, `once`), `LLAMA50` (50% off, 12 months, unlimited) **Discounts:** `LLAMAFOUNDER` (100% off, 50 uses, `once`), `LLAMA50` (50% off, 12 months, unlimited)
**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: 🔶 Scoped — Polar infra live, in-app plumbing not built ### Status: 🔶 Ready to execute — Polar infra live, org ID obtained, in-app plumbing not built
1. ✅ **Billing provider** — Polar (polar.sh) chosen and configured. Product, price, license key benefit, discounts, checkout link all created. 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 or dedicated dialog; key entry field + validate against Polar API 2. ☐ **License key entry + verification UI** — About overlay or dedicated dialog; key entry field + validate against Polar API
3. ☐ **Offline entitlement** — cached license state in `LayoutStore` (schema bump); online check at startup, offline grace period 3. ☐ **Offline entitlement** — cached license state in `LayoutStore` (schema bump); online check at startup, offline grace period
4. ☐ **BrandFlash → watermark toggle** — `BrandFlashEnabled = false` when licensed; the flash asset image needs to be created (the XAML `TextBlock` is preview-only, the compositor needs a `VideoFrame`) 4. ☐ **BrandFlash → watermark toggle** — `BrandFlashEnabled = false` when licensed; the flash asset image needs to be created (the XAML `TextBlock` is preview-only, the compositor needs a `VideoFrame`)
5. ☐ **Remove social slot locks** — all 6 social bar slots open to everyone (no `IsPremium` gating on slots 3-6) 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 `llamacasty.com` checkout; `IsPremiumAvailable` becomes true 6. ☐ **"Unlock Premium" button** — `PremiumUrl` set to `llamacasty.com` checkout; `IsPremiumAvailable` becomes true
7. ☐ **Renewal/lapse handling** — key expiry check, grace period, re-prompt 7. ☐ **Renewal/lapse handling** — key expiry check, grace period, re-prompt
8. ☐ **In-app bug-report → git issues** — built-in report control; good error codes first, optional log attachment 8. ☐ **Velopack auto-updates** — NuGet packages + UpdateManager shim + GitHub Releases (`gramps/ytLlive`)
--- ---
@@ -845,12 +848,14 @@ No changes to `MusicPlayer`, the 0.20 cap, the ducker, or the meter zones. Build
**Goal:** branded background images for each canonical scene (Starting, Live, BRB, Chat, Ending) **Goal:** branded background images for each canonical scene (Starting, Live, BRB, Chat, Ending)
that both provide working hints to creators and self-promote LlamaCasty. that both provide working hints to creators and self-promote LlamaCasty.
### Status: ☐ Waiting on user to provide images ### Status: 🔶 2/5 seeded — Starting and BRB done; Live, Chat, Ending waiting on user images
1. ☐ User provides 5 background images (one per canonical scene), PNG format, 1920×1080 1. ✅ **Starting backdrop** — `Assets/starting-backdrop.jpg` (embedded resource), `SeedStartingBackdrop()` in MainViewModel, idempotent
2. ☐ Wire images as default `Background` sources, auto-populated on DB seed (empty DB → each scene gets its branded bg) 2. ✅ **BRB backdrop** — `Assets/brb-backdrop.jpg` (user-provided Gemini image), `SeedBrbBackdrop()` in MainViewModel, idempotent
3. ☐ Assets stored in DB via `Asset` table (BLOB, SHA-256 keyed) — survives file deletion 3. ☐ User provides 3 more background images (Live, Chat, Ending), PNG/JPG format, 1920×1080
4. ☐ Used by TASK 16 (infinity display fix) as the static fallback when no game is detected 4. ☐ Wire images as default `Background` sources, auto-populated on DB seed
5. ☐ Assets stored in DB via `Asset` table (BLOB, SHA-256 keyed) — survives file deletion
6. ☐ Used by TASK 16 (infinity display fix) as the static fallback when no game is detected
### Design decisions ### Design decisions
@@ -939,18 +944,18 @@ capturing the primary display (which causes the infinity mirror effect).
The tasks below are ordered by dependency and risk. Each task builds on the previous. The tasks below are ordered by dependency and risk. Each task builds on the previous.
1. **TASK 9.4** — Live chat (right panel) — wire `YouTubeChatService.Start()`, parse messages, render in panel. Foundation for chat box source. 1. ✅ **TASK 9.4** — Live chat (right panel) — wire `YouTubeChatService.Start()`, parse messages, render in panel. Foundation for chat box source.
2. **TASK 20** — Hotkeys — global keyboard shortcuts. Small scope, huge UX impact. 2. ✅ **TASK 3.18** — Chat box source — renders chat ON the stream. Depends on TASK 9.4 (same message parsing).
3. **TASK 19** — Scene transitions — Cut/Fade/Move/Custom. Depends on compositor. 3. **TASK 10** — Polar billing — in-app license key entry + watermark toggle + Velopack auto-updates.
4. **TASK 17** — Web source (WebView2) — enables alert ecosystem. 4. **TASK 20** — Hotkeys — global keyboard shortcuts. Small scope, huge UX impact.
5. **TASK 18** — Local recording — independent, but pairs with stream. 5. **TASK 19** — Scene transitions — Cut/Fade/Move/Custom. Depends on compositor.
6. **TASK 21** — Media source — video file playback for non-Live scenes. 6. **TASK 17** — Web source (WebView2) — enables alert ecosystem.
7. **TASK 22** — Audio sync offset — small, quality-of-life. 7. **TASK 18** — Local recording — independent, but pairs with stream.
8. **TASK 23** — Studio mode — lightweight preview before live. 8. **TASK 21** — Media source — video file playback for non-Live scenes.
9. ✅ **TASK 3.18** — Chat box source — renders chat ON the stream. Depends on TASK 9.4 (same message parsing). 9. **TASK 22** — Audio sync offset — small, quality-of-life.
10. **TASK 15** — Stock bg images — waiting on user. 10. **TASK 23** — Studio mode — lightweight preview before live.
11. **TASK 16** — Infinity display fix — depends on TASK 15. 11. **TASK 15** — Stock bg images — Starting and BRB seeded; Live, Chat, Ending still waiting on user.
12. **TASK 10** — Polar billing — in-app license key entry + watermark toggle. 12. **TASK 16** — Infinity display fix — depends on TASK 15.
13. **TASK 13** — Social media launch kit — after all v1 features ship. 13. **TASK 13** — Social media launch kit — after all v1 features ship.
--- ---
+29
View File
@@ -1356,6 +1356,7 @@ public class MainViewModel : ViewModelBase
AddScene(name); AddScene(name);
} }
SeedStartingBackdrop(); SeedStartingBackdrop();
SeedBrbBackdrop();
// The live backdrop belongs to Live only; a pre-policy DB may have // The live backdrop belongs to Live only; a pre-policy DB may have
// backdrops lingering in other scenes — drop them, then // backdrops lingering in other scenes — drop them, then
@@ -1764,6 +1765,34 @@ public class MainViewModel : ViewModelBase
catch { /* non-critical — stream works fine without a default bg */ } catch { /* non-critical — stream works fine without a default bg */ }
} }
private void SeedBrbBackdrop()
{
try
{
var brb = Scenes.FirstOrDefault(s => SceneCatalog.Is(s.Name, "BRB"));
if (brb == null) return;
if (brb.Elements.OfType<Source>().Any(s => s.Type == SourceType.Background)) return;
var uri = new Uri("pack://application:,,,/Assets/brb-backdrop.jpg", UriKind.Absolute);
using var stream = Application.GetResourceStream(uri)?.Stream;
if (stream == null) return;
using var ms = new MemoryStream();
stream.CopyTo(ms);
var bytes = ms.ToArray();
var assetId = AddAsset(bytes);
if (assetId == null) return;
brb.Elements.Add(new Source
{
Name = "Background",
Type = SourceType.Background,
AssetId = assetId,
Width = 1920,
Height = 1080,
});
}
catch { /* non-critical — stream works fine without a default bg */ }
}
private void BeginEditElement(SceneElement? element) private void BeginEditElement(SceneElement? element)
{ {
if (element == null) return; if (element == null) return;
+4 -2
View File
@@ -132,7 +132,8 @@ C# / WPF (.NET 8) following MVVM:
- `YouTubeStreamService` manages the **variable reusable stream** (shipped 2026-08-16): `GetOrCreateReusableStreamAsync` lists `liveStreams?mine=true` and reuses the existing `cdn.isReusable` stream, creating it only on first use (`resolution=variable`, `frameRate=variable`); the stream is cached via `LayoutStore` (`SaveReusableStream`/`LoadReusableStream`, Settings table) and bound at broadcast insert (`boundStreamId`). Health (shipped 2026-08-16): `GetStreamHealthAsync(streamId)` polls `liveStreams?part=status` for `healthStatus` + `configurationIssues[]` → `StreamHealth`; banner decision in pure `StreamHealthReporter` - `YouTubeStreamService` manages the **variable reusable stream** (shipped 2026-08-16): `GetOrCreateReusableStreamAsync` lists `liveStreams?mine=true` and reuses the existing `cdn.isReusable` stream, creating it only on first use (`resolution=variable`, `frameRate=variable`); the stream is cached via `LayoutStore` (`SaveReusableStream`/`LoadReusableStream`, Settings table) and bound at broadcast insert (`boundStreamId`). Health (shipped 2026-08-16): `GetStreamHealthAsync(streamId)` polls `liveStreams?part=status` for `healthStatus` + `configurationIssues[]` → `StreamHealth`; banner decision in pure `StreamHealthReporter`
- 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) - 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 - `StreamConfig` defaults (`TargetBitrate=6000`, `Resolution="1920x1080"`) are stale — the live dropdown drives `StreamHealth.CurrentBitrate`/`FPS` instead
- **v1 task queue (2026-08-19):** 5 new tasks added for v1 feature completeness: - **v1 task queue (2026-08-19):** tasks 19-23 added for v1 feature completeness; TASK 3.18 (chat box) shipped; TASK 10 (Polar billing) ready to execute (org ID obtained):
- TASK 10: Polar billing — license key entry, offline entitlement, brand flash gating, Velopack auto-updates
- TASK 19: Scene transitions (Cut/Fade/Move/Custom) — required for professional polish - TASK 19: Scene transitions (Cut/Fade/Move/Custom) — required for professional polish
- TASK 20: Hotkeys (global keyboard shortcuts) — the single biggest UX gap - TASK 20: Hotkeys (global keyboard shortcuts) — the single biggest UX gap
- TASK 21: Media source (video file playback) — starting soon videos, BRB loops - TASK 21: Media source (video file playback) — starting soon videos, BRB loops
@@ -637,7 +638,8 @@ crooked.
- **Billing:** **Polar (polar.sh)** — open-source MoR (Apache 2.0), handles payments, subscriptions, - **Billing:** **Polar (polar.sh)** — open-source MoR (Apache 2.0), handles payments, subscriptions,
license keys, and global tax compliance. Startup Program gives Scale plan free for 12 months. license keys, and global tax compliance. Startup Program gives Scale plan free for 12 months.
Product: `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0`. Checkout: `llamacasty.com` → Polar hosted page. Product: `d105dfa1-497e-423b-8cd4-e0ee2e3abbc0`. Checkout: `llamacasty.com` → Polar hosted page.
Discounts: `LLAMAFOUNDER` (100% off, 50 uses), `LLAMA50` (50% off, 12 months). Details in `MONETIZATION.md`. 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`.
- **Support (creator's model):** in-app bug-reporting mechanism → issues into git; most queries are - **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 how-tos / feature requests / manual-skimmers. Maintenance cadence = "when I get around to it" with
emergency patches; not a 24/7 service promise. emergency patches; not a 24/7 service promise.
+1
View File
@@ -23,6 +23,7 @@
<Resource Include="Assets\llamacasty-icon.png"/> <Resource Include="Assets\llamacasty-icon.png"/>
<Resource Include="Assets\llamacasty-logo.jpg"/> <Resource Include="Assets\llamacasty-logo.jpg"/>
<Resource Include="Assets\starting-backdrop.jpg"/> <Resource Include="Assets\starting-backdrop.jpg"/>
<Resource Include="Assets\brb-backdrop.jpg"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>