Files
LlamaCasty/ai.md
T
gramps 7827d239e2 docs(commercial): one source of truth for the money — prices, entitlement, channels
The commercial plan was spread over five documents written in five different weeks,
and they contradicted each other: product.md sold the Store, decisions.md called the
Store dead then re-opened, Distribution.md (736 lines) still described Polar as a
download host, MARCOM.md quoted "no subscription" next to a paid tier, and README.md
promised "free forever". An outsider could not tell what ships.

docs/ai/commercial.md is now the only place money is decided: free = whole app at a
921,600 px / 30 fps output profile covering the recording as well as the stream; Pro =
$10/mo or $400 lifetime through Polar, key bound to the buyer's YouTube channel ID via
a claim page, 2 activations, 7–14 day lease with offline grace, fail closed, never
downgrade a running stream; one portable zip + winget primary, Steam and the Store
parked; Azure Trusted Signing (~$9.99/mo), no EV; Founding 200 promo; ~$135/yr costs;
anti-piracy posture and what is permanently rejected.

Everything else now points at it instead of restating it:
- product.md — money sections replaced with pointers; packaging rewritten to
  winget-first, Store parked; signing updated to Trusted Signing.
- decisions.md — graveyard with cause of death for free-forever, the Store ordering,
  the updater, and the 2026-10-30 reversal of the quality-ceiling rejection.
- Distribution.md — rewritten to release mechanics only (artifact, GitHub Releases,
  winget manifest, signing, checklist, takedown): 736 → 120 lines.
- TASKS.md — TASK 54 rewritten, TASK 48's route settled, TASK 10 superseded, five new
  rows (entitlement seam, output-profile gate, licence UI, system messages, packaging).
- README.md — "free forever" replaced with the real split.
- capture.md — obs-backgroundremoval is GPL-3.0 and so licence-INCOMPATIBLE since the
  proprietary EULA; the old "compatible" line was falsified by that change.
- TASKS/task-10, task-48, task-51, task-54 — superseded-banner at the top of each, so
  none of them reads as current policy.
- HANDOFF.md — rewritten: plan settled, next code unit is the entitlement seam.

MARCOM.md and MONETIZATION.md (gitignored) were corrected in place: policy pointer at
the top of each, the flash removed from every live claim, the Polar fee break-even
corrected to ~$900/mo, and the projections flagged as written against a dead model.
2026-10-31 08:32:25 -07:00

67 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LlamaCasty (repo `ytLive`) — AI guide & router
> Read [`AGENTS.md`](AGENTS.md) first: the rules and the invariants. This file is the **map** —
> what the product is, how it is built, and where each subsystem's truth lives. It carries no
> narrative and no status.
## What it is
A Windows-only WPF (.NET 8) app that live-streams to YouTube. Five fixed scenes
(Starting / Live / BRB / Chat / Ending), a pure C# software compositor over an always-1920×1080
master, a bundled-ffmpeg encoder pushing RTMP, and a WASAPI audio chain. Freemium — free is the
whole app at a 720p30 output profile, Pro buys higher output quality — under a proprietary EULA,
with no account creation: it links an existing YouTube channel. One-click go-live is the product;
OBS is the escape hatch for anything bigger.
## Build, run, test
Windows `dotnet.exe` from WSL; takes are read in **Release**. Full detail in
[`docs/ai/environment.md`](docs/ai/environment.md).
```bash
"/mnt/c/Program Files/dotnet/dotnet.exe" build "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.csproj"
"/mnt/c/Program Files/dotnet/dotnet.exe" run -c Release
"/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"
```
`./scripts/verify.sh "<files>"` is the one pre-commit gate (doc budgets, clean build at 0
warnings, tests, scope).
## Architecture
C# / WPF (.NET 8) following MVVM:
| Path | Role |
|------|------|
| `Models/` | Plain data types — Scene, Source (incl. `ClipShape`, `IsMirrored`, `VideoImageSource`), QualityOption, StreamConfig, StreamHealth, YouTubeChannel, ChatMessage, **Socials (`SocialService` enum + `SocialEntry`/`SocialsConfig` + `SocialServiceIcons`) — the social bar** |
| `ViewModels/` | MainViewModel — `public partial class`, one file per functional area (Scenes, Background, Webcam, Audio, Trax, Socials, Streaming, Chat, Overlays, Account, License, Recording — split complete, see `ViewModels/index.md`); **Chat.cs is a thin delegating facade over `Services/ChatOverlayLayer.cs` (Commit G, first true decomposition), and now also over `Services/AlertOverlayLayer.cs` (TASK 43 — the native alert box, same true-component pattern)**; GoLiveViewModel, ReuseImageViewModel, CameraPickerViewModel, **SocialsDialogViewModel** |
| `Services/` | YouTube OAuth2, stream/broadcast management, live chat polling, LayoutStore (SQLite), **SocialValidator (`ISocialValidator` seam + `HttpSocialValidator` default)**, **webcam: `VideoFrame` seam + `CameraDeviceInfo`/`ICameraEnumerator`/`ICameraFrameSource` interfaces + `MediaCaptureCameraEnumerator`/`MediaCaptureFrameSource` (WinRT) + `CameraManager`**, **screen capture: `IFullScreenDetector`/`Win32FullScreenDetector` + `IScreenCaptureSource`/`ScreenCaptureFrameSource` (WinRT GraphicsCapture) + `ScreenCaptureManager` + `ScreenCaptureSourceFactory` + `Direct3D11Helper`/`CaptureInterop` (COM bridges)**, **media source: `IMediaFrameSource` + `MediaVideoSource` (spawns ffmpeg `rawvideo` BGRA decode) + `MediaVideoSourceManager` (refcount-by-path session owner) + pure `RawVideoFrameReader` + `IDecodeProcess`/`FfmpegDecodeProcess` process seam (binary-stdout mirror of `IEncoderProcess`; see [`TASKS/task-21-media-source.md`](TASKS/task-21-media-source.md))**, **compositor: `SceneCompositor` + `CompositorOptions` + pure `StretchMath` + `StaticPixelCache` (see [`docs/ai/frame-pipeline.md`](docs/ai/frame-pipeline.md) → "Scene compositor")**, **alerts: `ChatOverlayLayer` + `AlertOverlayLayer`/`AlertRenderer` (the native celebration-zone overlay, TASK 43 — see [`docs/ai/overlays.md`](docs/ai/overlays.md))**, **audio: `IAudioSource` seam + `WasapiLoopbackAudioSource`/`WasapiMicAudioSource` (NAudio WASAPI) + `AudioMixer` + pure `AudioLevelMeter`/`WaveToFloat`/`VoiceFilterChain`/`LowShelfFilter`/`HighShelfFilter`/`NoiseGate`/`Compressor`/`AutoDucker`/`AudioRingBuffer`/`TinyResampler`/`AudioSyncDelay` + `MusicPlayer` + `ITraxPlayer` (TRAX toggle seam — FakePlayer in tests; the dot is green/red/gray and the error scrolls terse in the desktop-audio bar; MusicVolume fixed 0.5) + `IAudioPipeWriter`/`NamedPipeAudioWriter` (see [`docs/ai/output.md`](docs/ai/output.md) → "Live audio capture")**, **encoder: `IFfmpegEncoder`/`FfmpegEncoder` + `IEncoderProcess`/`FfmpegEncoderProcess` + `IFfmpegLocator`/`FfmpegLocator` + pure `FfmpegArgs`/`FfmpegProgressParser`/`FfmpegEncoderPicker` + the `FramePump` frame producer (see [`docs/ai/output.md`](docs/ai/output.md) → "Live encoder" + [`docs/ai/frame-pipeline.md`](docs/ai/frame-pipeline.md) → "Live frame pipeline")**, **notifications: `INotificationService` seam (`AppNotificationSeverity` Info/Success/Warning/Error) + `NotificationService` (Notification.Wpf toasts, see "Toast notifications")** |
| `Helpers/` | ViewModelBase (INotifyPropertyChanged), RelayCommand, ImageCache, AppLog (file logger), FocusPreservingListBox, OAuthCredentials, **TokenStore (DPAPI session persistence)**, **BuildStamp (wordmark release counter `#N`, incremented by `GenerateBuildStamp` from the local `BuildCounter.txt`; per-build GUID/time are logged to startup.log)**, visibility converters |
| `Themes/` | `Controls.xaml` — the single dark-theme source, merged once in `App.xaml` (see `Themes/index.md`) |
| `MainWindow.xaml` | Dark theme; top bar + health banner; work area has a fixed 360px left column and preview column, top-left readouts/resolution and scene strip above preview, lower left panel + preview; bottom bar is an empty spacer |
## Where the truth lives
| Subsystem | File | Read when |
|---|---|---|
| Capture: backdrop, webcam, background effects, vertical tier | [`docs/ai/capture.md`](docs/ai/capture.md) | touching any frame source, the Background row, camera acquisition, or the 9:16 geometry |
| Compositor, render budget, frame pump | [`docs/ai/frame-pipeline.md`](docs/ai/frame-pipeline.md) | changing the render loop, per-frame cost, pacing, backpressure, or dropped/juddering frames |
| ffmpeg, encoder, recording, audio chain | [`docs/ai/output.md`](docs/ai/output.md) | ffmpeg args, REC/ON-AIR, the audio mix, loudness or sync |
| Social bar, alerts, chat overlays | [`docs/ai/overlays.md`](docs/ai/overlays.md) | anything drawn on top of the output |
| Go-live, broadcasts, health, chat API | [`docs/ai/youtube-api.md`](docs/ai/youtube-api.md) | go-live, broadcast lifecycle, health polling, streaming close-out |
| Control surface, theming, transitions | [`docs/ai/ui-surface.md`](docs/ai/ui-surface.md) | anything the creator looks at |
| Brand, packaging, legal posture | [`docs/ai/product.md`](docs/ai/product.md) | branding, naming, packaging behaviour, legal obligations |
| Prices, entitlement, channels, signing, promo | [`docs/ai/commercial.md`](docs/ai/commercial.md) | anything about money: pricing, licence keys, output cap, winget/Steam/Store, costs |
| Hosts, build commands, test map | [`docs/ai/environment.md`](docs/ai/environment.md) | building, running, adding a test |
| Routes for every subsystem | [`docs/ai/index.md`](docs/ai/index.md) | you want the full table with a "read when" per file |
Lookup, not reading: [`MyMistakes.md`](MyMistakes.md) (grep first on any "did this before?" wall) ·
[`TASKS.md`](TASKS.md) (the queue) · `TASKS/` (per-task detail and API research) ·
`<dir>/index.md` (per-directory map).
## Current state
[`HANDOFF.md`](HANDOFF.md) — branch, what's in flight, the next action, live landmines. Do not
restate it here.