{"owner":"Live-Charts","repo":"LiveCharts2","hasSkills":true,"totalSkillsCount":6,"totalTokensCount":24379,"categories":["copilot-instructions","claude-rule","root-instruction","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":[".github/copilot-instructions.md","CLAUDE.md","llms.txt",".claude/skills/render-chart/SKILL.md",".claude/skills/repro-and-fix/SKILL.md","llms-full.txt"],"skills":{".github/copilot-instructions.md":"# LiveCharts2 Copilot Instructions\n\nThis document helps coding agents work efficiently with the LiveCharts2 repository.\n\n## Repository Overview\n\nLiveCharts2 is a flexible, cross-platform charting library for .NET. It follows a layered architecture where:\n- **Core library** (`LiveChartsCore`) is platform-agnostic and handles all chart mathematics\n- **SkiaSharp backend** renders the charts using SkiaSharp\n- **Platform-specific views** provide UI controls for various frameworks (WPF, Avalonia, MAUI, Blazor, etc.)\n\n## Repository Structure\n\n```\nLiveCharts2/\n├── src/\n│   ├── LiveChartsCore/                    # Platform-agnostic core library\n│   │   ├── Kernel/                        # Core charting engine\n│   │   ├── Drawing/                       # Drawing abstractions\n│   │   ├── Motion/                        # Animation system\n│   │   ├── Measure/                       # Chart measurement logic\n│   │   └── [Series types]/                # Line, Bar, Pie, Scatter, etc.\n│   ├── skiasharp/                         # SkiaSharp rendering implementations\n│   │   ├── LiveChartsCore.SkiaSharp/      # Core SkiaSharp provider\n│   │   ├── LiveChartsCore.SkiaSharp.WPF/\n│   │   ├── LiveChartsCore.SkiaSharp.Avalonia/\n│   │   ├── LiveChartsCore.SkiaSharpView.Maui/\n│   │   ├── LiveChartsCore.SkiaSharpView.Blazor/\n│   │   └── [other platforms]/\n│   └── _Shared.Native/                    # Native platform interop\n├── samples/                               # Sample applications\n│   ├── ViewModelsSamples/                 # Shared ViewModels for all samples\n│   │   └── Index.cs                       # List of all sample paths\n│   ├── WPFSample/\n│   ├── AvaloniaSample/\n│   ├── MauiSample/\n│   ├── VorticeSample/                     # DirectX sample (core without SkiaSharp)\n│   └── [other platforms]/\n├── tests/\n│   ├── CoreTests/                         # Core unit tests using MSTest\n│   │   ├── ChartTests/                    # High-level chart tests\n│   │   ├── SeriesTests/                   # Series-specific tests\n│   │   ├── LayoutTests/                   # Layout tests\n│   │   ├── CoreObjectsTests/              # Core objects tests\n│   │   └── OtherTests/                    # Axes, events, etc.\n│   ├── SnapshotTests/                     # Snapshot/image comparison tests (net10.0)\n│   ├── UITests/                           # UI testing orchestrator\n│   │   └── Program.cs                     # Factos-based multi-platform test runner\n│   └── SharedUITests/                     # Shared UI tests (referenced by sample apps)\n│       ├── CartesianChartTests.cs\n│       ├── PieChartTests.cs\n│       ├── PolarChartTests.cs\n│       └── MapChartTests.cs\n├── docs/                                  # Documentation (Scriban templates)\n│   ├── samples/                           # Sample documentation templates\n│   ├── shared/                            # Reusable template fragments\n│   ├── cartesianChart/                    # Cartesian chart docs\n│   ├── piechart/                          # Pie chart docs\n│   └── polarchart/                        # Polar chart docs\n└── generators/                            # Code generators\n```\n\n## Key Architecture Concepts\n\n### 1. Layered Design\n- **LiveChartsCore**: Pure .NET, no UI dependencies, handles all calculations\n- **SkiaSharp Provider**: Implements `IDrawingProvider` to render using SkiaSharp\n- **Platform Views**: WPF/Avalonia/MAUI/etc. specific controls that host the renderer\n\n### 2. Multi-Platform Targeting\n\nCore projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) target:\n- `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **No mobile workloads required** to build the core library\n\n**Platform-specific view projects** (WPF, Avalonia, MAUI, etc.) have their own target framework requirements based on the platform.\n\n### 3. Sample Structure\n- **ViewModelsSamples**: Contains shared ViewModels used across all UI frameworks\n- **Index.cs**: Defines available samples as string paths (e.g., \"Lines/Basic\", \"Pies/Doughnut\")\n- Each platform sample project (WPF, Avalonia, etc.) references ViewModelsSamples and creates platform-specific views\n\n### 4. VorticeSample\nA special sample demonstrating how to use LiveChartsCore without SkiaSharp, using DirectX instead. This shows the core library is truly rendering-agnostic.\n\n## Building the Repository\n\n### Prerequisites\n- .NET SDK (see `global.json` for minimum version)\n- No workloads required for core projects\n- Platform-specific projects (MAUI, UNO, Avalonia Browser) require relevant workloads:\n  ```bash\n  dotnet workload install maui\n  dotnet workload install wasm-tools\n  ```\n\n### Build Methods\n\n#### Quick Build - Core Projects\n```bash\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n```\n\n#### Quick Build - Platform Views\n```bash\n# Build specific platform views (recommended for development)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n```\n\n#### Full Build (Windows)\n```bash\n# Build platform-specific projects individually\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj\n# Or use platform-specific solution files (see below)\n```\n\n#### Build with Solution Files\n```bash\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n```\n\n### Common Build Issues and Workarounds\n\n#### Issue: Missing workload errors (NETSDK1147)\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\n```\n\n**Context**: This error occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require workloads.\n\n**Workaround Options:**\n1. Install the required workload: `dotnet workload install maui`\n2. Build only the platform you need (e.g., WPF or Avalonia desktop on Windows)\n3. Use platform-specific solution files that don't include all targets\n\n#### Issue: SkiaSharp version conflicts\nThe project supports multiple SkiaSharp versions:\n- `MinSkiaSharpVersion`: 2.88.9 (minimum supported)\n- `LatestSkiaSharpVersion`: 3.119.0 (default for GPU support)\n\nDefined in `Directory.Build.props`.\n\n#### Issue: Multi-targeting complexity\nWhen building fails for specific targets, you can:\n1. Use `-f` to target specific framework: `dotnet build -f net8.0`\n2. Edit `TargetFrameworks` in .csproj to focus on needed platforms\n\n## Testing\n\n### Unit Tests (Core Library)\n\n**Location**: `tests/CoreTests/`\n\n**Framework**: MSTest with coverlet for code coverage\n\n**Run Tests:**\n```bash\ndotnet test tests/CoreTests/\n\n# Run for specific framework\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run with coverage\ndotnet test tests/CoreTests/ --collect:\"XPlat Code Coverage\"\n```\n\n**Test Structure:**\n- `ChartTests/`: High-level chart functionality\n- `SeriesTests/`: Tests for Line, Bar, Pie, Scatter, Heat, etc.\n- `LayoutTests/`: Stack and table layouts\n- `CoreObjectsTests/`: Transitions, colors, labels\n- `OtherTests/`: Axes, events, data providers, visual elements\n- `MockedObjects/`: Test helpers and mocks\n- `TestsInitializer.cs`: MSTest assembly initialization\n\n**Important**: Tests use `CoreMotionCanvas.IsTesting = true` to disable animations during testing.\n\n### Snapshot Tests\n\n**Location**: `tests/SnapshotTests/`\n\n**Framework**: MSTest, targets `net10.0`\n\nSnapshot tests render charts to images and compare them against stored reference snapshots. They are run in CI on Windows.\n\n**Run Tests:**\n```bash\ndotnet test tests/SnapshotTests/\n```\n\n### UI Testing\n\n**Location**: `tests/UITests/` (orchestrator) and `tests/SharedUITests/` (shared tests)\n\n**Framework**: [Factos](https://github.com/beto-rodriguez/Factos) - A multi-platform UI testing framework\n\n**How it works:**\n1. Shared UI tests are defined in `tests/SharedUITests/` (shared project)\n2. Each sample application references `SharedUITests` \n3. The `tests/UITests/Program.cs` orchestrator:\n   - Starts various sample applications (Avalonia, WPF, MAUI, Blazor, etc.)\n   - Connects to them via Factos\n   - Runs the shared UI tests against each platform\n4. Tests ensure charts render correctly across all supported UI frameworks\n\n**Test Coverage:**\n- `CartesianChartTests.cs`: Cartesian chart rendering and behavior\n- `PieChartTests.cs`: Pie/Doughnut chart tests\n- `PolarChartTests.cs`: Polar chart tests  \n- `MapChartTests.cs`: Map chart tests\n- `AvaloniaTests.cs`: Avalonia-specific tests\n\n**Running UI Tests:**\n```bash\n# Run UI tests (requires sample apps to be built)\ndotnet run --project tests/UITests/\n\n# Run against specific platform (see Program.cs for options)\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\ndotnet run --project tests/UITests/ -- --select maui --test-env \"tf=net10.0-windows10.0.19041.0\"\n```\n\n**Important Notes:**\n- UI testing requires the Factos package\n- Each platform may need specific prerequisites (emulators for mobile, browsers for web)\n- In Debug mode, tests use project references; in Release mode, they use NuGet packages\n- The orchestrator supports testing against multiple target frameworks\n- Mobile platforms (Android, iOS) require running emulators\n\n**Build Configuration for UI Tests:**\nUI test configuration is managed through MSBuild properties. When `UITesting=true` is set, samples include the shared UI test project.\n\n## Running Samples\n\n### Sample Applications\nEach platform has its own sample application that references `ViewModelsSamples`:\n\n```bash\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\n### Adding New Samples\n1. Add ViewModel class in `samples/ViewModelsSamples/[Category]/[Name].cs`\n2. Add path to `samples/ViewModelsSamples/Index.cs`\n3. Create platform-specific view files in each sample project (WPF, Avalonia, etc.)\n\n### Sample Platforms Reference\n\nThe following platforms each need a view for every sample. **ConsoleSample** and **VorticeSample** are excluded — they don't follow this pattern.\n\n| Platform | Root path | View file(s) | Base class | LVC namespace (xmlns:lvc) |\n|---|---|---|---|---|\n| **Avalonia** | `samples/AvaloniaSample/[Category]/[Name]/` | `View.axaml` + `View.axaml.cs` | `UserControl` | `using:LiveChartsCore.SkiaSharpView.Avalonia` |\n| **WPF** | `samples/WPFSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` | `clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF` |\n| **MAUI** | `samples/MauiSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `ContentPage` | `clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui` |\n| **WinUI** | `samples/WinUISample/WinUISample/Samples/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` (`sealed partial`) | `using:LiveChartsCore.SkiaSharpView.WinUI` |\n| **WinForms** | `samples/WinFormsSample/[Category]/[Name]/` | `View.cs` + `View.Designer.cs` + `View.resx` | `UserControl` (`partial`) | N/A — code-only |\n| **Blazor** | `samples/BlazorSample/Pages/[Category]/[Name]/` | `View.razor` | N/A — Razor component | `@using LiveChartsCore.SkiaSharpView.Blazor` |\n| **EtoForms** | `samples/EtoFormsSample/[Category]/[Name]/` | `View.cs` | `Panel` (non-partial) | N/A — code-only |\n| **UnoPlatform** | *(no separate files)* | Reuses `WinUISample` views via reflection | — | — |\n\n**Key facts for each platform:**\n\n- **All XAML platforms (Avalonia, WPF, MAUI, WinUI)** use `Activator.CreateInstance` with the pattern `{Platform}.{Category}.{Name}.View` to load views — so the **C# namespace must exactly match** `{PlatformPrefix}.{Category}.{Name}` and the class must be named `View`.\n- **WinForms** and **EtoForms** use the same reflection pattern. The view class must be `partial class View : UserControl` (WinForms) or `class View : Panel` (EtoForms).\n- **Blazor** uses Razor's `@page \"/{Category}/{Name}\"` directive for routing. The nav menu reads `ViewModelsSamples.Index.Samples` automatically.\n- **UnoPlatform** (`samples/UnoPlatformSample/`) loads views from the `WinUISample` assembly — no separate files are needed.\n\n**XAML DataContext / BindingContext patterns:**\n\n```xml\n<!-- Avalonia (View.axaml) -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\"\n             x:DataType=\"vms:ViewModel\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- WPF (View.xaml) -->\n<UserControl xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- MAUI (View.xaml) — ContentPage + XamlCompilation attribute on code-behind -->\n<ContentPage xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\"\n             x:DataType=\"vms:ViewModel\">\n    <ContentPage.BindingContext><vms:ViewModel/></ContentPage.BindingContext>\n</ContentPage>\n\n<!-- WinUI (View.xaml) — sealed partial class -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.WinUI\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n```\n\n**Code-only platforms (WinForms / EtoForms)** typically instantiate the ViewModel directly or inline the data:\n\n```csharp\n// WinForms — partial class View : UserControl\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nchart.Location = new System.Drawing.Point(0, 0);\nchart.Size = new System.Drawing.Size(50, 50);\nchart.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;\nControls.Add(chart);\n\n// EtoForms — class View : Panel (non-partial, no Designer file)\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nContent = new DynamicLayout(chart);\n```\n\n**WinForms `View.Designer.cs`** is always a minimal boilerplate — copy from any existing sample, just update the namespace.\n\n**UI-testing accessor** — most XAML views expose a `Chart` property under `#if UI_TESTING` for the Factos test runner:\n\n```csharp\n// XAML platforms (WPF, Avalonia, MAUI, WinUI)\n#if UI_TESTING\n    public SomeChartType Chart => chartNamedInXaml;\n#endif\n\n// EtoForms / WinForms\npublic SomeChartType Chart;  // public field, always present\n```\n\n**Blazor** exposes the chart via `@ref`:\n```razor\n<CartesianChart @ref=\"Chart\" .../>\n@code { public CartesianChart Chart; }\n```\n\n## Code Style and Conventions\n\n### Editor Config\nThe repository uses `.editorconfig` based on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with exceptions.\n\n**Key Style Rules:**\n- **Indentation**: 4 spaces\n- **Line endings**: LF, insert final newline\n- **Braces**: New line before open brace (Allman style)\n- **var usage**: Use `var` freely (explicitly allowed)\n- **Single-line if**: Allowed and preferred when line is short\n- **Naming**:\n  - Private/internal fields: `_camelCase`\n  - Static private fields: `s_camelCase`\n  - Constants: `PascalCase`\n- **Using directives**: Outside namespace\n\n### File Naming\n**Critical for auto-generated documentation:**\n- File names MUST match the class name exactly\n- `public class Hello` → `Hello.cs`\n- `public class Hello<T>` → `Hello.cs` (ignore generics)\n- Generic and non-generic with same name → same file (only if inheritance relationship)\n\n### Important Constants\nDefined in `Directory.Build.props`:\n- `LiveChartsVersion`: Current version (2.0.0-rc6.1)\n- `MinSkiaSharpVersion`: 2.88.9\n- `LatestSkiaSharpVersion`: 3.119.0\n- `LangVersion`: 14.0 (C# 14)\n\n## Build Configuration Properties\n\n### Rendering Settings\nRendering settings are configured via MSBuild properties:\n- `GPU`: Enable/disable GPU acceleration\n- `VSYNC`: Enable/disable vertical sync\n- `FPS`: Frame rate (10, 20, 30, 45, 60, 75, 90, 120)\n- `Diagnose`: Enable diagnostic mode\n\nThese create conditional compilation symbols for testing different rendering modes.\n\n### Development Flags\nIn `Directory.Build.props`:\n- `UseNuGetForSamples`: Use NuGet packages vs project references (default: false)\n- `UseNuGetForGenerator`: Use NuGet generator package (default: true)\n\n## CI/CD\n\n### GitHub Actions Workflows\n\n#### 1. Main CI (`livecharts.yml`)\n- Triggers: Pull requests\n- Runs on: `windows-2025` (pack/test), `ubuntu-24.04` (Linux/browser), `macos-26` (Mac/iOS)\n- Steps:\n  1. **Pack**: Builds NuGet packages for all platform libraries (core, skiasharp, WPF, Avalonia, MAUI, Blazor, WinUI, UNO, WinForms, Eto)\n  2. **test-core**: Runs `CoreTests` on `net8.0` and `net462`\n  3. **test-snapshot**: Runs `SnapshotTests`\n  4. **test-windows/linux/mac/browser/android/ios**: Runs Factos UI tests for each platform\n- On tag pushes (after tests pass): publishes packages to NuGet.org\n\n#### 2. Publish (`publish.yml`)\n- Handles NuGet package publishing\n\n**Note**: The CI uses NuGet packages (not project references) when running UI tests in Release mode.\n\n## Common Development Workflows\n\n### Adding a New Series Type\n1. Create series class in `src/LiveChartsCore/[SeriesType]/`\n2. Implement series interfaces (`ISeries`, etc.)\n3. Create SkiaSharp drawable in `src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/`\n4. Add tests in `tests/CoreTests/SeriesTests/`\n5. Create sample ViewModel in `samples/ViewModelsSamples/`\n6. Update `samples/ViewModelsSamples/Index.cs`\n\n### Adding Platform Support\n1. Create new project in `src/skiasharp/LiveChartsCore.SkiaSharpView.[Platform]/`\n2. Reference `LiveChartsCore.SkiaSharp` project\n3. Create platform-specific control classes\n4. Add shared code to `_Shared/` if applicable\n5. Create sample application in `samples/[Platform]Sample/`\n6. Add platform-specific solution file\n\n### Updating Documentation\n\n**Important**: Documentation files in the `docs/` folder are **Scriban templates**, not final markdown files.\n\n**How it works:**\n1. Template files are compiled by an external (non-open-source) repository\n2. Templates use [Scriban](https://github.com/scriban/scriban) - a fast, powerful, and lightweight text templating language\n3. Scriban supports custom functions and expressions embedded in the markdown\n\n**Common Scriban expressions you'll find:**\n\n**File inclusion** - Renders content from source files:\n```\n{{~ render \"~/../samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs\" ~}}\n{{~ render \"~/../samples/MauiSample/MauiProgram.cs\" ~}}\n{{~ render \"~/../samples/{samples_folder}/Events/Cartesian{view_extension}\" ~}}\n```\n\n**Conditionals** - Platform-specific content:\n```\n{{~ if xaml ~}}\n  Content for XAML platforms (WPF, Avalonia, UNO, WinUI, MAUI)\n{{~ end ~}}\n\n{{~ if winforms ~}}\n  Content specific to WinForms\n{{~ end ~}}\n```\n\n**Variables** - Dynamic content:\n```\n{{ website_url }}/docs/{{ platform }}/{{ version }}/About\n{{ assets_url }}/docs/{{ unique_name }}/result.gif\n{{ name | to_title_case }}\n{{ edit_source | replace_local_to_server }}\n```\n\n**Loops** - Iterate over collections:\n```\n{{~ for r in related_to ~}}\n  <a href=\"{{ compile this r.url }}\">{{ r.name }}</a>\n{{~ end ~}}\n```\n\n**Template structure:**\n- `docs/samples/[category]/[name]/template.md` - Sample documentation templates\n- `docs/shared/*.md` - Reusable template fragments included via `{{ render \"~/shared/...\" }}`\n- `docs/piechart/`, `docs/cartesianChart/`, etc. - Feature documentation with templates\n\n**When editing docs:**\n- Always edit the `.md` files as Scriban templates\n- Test template syntax (though final compilation happens externally)\n- Use `{{~ ~}}` syntax to strip whitespace around expressions\n- File paths in `render` are relative to the template location (use `~/../` for repo root)\n\n## Important Notes for Coding Agents\n\n### Do's\n- ✅ Use project references during development (not NuGet packages)\n- ✅ Follow the exact file naming convention (critical for docs)\n- ✅ Run tests after changes to core or series logic\n- ✅ Use platform-specific solution files for focused development\n- ✅ Consult `CONTRIBUTING.md` for detailed style guide\n- ✅ Use shared code in `_Shared/` folders when adding cross-platform features\n\n### Don'ts\n- ❌ Don't break multi-platform support when modifying core projects\n- ❌ Don't add platform-specific code to `LiveChartsCore` (keep it agnostic)\n- ❌ Don't ignore `.editorconfig` warnings\n- ❌ Don't remove or modify working tests without good reason\n- ❌ Don't add new dependencies without checking compatibility across all target frameworks\n\n### Special Considerations\n- The library supports .NET Framework 4.6.2 - maintain compatibility\n- SkiaSharp is abstracted - core library should work with other rendering engines\n- Animation system (`Motion/`) is critical - changes require extensive testing\n- Multi-threading: Chart updates can come from any thread; proper synchronization is essential\n\n## Quick Reference Commands\n\n```bash\n# === Building ===\n# Build core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Build platform-specific projects\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# === Install Workloads (for platform-specific projects) ===\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n\n# Check installed workloads\ndotnet workload list\n\n# === Testing ===\n# Run core unit tests\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run snapshot tests\ndotnet test tests/SnapshotTests/\n\n# Run UI tests (requires sample apps to build)\ndotnet run --project tests/UITests/\n\n# Run UI tests for specific platform\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n\n# === Running Samples ===\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n\n# === Troubleshooting ===\n# Clean build artifacts\ndotnet clean\nfind . -type d -name \"bin\" -o -name \"obj\" | xargs rm -rf\n\n# Restore packages\ndotnet restore\n\n# Check for workload issues\ndotnet workload restore --skip-sign-check\n```\n\n## Documented Errors and Workarounds\n\nThis section documents actual errors encountered when working with this repository and their solutions.\n\n### Error 1: NETSDK1147 - Missing Workloads\n\n**Error Message:**\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\nTo install these workloads, run the following command: dotnet workload restore\n```\n\n**Context**: This occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require any workloads.\n\n**Workarounds:**\n\n**Option 1: Install Required Workloads**\n```bash\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n```\n\n**Option 2: Build Platform-Specific Projects that don't need workloads**\n```bash\n# Build only WPF (Windows only)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\n\n# Build only Avalonia desktop (cross-platform)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\n```\n\n### Error 2: Visual Studio Component Required\n\n**Error Message:**\n```\nUnhandled exception: The imported file \"$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v$(VisualStudioVersion)/CodeSharing/Microsoft.CodeSharing.Common.Default.props\" does not exist and appears to be part of a Visual Studio component.\n```\n\n**Context**: Appears when running `dotnet workload restore` on non-Windows systems or when Visual Studio is not installed.\n\n**Why it happens**: The `src/skiasharp/_Shared.WinUI/_Shared.WinUI.shproj` shared project requires Visual Studio components that are Windows-specific.\n\n**Workaround**: This error can be ignored if you're not building WinUI projects. The workload installation succeeds despite this error. If you need to build WinUI:\n- Use Windows with Visual Studio 2022 installed\n- Use `msbuild` instead of `dotnet build` for WinUI projects\n\n### Error 3: Ambiguous Argument with Git\n\n**Error Message:**\n```\nfatal: ambiguous argument 'origin/branch-name': unknown revision or path not in the working tree.\n```\n\n**Context**: After fetching a branch with `git fetch origin branch-name`, trying to reference it as `origin/branch-name`.\n\n**Why it happens**: Git fetch stores the ref as `FETCH_HEAD`, not as a trackable remote branch.\n\n**Solution**: Use `FETCH_HEAD` or create a local tracking branch:\n```bash\n# Option 1: Use FETCH_HEAD directly\ngit log FETCH_HEAD\n\n# Option 2: Create tracking branch\ngit fetch origin main\ngit checkout -b main --track origin/main\n\n# Option 3: Fetch with branch creation\ngit fetch origin main:main\n```\n\n### Error 4: Package Not Found During Build\n\n**Context**: Sample applications may fail to build if NuGet packages are not found.\n\n**Why it happens**: `UseNuGetForSamples` flag in `Directory.Build.props` controls whether samples use project references or NuGet packages.\n\n**Solution**: Ensure you're using project references during development:\n```xml\n<!-- In Directory.Build.props -->\n<UseNuGetForSamples>false</UseNuGetForSamples>\n```\n\nOr restore NuGet packages if building from packages:\n```bash\ndotnet restore\n```\n\n### Error 5: Strong Name Assembly Conflicts\n\n**Context**: When building for .NET Framework 4.6.2, you may encounter assembly version conflicts.\n\n**Why it happens**: .NET Framework uses strong-named assemblies, and SkiaSharp has different versioning.\n\n**Referenced Issue**: https://github.com/mono/SkiaSharp/issues/3153\n\n**Solution**: The project is configured to handle this, but if you encounter issues:\n1. Clean the solution: `dotnet clean`\n2. Delete `bin` and `obj` folders\n3. Restore and rebuild: `dotnet restore && dotnet build`\n\n### Error 6: Test Build Failures on CI\n\n**Context**: UI tests may fail with target framework mismatches in CI.\n\n**Solution**: The UI test infrastructure uses special MSBuild properties:\n- `TestBuildTargetFramework`: Override target framework for test builds\n- `IsTestBuild`: Flag to indicate test build\n- `UITesting`: Flag to include shared UI tests\n\nExample from `tests/UITests/Program.cs`:\n```csharp\nMSBuildArg tf_n10w = new(\"TestBuildTargetFramework\", \"net10.0-windows\");\nMSBuildArg isTest = new(\"IsTestBuild\", \"true\");\n```\n\n## Troubleshooting\n\n### Problem: Can't build platform-specific projects - workload errors\n**Solution**: Install the required workload for the platform you're targeting (e.g., `dotnet workload install maui`). Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) build without any workloads.\n\n### Problem: SkiaSharp errors\n**Solution**: Check SkiaSharp version in `Directory.Build.props`, ensure NuGet restore succeeded\n\n### Problem: Tests fail with animation issues\n**Solution**: Verify `CoreMotionCanvas.IsTesting = true` in test initialization\n\n### Problem: Sample won't run\n**Solution**: Ensure platform-specific dependencies are installed (e.g., .NET Desktop Runtime for WPF)\n\n### Problem: Generator errors\n**Solution**: Check `UseNuGetForGenerator` setting and ensure LiveChartsGenerators package/project is available\n\n## Issue Reproduction & Fix Workflow\n\nWhen picking up a GitHub issue (reproduce → diagnose → fix → regression test → PR),\nfollow the canonical workflow at [`.claude/skills/repro-and-fix/SKILL.md`](../.claude/skills/repro-and-fix/SKILL.md).\nThat doc is the single source of truth for both Claude Code and Copilot Coding Agent —\nkeep edits there, not duplicated here.\n\nQuick reference for the dev-loop hooks the workflow relies on:\n\n- **`LVC_SAMPLE=<sample-path>`** — XAML samples (Avalonia / WPF / WinUI / MAUI / Uno) auto-navigate to the named sample on launch, e.g. `LVC_SAMPLE=VisualTest/Issue1986Repro`. Skips manual UI navigation for repros.\n- **`LVC_SCREENSHOT=<png-path>`** — Avalonia / WPF / WinUI samples render the main window to PNG via `RenderTargetBitmap` shortly after activation and exit. Captures scale to physical pixels on HiDPI.\n- **`LVC_SCREENSHOT_DELAY_MS=<ms>`** — overrides the 3 s default settle delay before the in-app screenshot is taken (use on slower CI hosts).\n- **`.claude/scripts/capture-window.{ps1,-macos.sh,-linux.sh}`** — per-OS PrintWindow / `screencapture` / `grim` fallbacks for platforms without an in-app capture path (MAUI, Uno).\n\nRepro views live under `samples/AvaloniaSample/VisualTest/Issue<N>Repro/` (or\nthe equivalent under whichever platform sample fits the bug). Their code-behind\nexposes helpers (e.g. `FindTemplatedGaugeSeries()`) that Factos UI tests call\ndirectly. Factos and `LVC_SAMPLE` navigate by path and don't need the repro\nregistered in `samples/ViewModelsSamples/Index.cs` — **do not commit changes\nto that file for a repro view.** It's shared across every platform sample,\nso a single-platform repro entry will crash the load on the other platforms.\n\n## Resources\n\n- **Main Documentation**: https://livecharts.dev\n- **Contributing Guide**: `CONTRIBUTING.md`\n- **Repository**: https://github.com/Live-Charts/LiveCharts2\n- **Code of Conduct**: `CODE_OF_CONDUCT.md`\n- **License**: MIT (see `LICENSE`)\n\n## Version Information\n\n- **Current Version**: 2.0.0-rc6.1 (Release Candidate)\n- **C# Language Version**: 14.0\n- **SkiaSharp**: 2.88.9 (min) to 3.119.0 (latest)\n- **Target Frameworks**: `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows` (core); plus platform-specific targets for view projects\n","CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nLiveCharts2 is a cross-platform .NET charting library with a layered architecture:\n- **`src/LiveChartsCore/`** — Platform-agnostic core (math, series, axes, animation). No UI dependencies. Targets `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp/`** — SkiaSharp rendering backend implementing the core drawing abstractions.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp.{Platform}/`** — Platform-specific view controls (WPF, Avalonia, MAUI, Blazor, WinForms, WinUI, Eto, UNO).\n- **`generators/LiveChartsGenerators/`** — Roslyn source generator for boilerplate reduction.\n\n## Build Commands\n\n```bash\n# Core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Platform-specific (examples)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n\n# Target a specific framework when multi-targeting causes issues\ndotnet build -f net8.0\n```\n\nMAUI/WASM projects require workloads: `dotnet workload install maui --skip-sign-check` / `dotnet workload install wasm-tools --skip-sign-check`. Core and desktop projects (WPF, Avalonia, WinForms) do not.\n\n## Testing\n\n```bash\n# Unit tests (MSTest) — primary test suite\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Snapshot tests (image comparison, net10.0 only)\ndotnet test tests/SnapshotTests/\n\n# UI tests via Factos (requires sample apps built)\ndotnet run --project tests/UITests/\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n```\n\nTests use `CoreMotionCanvas.IsTesting = true` to disable animations. UI tests are defined in `tests/SharedUITests/` (shared project) and run against each platform via the Factos orchestrator in `tests/UITests/`.\n\n## Running Samples\n\n```bash\ndotnet run --project samples/WPFSample/WPFSample.csproj\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\nSample ViewModels live in `samples/ViewModelsSamples/` and are shared across all platform samples. Each platform sample creates its own views. `samples/ViewModelsSamples/Index.cs` lists all available sample paths.\n\n## Architecture Details\n\n**Rendering pipeline**: Data → Core series engine (measurement, layout) → SkiaSharp drawables → Platform-native surface. The core is rendering-agnostic — `samples/VorticeSample/` demonstrates using DirectX instead of SkiaSharp.\n\n**Shared projects**: `src/skiasharp/_Shared/`, `_Shared.Xaml/`, `_Shared.WinUI/` contain code shared across platform views via MSBuild linked files (configured in `build/*.Build.props`).\n\n**Code generation**: `LiveChartsGenerators` is a Roslyn analyzer/generator. Controlled by `UseNuGetForGenerator` in `Directory.Build.props` (default: `true` = NuGet package).\n\n**Key build properties** (`Directory.Build.props`):\n- `UseNuGetForSamples`: `false` during development (project references), `true` for CI/release\n- `UITesting`: set to `true` to include shared UI tests in sample projects\n- `GPU`, `VSYNC`, `Diagnose`: rendering mode overrides for testing\n\n## Code Style\n\nBased on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with these exceptions (enforced via `.editorconfig`):\n- `var` is freely used everywhere (not restricted to explicit right-hand types)\n- Single-line `if` without braces is preferred when the line is short; break long lines rather than adding braces\n- Private fields: `_camelCase`, static private: `s_camelCase`, constants: `PascalCase`\n- 4-space indentation, Allman braces, LF line endings\n\n**File naming is critical**: file names must match the class name exactly (`Hello<T>` → `Hello.cs`). Generic and non-generic with the same name go in the same file (only when related by inheritance). This is required for automatic documentation generation.\n\n## Key Constraints\n\n- **Never add platform-specific code to `LiveChartsCore`** — it must remain platform-agnostic\n- **.NET Framework 4.6.2 compatibility must be maintained** (strong-named assemblies, `LiveCharts.snk`)\n- **SkiaSharp version range**: min 2.88.9, latest 3.119.0 — changes must respect both\n- **C# 14.0** language version\n- Animation system (`Motion/`) is core infrastructure — changes require extensive testing\n- Chart updates can arrive from any thread; synchronization is essential\n\n## Additional Documentation\n\nSee `.github/copilot-instructions.md` for extended guidance including: sample platform view patterns (XAML/code-only/Blazor), adding new series types, CI/CD workflow details, and documented build errors with workarounds.\n","llms.txt":"# LiveCharts2\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET built on top of SkiaSharp for rendering; it supports Cartesian, Pie, Polar, and GeoMap chart types with smooth, automatic animations. The library uses a layered architecture separating a platform-agnostic Core from a SkiaSharp-based Renderer and platform-specific Views (WPF, Avalonia, MAUI, Blazor, etc.), so adding a new platform requires minimal effort. LiveCharts2 targets .NET Framework 4.6.2, .NET Standard 2.0, and modern .NET, and uses `INotifyPropertyChanged`/`INotifyCollectionChanged` for zero-boilerplate automatic chart updates.\n\n> **⚠️ Important: This is LiveCharts v2. Do NOT use v0 syntax.**\n> The legacy v0 (`LiveCharts` / `LiveCharts.Wpf` NuGet packages) is obsolete and has a completely different API.\n> v0 source and samples: https://github.com/Live-Charts/Live-Charts\n> Always use the v2 packages listed below and the v2 documentation at https://livecharts.dev.\n\n## Supported UI Frameworks\n\n- **MAUI** — `LiveChartsCore.SkiaSharpView.Maui` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.maui\n- **Uno Platform (WinUI)** — `LiveChartsCore.SkiaSharpView.Uno.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.Uno.WinUI\n- **Avalonia** — `LiveChartsCore.SkiaSharpView.Avalonia` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.avalonia\n- **WPF** — `LiveChartsCore.SkiaSharpView.WPF` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.wpf\n- **WinForms** — `LiveChartsCore.SkiaSharpView.WinForms` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.winforms\n- **WinUI** — `LiveChartsCore.SkiaSharpView.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.winui\n- **Blazor (WASM)** — `LiveChartsCore.SkiaSharpView.Blazor` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.blazor\n- **Eto.Forms** — `LiveChartsCore.SkiaSharpView.Eto` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.eto\n\n## URL Templates\n\n### API Reference\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\n- `{objectFullName}` follows CLI (Common Language Infrastructure) metadata naming conventions, e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `{LiveChartsVersion}`: use `latest` for the latest version, or a specific version string (e.g. `2.0.0-rc6.1`)\n- Full list of available versions: `https://livecharts.dev/docs/{UIFramework}/list`\n  - `{UIFramework}` is one of: `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`\n\n**Examples:**\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.Avalonia.PieChart`\n\n### Documentation & Examples\n\n```\nhttps://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}\n```\n\n`{UIFramework}` and `{LiveChartsVersion}` are as described above.\n\nAvailable `{ArticleName}` values:\n\n**Overview**\n- `Overview.Installation`\n- `Overview.How%20it%20works`\n- `Overview.Automatic%20updates`\n- `Overview.Mappers`\n- `Overview.Paints`\n- `Overview.Animations`\n\n**Cartesian Chart**\n- `CartesianChart.Cartesian%20chart%20control`\n- `CartesianChart.Axes%20properties`\n- `CartesianChart.Tooltips`\n- `CartesianChart.Legends`\n- `CartesianChart.Line%20series%20properties`\n- `CartesianChart.Column%20series%20properties`\n- `CartesianChart.Scatter%20series%20properties`\n- `CartesianChart.Step%20line%20series%20properties`\n- `CartesianChart.Heat%20series%20properties`\n- `CartesianChart.Candle%20sticks%20series%20properties`\n- `CartesianChart.Stacked%20line%20series%20properties`\n- `CartesianChart.Stacked%20column%20series%20properties`\n- `CartesianChart.Stacked%20step%20line%20series%20properties`\n- `CartesianChart.Box%20series%20properties`\n\n**Pie Chart**\n- `PieChart.Pie%20chart%20control`\n- `PieChart.Pie%20series`\n- `PieChart.Gauges`\n\n**Polar Chart**\n- `PolarChart.Polar%20chart%20control`\n- `PolarChart.Polar%20line%20series`\n\n**GeoMap**\n- `GeoMap.GeoMap%20control`\n- `GeoMap.Heat%20land%20series`\n\n**About**\n- `About.About%20this%20samples`\n\n**Samples**\n- `samples.lines.basic`\n- `samples.lines.straight`\n- `samples.lines.area`\n- `samples.lines.custom`\n- `samples.lines.custompoints`\n- `samples.lines.autoupdate`\n- `samples.lines.xy`\n- `samples.lines.zoom`\n- `samples.steplines.basic`\n- `samples.stackedArea.basic`\n- `samples.stackedArea.stepArea`\n- `samples.bars.basic`\n- `samples.bars.withBackground`\n- `samples.bars.custom`\n- `samples.bars.spacing`\n- `samples.bars.layered`\n- `samples.bars.rowsWithLabels`\n- `samples.bars.delayedAnimation`\n- `samples.bars.race`\n- `samples.stackedBars.basic`\n- `samples.stackedBars.groups`\n- `samples.pies.basic`\n- `samples.pies.pushout`\n- `samples.pies.doughnut`\n- `samples.pies.outlabels`\n- `samples.pies.custom`\n- `samples.pies.icons`\n- `samples.pies.nightingaleRose`\n- `samples.pies.nested`\n- `samples.pies.gauge1`\n- `samples.pies.gauge2`\n- `samples.pies.gauge3`\n- `samples.pies.gauge4`\n- `samples.pies.gauge5`\n- `samples.pies.angularGauge`\n- `samples.error.basic`\n- `samples.box.basic`\n- `samples.scatter.basic`\n- `samples.scatter.bubbles`\n- `samples.scatter.custom`\n- `samples.financial.basicCandlesticks`\n- `samples.heat.basic`\n- `samples.polar.basic`\n- `samples.polar.radialArea`\n- `samples.polar.coordinates`\n- `samples.maps.world`\n- `samples.events.tutorial`\n- `samples.events.addPointOnClick`\n- `samples.axes.labelsFormat`\n- `samples.axes.labelsFormat2`\n- `samples.axes.multiple`\n- `samples.axes.shared`\n- `samples.axes.style`\n- `samples.axes.crosshairs`\n- `samples.axes.dateTimeScaled`\n- `samples.axes.timeSpanScaled`\n- `samples.axes.matchScale`\n- `samples.axes.logarithmic`\n- `samples.axes.customSeparatorsInterval`\n- `samples.axes.paging`\n- `samples.general.multiThreading`\n- `samples.general.realTime`\n- `samples.general.sections`\n- `samples.general.chartToImage`\n- `samples.general.visualElements`\n- `samples.general.visibility`\n- `samples.general.nullPoints`\n- `samples.general.customTooltips`\n- `samples.general.customLegends`\n- `samples.general.mapPoints`\n- `samples.general.drawOnCanvas`\n- `samples.general.conditionalDraw`\n- `samples.general.scrollable`\n- `samples.design.linearGradients`\n- `samples.design.radialGradients`\n- `samples.design.strokeDashArray`\n",".claude/skills/render-chart/SKILL.md":"---\nname: render-chart\ndescription: Use when the user asks to render, visualize, plot, or \"show me a chart of\" any kind of series data (line, column, row, scatter, stacked, candlestick, box, pie, polar, heat). Renders via the `lvc` CLI from a JSON spec — inline in your reply for simple charts you need to read, or in a new terminal window for interactive / color-dependent ones (heat maps, pies with many slices, anything with > 3 series the user wants to explore).\n---\n\n# render-chart\n\nThe user wants to *see* data as a chart. You have access to a renderer (`lvc`)\nthat writes LiveCharts to a terminal. Pick the right mode for the situation,\ninstall the tool if it's missing, and either inline the result in your reply\nor hand the user a live window.\n\n## Decision: inline vs live window\n\n| Situation | Mode | Why |\n| --- | --- | --- |\n| ≤ 3 series, line / column / row / stacked-bar / scatter, you need to *verify* the shape | `--no-color` inline | Plain Braille glyphs render in a fenced code block. You can read it; the user sees it. |\n| User said \"open this in a new window\" / \"let me play with it\" / \"zoom into this\" | `--live` in a new terminal | Interactive Sixel + mouse hover + wheel zoom + click-drag pan. The user explores; you can't read the result, so don't pretend to. |\n| Heat map | `--live` in a new terminal | Heat reads the gradient by color. Strip color and it's an undifferentiated blob. |\n| Pie with > 4 slices | `--live` in a new terminal | Outer labels collide and Pushout gaps stop reading at small canvas sizes. |\n| Anything where the *meaning* depends on color (gradient encodes magnitude, similar curves only separable by hue) | `--live` in a new terminal | Plain mode can't carry color information — see [[reference_claude_code_cli_ansi_passthrough]]. |\n| User asks to \"compare these two/three series\" with simple shapes | `--no-color` inline | Single bar series stays Braille; multi-bar uses textures; line series get end-of-line labels. Distinguishable without color. |\n\n**Default to `--no-color` inline** when you can read the chart — it keeps the\nconversation flowing and you can describe what's in it. Reserve `--live` for\nwhen there's genuinely no way to convey the information in monochrome glyphs.\n\n## Step 1 — make sure dotnet is installed\n\n```sh\ndotnet --version\n```\n\nIf that errors, the user needs the .NET 8 SDK or runtime. Point them at\n<https://dotnet.microsoft.com/download> and stop — don't try to install it\nfor them (admin install, varies per OS).\n\n## Step 2 — install `lvc` as a global tool (once)\n\n```sh\ndotnet tool install -g LiveChartsCore.Console.Cli\n```\n\nIf they already have it, this errors with \"already installed\" — that's fine.\nUpdate with `dotnet tool update -g LiveChartsCore.Console.Cli`.\n\nAfter install, `lvc` is on the user's PATH. Verify with:\n\n```sh\nlvc --json '{\"kind\":\"line\",\"series\":[{\"values\":[1,2,3,2,1]}]}' --no-color\n```\n\nYou should see a small Braille line chart in stdout.\n\n## Step 3 — write the JSON spec\n\nPass via `--json '<spec>'`, `--file path.json`, or pipe stdin.\n\n```json\n{\n  \"kind\": \"line\",\n  \"title\": \"optional\",\n  \"width\": 70,\n  \"height\": 20,\n  \"series\": [\n    {\n      \"name\": \"Signal\",\n      \"values\": [1, 2, 3, 4],\n      \"strokeThickness\": 2\n    }\n  ],\n  \"xAxis\": { \"name\": \"X\", \"labels\": [\"a\", \"b\", \"c\", \"d\"] },\n  \"yAxis\": { \"name\": \"Y\" }\n}\n```\n\n`kind` accepts: `line`, `column`, `row`, `step`, `scatter`, `stackedcolumn`,\n`stackedrow`, `stackedarea`, `candlestick`, `box`, `pie`, `polar`.\n\nSeries shape:\n- `values: number[]` — line / column / row / step / stacked / pie / polar\n- `points: number[][]` — scatter (`[x, y]`) / candlestick (`[open, high, close, low]`) / box (`[max, q3, q1, median, min]`)\n- `strokeThickness: number` — line / step (optional, default 1)\n\nFor pie: needs `--width ≥ 80 --height ≥ 30` (outer labels collide otherwise).\nFor stacked column / row with 2+ series: per-series textures auto-applied in\nplain mode; legend shows the texture next to each series name.\n\n## Step 4a — inline rendering (the common path)\n\n```sh\nlvc --json '<spec>' --no-color --width 70 --height 20\n```\n\nCapture the output and paste it back inside a fenced code block in your reply.\nCommonMark renders it monospace, the user sees the same glyphs you see.\n\nSizing: ~70×20 is a sweet spot. Smaller charts get cramped; larger ones might\nwrap weirdly in the user's terminal. Default to 70×20 unless the user asked\notherwise.\n\nRead what you rendered. Describe what's in it — \"the blue series climbs from\n~5 to ~12, the red oscillates around 8\" — so the user can sanity-check it\nmatches what they wanted. Don't claim \"the chart looks correct\" without\nnaming the actual shapes you see.\n\n## Step 4b — live window (interactive / color path)\n\nSpawn a new terminal so it doesn't block your conversation:\n\n**Windows (Windows Terminal):**\n```pwsh\nStart-Process wt.exe -ArgumentList '-d', $pwd.Path, 'pwsh', '-NoExit', '-NoLogo', '-Command', 'lvc --live --file demo.json'\n```\n\n**macOS (Terminal.app):**\n```sh\nosascript -e \"tell app \\\"Terminal\\\" to do script \\\"lvc --live --file $PWD/demo.json\\\"\"\n```\n\n**Linux (GNOME Terminal):**\n```sh\ngnome-terminal --working-directory=\"$PWD\" -- lvc --live --file demo.json\n```\n\nFor multi-line JSON, write a `demo.json` file first via the Write tool and\npass `--file` — avoids cross-shell quoting hell.\n\n**Critical:** you can't read the live window's contents. After launching,\ntell the user \"I opened a chart in a new window — what do you see?\" and\niterate from their feedback. Don't fabricate a description of what's\n\"probably there.\"\n\nIn the live window the user gets: mouse hover (tooltips), click-and-drag (pan),\nmouse wheel (zoom), `q` (quit), `r` (reset zoom), `+` / `-` (zoom at center).\n\n## Common pitfalls\n\n- **`--live --no-color`** is an error: live mode redraws frames in place via\n  ANSI escapes, which is exactly what `--no-color` strips. Pick one.\n- **`--live` with stdout redirected** errors out — it needs a real TTY. Always\n  spawn a new terminal window, never pipe `--live` output.\n- **`--mode sixel --no-color`** errors out — Sixel is a binary escape sequence\n  with no plain form. Drop `--mode sixel` or drop `--no-color`.\n- **Pie charts in plain mode at small canvases** collapse the disc to a sliver\n  because outer labels reserve margin space. Use `--width 80 --height 30`\n  minimum, or accept a smaller render in `--live` mode where the disc has\n  full canvas.\n- **Stacked bar plain mode with 1 series** keeps Braille `⣿` fills (no\n  textures kick in until 2+ bar series exist). This is intentional.\n- **You cannot see colors in the user's terminal from your own output.** Inline\n  ANSI escapes you write get collapsed to one inline-code style by the\n  CommonMark renderer — see [[reference_claude_code_cli_ansi_passthrough]].\n  This is why `--no-color` is the inline path: plain glyphs don't pretend to\n  carry color information.\n\n## When NOT to use this skill\n\n- The user asks to *edit chart configuration* in a LiveCharts app (XAML /\n  source-code view) — that's a code-edit task, not a rendering task.\n- The user wants to *understand* a chart they already have a screenshot of —\n  use vision on the image, not lvc.\n- The data is structural / hierarchical (trees, graphs, org charts) — lvc\n  only handles statistical chart kinds.\n",".claude/skills/repro-and-fix/SKILL.md":"---\nname: repro-and-fix\ndescription: Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. \"let's work on issue #1234\", a github.com/Live-Charts/LiveCharts2/issues/N URL, or \"reproduce and propose a fix\"). Implements the LiveCharts workflow end-to-end — worktree, in-sample repro view, auto-launched sample, screenshot/log verification, diagnosis, fix, separate regression-test commit, and PR — with minimal user interaction.\n---\n\n# repro-and-fix\n\nA user pointed you at a GitHub issue and asked you to reproduce + fix it. Run\nthe workflow below. The whole point is that the dev loop is *self-contained*:\nyou build the repro, launch the sample at that repro automatically, verify the\nbug yourself (screenshot or logs), fix it, verify the fix, and commit. Don't\nask the user for visual confirmations you can get yourself.\n\n> **Shared with Copilot Coding Agent.** `.github/copilot-instructions.md` links\n> here as the canonical issue → reproduce → fix → PR workflow. Edit this file\n> when changing the workflow; keep the Copilot doc as a thin pointer to avoid\n> drift.\n\n## When this skill applies\n\n- \"Let's work on https://github.com/Live-Charts/LiveCharts2/issues/N\"\n- \"Reproduce issue #N and propose a fix\"\n- \"Investigate this bug report: <URL>\"\n- A user paste of an issue URL with no other instruction\n\nIf the user is asking about *theory* (\"why does the gauge use a doughnut\ngeometry?\") or a *non-issue* task (refactor, doc update, perf), this skill is\nnot the right tool — fall back to general workflow.\n\n## Pick the platform that matches the issue\n\nRead the issue's **labels** and **repro snippet** to choose. The workflow is\nthe same on every XAML platform — only paths and launch commands change.\n\n| Platform | Sample dir                    | Launch project (Debug build)                                                | In-app screenshot |\n| -------- | ----------------------------- | --------------------------------------------------------------------------- | ----------------- |\n| Avalonia | `samples/AvaloniaSample/`     | `samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/.../*.Desktop.exe` | ✅ supported       |\n| WPF      | `samples/WPFSample/`          | `samples/WPFSample/.../WPFSample.exe`                                       | ✅ supported       |\n| WinUI    | `samples/WinUISample/WinUISample/` | `samples/WinUISample/WinUISample/.../WinUISample.exe`                  | ✅ supported       |\n| MAUI     | `samples/MauiSample/`         | per-platform; `dotnet build -t:Run -f net10.0-windows10.0.19041.0`          | ❌ use OS tool     |\n| Uno      | `samples/UnoPlatformSample/UnoPlatformSample/` | per-platform                                              | ❌ use OS tool     |\n\nIf the issue is platform-agnostic (a core engine bug), prefer Avalonia for the\nfastest dev loop on Windows (no WindowsAppSDK / packaged-build overhead).\n\n## Project conventions you must follow\n\nThese are durable rules from `~/.claude/projects/.../memory/MEMORY.md`. Re-read\nthe relevant memory file if uncertain — these are not optional:\n\n- **Worktree per issue.** Create `../LiveCharts2-fix-<issue>-<slug>` first\n  (`feedback_worktree_per_issue`). Don't work in the primary tree.\n- **One concept per commit.** Fix and regression test go in *separate* commits.\n  The regression-test commit must fail when the fix is reverted — verify this\n  before pushing (`feedback_commit_separation`).\n- **Snapshot tests for render-path changes.** If your fix touches paint, layout,\n  z-index, or draw order, run `tests/SnapshotTests/` before claiming done — unit\n  tests have missed catastrophic regressions\n  (`feedback_run_snapshots_for_render_changes`).\n- **Update docs when public API changes** in the same change set as a separate\n  commit (`feedback_update_docs_for_api`).\n- Check `Directory.Build.props` for `<LiveChartsVersion>` and use that value in\n  user-facing text (`project_current_version`).\n\n## Workflow\n\n### 1. Read the issue and decide if it still reproduces\n\n```bash\ngh issue view <N> --repo Live-Charts/LiveCharts2 --json title,body,labels,state,comments\n```\n\nPay attention to **comments**, not just the body. Issues commonly evolve:\n\n- The original symptom may already be fixed in main (commenter says \"newer\n  releases fixed this\") and the *current* bug is a downstream observation.\n  This is exactly what happened with #2008 — the `GaugeValue` TemplateBinding\n  bug in the title was already resolved; the live bug was a `CornerRadius=0`\n  override in the comments.\n- Multiple users may report different things in the same thread. Identify the\n  most recent reporter's actual symptom.\n\nIf you suspect the title bug is already fixed: build the original repro\nverbatim and verify *first*, before doing diagnosis. Cite the commenter who\nsaid it's fixed in your PR description.\n\n### 2. Set up the worktree\n\n```bash\ngit worktree add ../LiveCharts2-fix-<issue>-<short-slug> -b fix/issue-<N>-<short-slug>\n```\n\nAll edits, builds, and runs happen in the worktree. The primary tree stays\nclean for other work.\n\n### 3. Build the repro view (XAML platforms)\n\nThe repro convention is a **sample view inside the platform sample app**:\n\n```\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>.cs\n```\n\nMatch the issue's repro setup as closely as you can — same `ControlTemplate`\nshape, same property values, same paints. *Don't simplify* until you've\nconfirmed the bug fires; over-minimization can accidentally avoid the trigger.\n\nExisting repros to mirror:\n\n- `samples/AvaloniaSample/VisualTest/Issue1986Repro/` — TabControl + ScrollViewer\n- `samples/AvaloniaSample/VisualTest/Issue1417Repro/` — GeoMap reattach\n\nThe View's code-behind should expose helpers that a Factos test can call\n(e.g. `FindTemplatedGaugeSeries()`). This is how the regression test hooks in\nwithout going through the visual tree.\n\n**Do not commit changes to `samples/ViewModelsSamples/Index.cs` for repro\nviews.** Factos navigates to a sample by path via `LVC_SAMPLE` regardless of\nwhether the path is listed in the index, and the index is shared across every\nplatform sample. If you add `VisualTest/Issue<N>Repro` there and the view only\nexists in `samples/AvaloniaSample/`, every other platform sample (WPF, MAUI,\nWinUI, Uno) will throw when it loads the index. Leave the file untouched on\nyour branch.\n\nIf it's genuinely easier for your *local* dev loop to pick the repro from the\nsample selector dropdown rather than via `LVC_SAMPLE`, edit `Index.cs`\ntemporarily — but revert it before committing. `git restore\nsamples/ViewModelsSamples/Index.cs` before each commit, or just don't stage\nthe file.\n\n### 4. Auto-launch the sample at your repro\n\nAll XAML platform samples read `LVC_SAMPLE` at startup and load that sample\ninstead of the default landing screen. Set it before launching:\n\n```bash\n# bash / WSL\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nBuild first if needed: `dotnet build samples/<Platform>Sample/... -c Debug`.\n\n### 5. Verify the bug yourself\n\nTwo paths — pick based on the bug type:\n\n**A. In-app screenshot for visual bugs** (color, shape, position, rendering\nartifacts). Avalonia/WPF/WinUI samples support `LVC_SCREENSHOT`: when set,\nthe sample renders its main window via the framework's native\n`RenderTargetBitmap` after a short delay (default 3 s, override with\n`LVC_SCREENSHOT_DELAY_MS`) and exits. No external tooling, no race against\na screenshot tool launching too early. The capture is scaled to the\nwindow's physical pixels (`RenderScaling` on Avalonia,\n`VisualTreeHelper.GetDpi` on WPF) so HiDPI displays produce a sharp PNG\nthat matches what's on screen:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-before.png \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n$env:LVC_SCREENSHOT = \"$pwd\\.claude\\screenshots\\<N>-before.png\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nAfter it exits, `Read` the PNG. You're multimodal — describe what you see,\ncompare to a control sample (often `Pies/Gauge1` or `General/FirstChart` for\n\"what should this look like\"). If the bug is subtle (a few pixels), make the\nrepro larger (`Width=380`, `Height=380`) so it's clearly visible.\n\n**Fallback for MAUI/Uno or other-OS edge cases:** use the OS-appropriate\nhelper script. They all take `<ProcessName> <OutPath> [WaitSeconds]` and\npoll for the target window before capturing:\n\n| OS      | Script                                       | Underlying tool                            |\n| ------- | -------------------------------------------- | ------------------------------------------ |\n| Windows | `.claude/scripts/capture-window.ps1`         | `PrintWindow` via Win32 (works occluded)   |\n| macOS   | `.claude/scripts/capture-window-macos.sh`    | `osascript` + `screencapture -l <id>`      |\n| Linux   | `.claude/scripts/capture-window-linux.sh`    | `xdotool`+`import` / `swaymsg`+`grim` / `gnome-screenshot` |\n\nThe Linux script tries X11 → sway → GNOME in priority order; install the\nmatching package if none are present (the script prints the apt/dnf hint).\nUse these only when `LVC_SCREENSHOT` isn't supported on the target platform\n(MAUI, Uno) — for Avalonia/WPF/WinUI prefer in-app capture.\n\n**B. Console logs for state/dataflow bugs** (binding doesn't fire, value\ndoesn't propagate, event order is wrong):\n\nAdd temporary `Console.WriteLine` calls along the suspected path:\n\n```csharp\nConsole.WriteLine($\"[issue<N>] OnPropertyChanged: {change.Property.Name} old={change.OldValue} new={change.NewValue}\");\n```\n\nThe platform sample writes to stdout when launched from the terminal. Run via\nthe bash tool with `run_in_background=true` (no `LVC_SCREENSHOT` so the app\nstays open), wait a few seconds, kill the app, then `grep` the captured output\nfile. **Remove the diagnostics before committing.**\n\nIf neither approach decisively confirms the bug, escalate to the user with\n**one** well-framed question, not a chain of polling questions. Example:\n\n> \"The before-fix capture shows the gauge endcaps as flat, contrary to the\n> issue's screenshot. Did you toggle CornerRadius after the screenshot was\n> taken in the original report?\"\n\n### 6. Diagnose the root cause\n\nTrace from symptom backward through the rendering/data pipeline. Cross-check\nagainst `MEMORY.md` — many bugs in this repo have related ancestors\n(z-index issues, theme overrides, motion-property defaults, source-gen\nbehavior). If you find a matching memory note, use its diagnosis as a starting\npoint but verify against current code; memories go stale.\n\nCommon gotchas in this codebase:\n\n- **Theme overrides user-set values** when the user's value equals the DP\n  default — Avalonia skips `OnPropertyChanged` and `_userSets` never gets\n  populated. `XamlGaugeSeries.EndInit` syncs IsSet DPs as a remediation; if\n  you see this pattern in another wrapper, the same fix shape applies.\n- **Series controls aren't in the visual tree.** `OnInitialized` and\n  `TemplatedParent` may not fire/be set the way you'd expect. Use `EndInit`\n  instead.\n- **Theme rules run from the chart engine measure pass**, not at construction.\n  `_isInternalSet` + `_userSets` is the existing precedence mechanism — don't\n  reinvent it.\n- **Motion properties animate from a stale \"from\" value.** A value flip from\n  N→0 may render N for one frame.\n\n### 7. Write the regression test first\n\nTest-first: by the end of step 6 you understand the root cause and the\nobservable that would catch a regression. Write the test now, *before*\napplying the fix, and run it — it must fail for the right reason. A test\nwritten after the fix risks passing against both versions of the code; a\ntest that fails first proves it's gated on the broken behavior, and you\nskip the awkward \"comment out the fix, rebuild, re-run\" verification dance.\n\nTest choice depends on the bug nature:\n\n- **Programmatic state assertion** (the bug is in state propagation, not\n  pixels): Factos test in `tests/SharedUITests/`. Navigate to the repro,\n  query a helper method on the View that exposes the state under test,\n  assert. Gate by `#if <PLATFORM>_UI_TESTING` if platform-specific (most\n  XAML-platform-quirk bugs are).\n- **Pixel-perfect rendering**: snapshot test in `tests/SnapshotTests/`.\n- **Animation trajectory** (the bug is in per-frame interpolation, not the\n  final value — a bar pops to target instead of growing, a slice doesn't\n  sweep, a transition runs at the wrong speed, a refactor risks changing the\n  motion shape of an existing series): JSON animation baseline under\n  `tests/CoreTests/AnimationBaselines/` driven by\n  `tests/CoreTests/Helpers/SeriesAnimationCapture.cs`. The helper steps\n  `CoreMotionCanvas.DebugElapsedMilliseconds`, captures the visual's geometry\n  at each sample timestamp, and `AssertTrajectoryMatches` compares the\n  trajectory to a committed `.json`. First run writes the new trajectory to\n  `AnimationBaselinesNew/` and fails with a \"review and commit\" message —\n  inspect the file, then move it into `AnimationBaselines/`. Re-baseline the\n  same way: delete the JSON, re-run, move from `New/` back. On mismatch the\n  helper also drops `[EXPECTED]`/`[RESULT]` files into\n  `AnimationBaselinesDiff/` so you can diff them directly. Caller must use\n  `EasingFunctions.Lineal` + fixed `MinLimit`/`MaxLimit` so interpolation is\n  deterministic; the existing `tests/CoreTests/SeriesTests/*AnimationTests.cs`\n  files are the templates. Prefer this over a plain MSTest whenever the\n  observable is \"how the value changes between two states\" — a single\n  before/after assertion can't catch a regression that only mis-paints the\n  intermediate frames.\n- **Pure C# logic** (chart engine, motion, math): MSTest in\n  `tests/CoreTests/`.\n\nRun the test and confirm the failure message matches the symptom you saw in\nstep 5 — not, for example, a setup error or NullRef from missing test\ninfrastructure. If it fails for an unrelated reason, the test isn't yet\ncatching the bug; fix the test before moving on.\n\nTo run a single Factos UI test:\n\n```bash\n# In tests/UITests/Program.cs, set: var appToRun = \"<platform>-desktop\"\n# (avalonia-desktop / wpf-net10 / winui / maui / uno).\ndotnet build tests/UITests/UITests.csproj -c Debug\ncd tests/UITests/bin/Debug/net10.0 && dotnet UITests.dll\n# Revert the appToRun change before committing — it's a local dev-loop tweak.\n```\n\n### 8. Apply the fix\n\nSmallest possible change. Don't refactor surrounding code. Don't add\ncomments unless the WHY is non-obvious — but if the bug is a subtle\ninteraction (Avalonia behavior, theme precedence, source-gen quirk), a comment\nexplaining *why this fix is necessary* is warranted because future readers\nwon't reconstruct it from memory.\n\n### 9. Verify the fix\n\nRe-run the failing test from step 7 — it must now pass. Then re-run step 5\nwith the fix in place to capture an \"after\" screenshot at a sibling path and\ncompare visually:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-after.png \\\n  ./samples/<Platform>Sample/.../<Platform>Sample.exe\n```\n\n`Read` both images. Don't claim the fix works without comparing. The test\npassing is necessary but not sufficient for visual bugs — pixel-equivalent\noutput can still look subtly wrong if the assertion was too narrow.\n\n### 10. Commit and PR\n\nYou developed test-first, but commit fix-first. Two commits, in this order:\n\n1. `fix(<scope>): <one-line summary> (#<N>)` — only the fix.\n2. `test(<scope>): regression for <symptom> (#<N>)` — only the test +\n   repro view. Do not stage `samples/ViewModelsSamples/Index.cs`; see step 3\n   for why.\n\nWhy fix-first commit order despite test-first development: every commit on\nthe branch should be individually green so `git bisect` lands on a usable\nstate. If the test commit landed first it would be a failing-test commit\nthat bisect would (correctly) flag as broken. Fix-then-test keeps both\ncommits green while still satisfying the project rule that reverting the\nfix must surface the regression — revert commit 1 alone and the test from\ncommit 2 fails.\n\nCommit message style follows recent history (`git log --oneline -10`).\nBody: imperative, mention the root-cause mechanism, why the test catches it.\nEnd with the standard `Co-Authored-By` line.\n\nPush and open the PR with `gh pr create`. The PR body should include:\n\n- **Summary** bullet list (what changed, what it closes)\n- **Why** section (root cause walkthrough — the most valuable part)\n- **Test plan** checklist with what you actually verified locally\n\n### 11. Update memory\n\nAfter the PR is open, write a `project_issue_<N>.md` memory and add a one-line\nentry to `MEMORY.md`. Capture: **what was non-obvious** about the bug, what\ndiagnosis steps led to the fix, and what conventions/files the next person\nneeds. Don't re-document the code — just the insights.\n\n## Anti-patterns to avoid\n\n- **Asking the user \"is the bug visible now?\" repeatedly.** Capture a\n  screenshot or read logs. If you can't decide from one capture + one\n  question, you haven't framed the question precisely enough.\n- **Simplifying the repro before confirming.** A \"minimal\" repro that doesn't\n  trigger the bug is worse than a verbose one that does.\n- **Writing the test after the fix.** Develop test-first (step 7 before\n  step 8) so the failure is real and you don't have to comment out the fix\n  to verify the test catches anything. A test authored against\n  already-fixed code can pass for the wrong reason.\n- **Mixing fix + test + cleanup in one commit.** Project policy is strict\n  here — every fix needs a separately revertible test commit.\n- **Force-pushing for \"cleanliness\".** Never. Stack new commits.\n- **Trusting memory over code.** Memory files name specific functions and\n  files; verify they still exist before recommending — projects refactor.\n\n## Tooling reference\n\n- Issue triage: `gh issue view <N> --repo Live-Charts/LiveCharts2`\n- **Auto-launch sample**: `LVC_SAMPLE=<path>` env var (Avalonia, WPF, WinUI,\n  MAUI, Uno).\n- **In-app screenshot**: `LVC_SCREENSHOT=<path>` env var (Avalonia, WPF,\n  WinUI). Sample renders to PNG after `LVC_SCREENSHOT_DELAY_MS` (default\n  3000) and exits.\n- **External screenshot fallback** — one script per OS, all take the same\n  `<ProcessName> <OutPath> [WaitSeconds]` shape:\n  - Windows: `.claude/scripts/capture-window.ps1` (also accepts\n    `-WindowTitle <substring>` instead of `-ProcessName`)\n  - macOS:   `.claude/scripts/capture-window-macos.sh`\n  - Linux:   `.claude/scripts/capture-window-linux.sh` (X11 / sway / GNOME)\n- Factos UI tests: `tests/UITests/`, set `appToRun` in `Program.cs` for\n  local runs.\n- Build per-platform: `LiveCharts.<Platform>.slnx` solutions.\n","llms-full.txt":"# LiveCharts2 — Comprehensive Knowledge Base for LLMs\n\n> **⚠️ Version Warning:** This document covers **LiveCharts v2** (package prefix `LiveChartsCore.SkiaSharpView.*`).\n> The legacy **v0** (`LiveCharts` / `LiveCharts.Wpf`) is completely obsolete and has a different API.\n> Do NOT mix v0 and v2 syntax. v0 reference: https://github.com/Live-Charts/Live-Charts\n\n---\n\n## Overview\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET. It fixes the main design issues of its\npredecessor (v0), is focused on running everywhere, and improves flexibility. It uses **SkiaSharp** as its default\nrendering backend — a cross-platform 2D graphics API for .NET based on Google's Skia graphics library.\n\n- **Website / full docs:** https://livecharts.dev\n- **GitHub:** https://github.com/Live-Charts/LiveCharts2\n- **License:** MIT\n- **Current version:** 2.1.0 (check NuGet for latest stable/prerelease)\n- **Target frameworks (core):** `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **C# language version:** 14.0\n\n### Supported Platforms & NuGet Packages\n\n| Platform | NuGet package |\n|---|---|\n| MAUI | `LiveChartsCore.SkiaSharpView.Maui` |\n| Uno Platform (WinUI) | `LiveChartsCore.SkiaSharpView.Uno.WinUI` |\n| Avalonia | `LiveChartsCore.SkiaSharpView.Avalonia` |\n| WPF | `LiveChartsCore.SkiaSharpView.WPF` |\n| WinForms | `LiveChartsCore.SkiaSharpView.WinForms` |\n| WinUI | `LiveChartsCore.SkiaSharpView.WinUI` |\n| Blazor WASM | `LiveChartsCore.SkiaSharpView.Blazor` |\n| Eto.Forms | `LiveChartsCore.SkiaSharpView.Eto` |\n\nSkiaSharp minimum supported version: **2.88.9** (default: 3.119.0 for GPU support).\n\n---\n\n## Architecture\n\nThe library is divided into three main modules:\n\n### Core (`LiveChartsCore`)\n\nPlatform-agnostic. Contains:\n- A drawing **API** (interfaces) that defines all the shapes the library needs to build a chart\n- The charting engine: measures sizes, calculates positions for every geometry\n- The animation system (`Motion/` namespace) — `IAnimatable`, `MotionProperty`\n- Change-detection via `CollectionDeepObserver` (wraps `INotifyPropertyChanged` / `INotifyCollectionChanged`)\n- Series implementations: `LineSeries<T>`, `ColumnSeries<T>`, `PieSeries<T>`, `ScatterSeries<T>`, etc.\n\n### Renderer (`LiveChartsCore.SkiaSharp`)\n\nImplements the Core drawing API using SkiaSharp. Responsible for materializing geometry objects to pixels.\nYou can replace SkiaSharp with any other rendering engine (see `VorticeSample` using DirectX11 via Vortice.Windows).\n\n### View (platform packages)\n\nPlatform-specific controls (`CartesianChart`, `PieChart`, `PolarChart`, `GeoMap`) that:\n1. Ask the **Core** *what* to draw (geometry sizes and positions)\n2. Ask the **Renderer** *how* to draw it (render to the platform surface)\n\n### Animation System\n\nLiveCharts generates animations by producing many frames over time. Each animatable object has\n`MotionProperty` fields whose getter returns the *current interpolated value* for the current point\nin time — not the last assigned value. This means:\n\n```csharp\nvar line = new LineGeometry();\nline.X1 = 0;\nline.X1 = 100;\nvar x1 = line.X1; // returns 0 (animation has not elapsed yet)\n// After 5 seconds (of a 10s linear transition): line.X1 returns ~50\n```\n\n### Automatic Update Cycle\n\n1. User changes data (property or collection).\n2. `CollectionDeepObserver` detects the change via `INotifyPropertyChanged` / `INotifyCollectionChanged`.\n3. The chart **throttles** a *Measure request* (fires at most once every ~10 ms).\n4. On measure: Core recalculates geometry positions → Update cycle draws frames until all `MotionProperty` animations complete.\n\n---\n\n## Installation\n\n### Install via NuGet (pick your platform)\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView.WPF\ndotnet add package LiveChartsCore.SkiaSharpView.Avalonia\ndotnet add package LiveChartsCore.SkiaSharpView.Maui\ndotnet add package LiveChartsCore.SkiaSharpView.Blazor\ndotnet add package LiveChartsCore.SkiaSharpView.WinForms\ndotnet add package LiveChartsCore.SkiaSharpView.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Uno.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Eto\n```\n\n> **Note for WPF / WinForms:** By default these projects target `netX.0-windows`, but SkiaSharp 3 does not provide\n> a build for that TFM. Consider specifying a minimum Windows version: `net8.0-windows10.0.19041`.\n\n### Configure LiveCharts at startup\n\nCreate a `CustomLiveChartsExtensions` class (shared across all platforms):\n\n```csharp\nusing LiveChartsCore.Kernel;\nusing LiveChartsCore.SkiaSharpView;\n\npublic static partial class CustomLiveChartsExtensions\n{\n    public static LiveChartsSettings AddLiveChartsAppSettings(this LiveChartsSettings settings) =>\n        settings\n            .AddSkiaSharp()           // use SkiaSharp as renderer\n            .AddDefaultMappers()      // register built-in type mappers\n            .AddDefaultTheme()        // light/dark theme based on OS\n            // optionally register a mapper for a custom type:\n            .HasMap<City>((city, index) => new(index, city.Population));\n}\n```\n\n#### WPF — `App.xaml.cs`\n\n```csharp\nprotected override void OnStartup(StartupEventArgs e)\n{\n    base.OnStartup(e);\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n}\n```\n\n#### Avalonia — `App.axaml.cs`\n\n```csharp\npublic override void OnFrameworkInitializationCompleted()\n{\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    // ...\n}\n```\n\n#### MAUI — `MauiProgram.cs`\n\n```csharp\nbuilder\n    .UseMauiApp<App>()\n    .UseLiveCharts(config => config.AddLiveChartsAppSettings());\n```\n\n#### Blazor — `App.razor`\n\n```razor\n@inject IJSRuntime JS\n@code {\n    protected override async Task OnInitializedAsync()\n    {\n        LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    }\n}\n```\n\n---\n\n## Core Concepts\n\n### Series and Values\n\nEvery series is generic over its data type `T`. LiveCharts natively supports `short`, `int`, `long`, `float`,\n`double`, `decimal` and their nullable forms. It also provides observable wrappers:\n\n| Type | Use case |\n|---|---|\n| `ObservableValue` | Single Y value that notifies changes |\n| `ObservablePoint` | Explicit X and Y |\n| `WeightedPoint` | X, Y, Weight (bubble charts) |\n| `DateTimePoint` | X is `DateTime` |\n| `TimeSpanPoint` | X is `TimeSpan` |\n| `ObservablePolarPoint` | Polar charts |\n| `FinancialPoint` / `FinancialPointI` | OHLC candlestick charts |\n\n```csharp\n// simple array — static, no auto-update:\nnew LineSeries<double> { Values = new double[] { 1, 2, 3 } }\n\n// ObservableCollection — auto-updates when items are added/removed:\nvar values = new ObservableCollection<ObservableValue>();\nnew LineSeries<ObservableValue> { Values = values }\nvalues.Add(new ObservableValue(5));  // chart updates automatically\n```\n\n### Mappers\n\nUse a **mapper** to teach LiveCharts how to plot a custom type:\n\n```csharp\n// Per-series mapper:\nnew LineSeries<TempSample>\n{\n    Values = samples,\n    Mapping = (sample, index) => new Coordinate(sample.Time, sample.Temperature)\n}\n\n// Global mapper (applied to every series using TempSample):\nLiveCharts.Configure(config =>\n    config.HasMap<TempSample>((sample, index) => new Coordinate(sample.Time, sample.Temperature)));\n```\n\n### IChartEntity (high-performance custom types)\n\nImplement `IChartEntity` directly on your model for best performance (no delegate overhead per point):\n\n```csharp\npublic partial class TempSample : ObservableObject, IChartEntity\n{\n    [ObservableProperty] private int _time;\n    [ObservableProperty] private double _temperature;\n\n    public Coordinate Coordinate { get; protected set; }\n    public ChartEntityMetaData? MetaData { get; set; }\n\n    protected override void OnPropertyChanged(PropertyChangedEventArgs e)\n    {\n        Coordinate = new Coordinate(Time, Temperature);\n        base.OnPropertyChanged(e);\n    }\n}\n```\n\n### Paints\n\nA `Paint` is the v2 equivalent of WPF/Avalonia `Brush`. It wraps SkiaSharp's paint and adds animation support.\n\n```csharp\nusing SkiaSharp;\nusing LiveChartsCore.SkiaSharpView.Painting;\n\n// Solid color\nnew SolidColorPaint(SKColors.Blue) { StrokeThickness = 4 }\n\n// Linear gradient\nnew LinearGradientPaint(\n    new[] { new SKColor(255, 140, 148), new SKColor(220, 237, 194) },\n    new SKPoint(0.5f, 0),   // gradient start (center-top)\n    new SKPoint(0.5f, 1))   // gradient end   (center-bottom)\n\n// Radial gradient\nnew RadialGradientPaint(new SKColor(255, 96, 96), new SKColor(255, 234, 96))\n\n// null means \"do not draw\" (hides fill, stroke, etc.)\nFill = null\n```\n\nAvailable paint properties: `StrokeThickness`, `PathEffect` (for dashed lines), `ImageFilter`, etc.\n\n### Animations\n\nAll charts animate automatically. Customize with:\n\n```csharp\n// Chart-level speed:\nmyChart.AnimationsSpeed = TimeSpan.FromMilliseconds(300);\n\n// Easing function:\nmyChart.EasingFunction = EasingFunctions.BounceOut;\n\n// Disable animations:\nmyChart.AnimationsSpeed = TimeSpan.Zero;\n// or:\nmyChart.EasingFunction = null;\n```\n\nSeries and Axes also have their own `AnimationsSpeed` and `EasingFunction` properties\n(override the chart-level value when non-null).\n\n### Null / missing points\n\nSet a value to `null` or a `Coordinate` to `Coordinate.Empty` to create gaps:\n\n```csharp\nnew LineSeries<double?>\n{\n    Values = new double?[] { 2, 6, null, 3, 5 }\n}\n```\n\n### Hardware Acceleration (GPU)\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\n\nLiveCharts.Configure(c => c\n    .AddLiveChartsRenderSettings());  // see LiveChartsRenderSettings.cs in samples\n```\n\nGPU is disabled by default. On Avalonia/Uno with SkiaRenderer the GPU setting is ignored\n(the UI framework controls rendering).\n\n---\n\n## Chart Types\n\n### CartesianChart\n\nStandard X/Y chart. Hosts `Series` (collection of `ICartesianSeries`), `XAxes`, `YAxes`.\n\nSupports: `LineSeries`, `ColumnSeries`, `ScatterSeries`, `StepLineSeries`, `HeatSeries`,\n`CandlesticksSeries`, `StackedLineSeries`, `StackedColumnSeries`, `StackedStepLineSeries`, `BoxSeries`, `ErrorSeries`.\n\nKey properties: `Series`, `XAxes`, `YAxes`, `ZoomMode`, `AnimationsSpeed`, `TooltipPosition`, `LegendPosition`.\n\n### PieChart\n\nHosts `PieSeries<T>`. Used for pie, doughnut, gauge, and Nightingale rose charts.\n\n### PolarChart\n\nHosts `PolarLineSeries<T>` and `PolarScatterSeries<T>`. Uses polar (angle + radius) coordinates.\n\n### GeoMap\n\nDisplays geographic maps. Hosts `HeatLandSeries` to color countries/regions by value.\n\n---\n\n## XAML Integration (WPF, Avalonia, MAUI, WinUI)\n\n### XAML Types (Xaml-prefixed)\n\nEvery `Series<T>` and `Axis` has a XAML-friendly counterpart (prefix `Xaml`). These live in the visual tree\nand support data bindings, styles, hot-reload and designer previews:\n\n- `XamlLineSeries`, `XamlColumnSeries`, `XamlPieSeries`, `XamlScatterSeries`, etc.\n- `XamlAxis`, `XamlDrawnLabelVisual`\n\nThe non-Xaml types (`LineSeries<T>`, `ColumnSeries<T>`) are plain C# objects and do **not** live in the\nvisual tree — use them in ViewModels when you want to keep UI logic separate from SkiaSharp dependencies.\n\n### SeriesCollection (WPF / WinUI / Uno)\n\nWPF, WinUI and Uno use `SeriesCollection` as a container in XAML to hold multiple series children:\n\n```xml\n<lvc:CartesianChart.Series>\n    <lvc:SeriesCollection>\n        <lvc:XamlLineSeries Values=\"{Binding Values1}\"/>\n        <lvc:XamlColumnSeries Values=\"{Binding Values2}\"/>\n    </lvc:SeriesCollection>\n</lvc:CartesianChart.Series>\n```\n\nAvalonia and MAUI support multiple children directly (no wrapper needed).\n\n---\n\n## Code Examples\n\n### Example 1 — Basic Line Chart (WPF, code-behind + XAML MVVM)\n\n**ViewModel (shared, no UI dependencies):**\n\n```csharp\n// samples/ViewModelsSamples/Lines/Basic/ViewModel.cs\nnamespace ViewModelsSamples.Lines.Basic;\n\npublic class ViewModel\n{\n    public double[] Values1 { get; set; } = [2, 1, 3, 5, 3, 4, 6];\n    public int[]    Values2 { get; set; } = [4, 2, 5, 2, 4, 5, 3];\n}\n```\n\n**WPF View (View.xaml):**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Lines.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Lines.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n                <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n**Avalonia View (View.axaml):**\n\n```xml\n<UserControl\n    x:Class=\"AvaloniaSample.Lines.Basic.View\"\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n    xmlns:vms=\"using:ViewModelsSamples.Lines.Basic\"\n    x:DataType=\"vms:ViewModel\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 2 — Bar Chart with Axis Labels (WPF)\n\n**ViewModel:**\n\n```csharp\nnamespace ViewModelsSamples.Bars.Basic;\n\npublic class ViewModel\n{\n    public double[] MaryValues { get; set; } = [2, 5, 4];\n    public double[] AnaValues  { get; set; } = [3, 1, 6];\n    public string[] Labels     { get; set; } = [\"Category 1\", \"Category 2\", \"Category 3\"];\n}\n```\n\n**WPF View:**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Bars.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Bars.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart LegendPosition=\"Right\">\n\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlColumnSeries SeriesName=\"Mary\" Values=\"{Binding MaryValues}\"/>\n                <lvc:XamlColumnSeries SeriesName=\"Ana\"  Values=\"{Binding AnaValues}\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n\n        <lvc:CartesianChart.XAxes>\n            <lvc:AxesCollection>\n                <lvc:XamlAxis\n                    Labels=\"{Binding Labels}\"\n                    SeparatorsPaint=\"#c8c8c8\"\n                    SeparatorsAtCenter=\"False\"\n                    TicksPaint=\"#232323\"\n                    TicksAtCenter=\"True\"\n                    MinStep=\"1\"\n                    ForceStepToMin=\"True\"/>\n            </lvc:AxesCollection>\n        </lvc:CartesianChart.XAxes>\n\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 3 — Real-Time Chart (shared ViewModel, any platform)\n\nAdds a new `DateTimePoint` every 100 ms using `ObservableCollection` — the chart updates automatically\nbecause `ObservableCollection` implements `INotifyCollectionChanged`.\n\n```csharp\nusing System;\nusing System.Collections.ObjectModel;\nusing System.Threading.Tasks;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing LiveChartsCore.Defaults;\n\nnamespace ViewModelsSamples.General.RealTime;\n\npublic partial class ViewModel : ObservableObject\n{\n    public ViewModel() { _ = ReadData(); }\n\n    // 'partial' is required by CommunityToolkit.Mvvm source generator (C# 14 partial properties)\n    [ObservableProperty]\n    public partial double[] Separators { get; set; } = [];\n\n    public ObservableCollection<DateTimePoint> Values { get; set; } = [];\n\n    public Func<DateTime, string> LabelsFormatter { get; } =\n        date => (DateTime.Now - date).TotalSeconds < 1 ? \"now\" : $\"{(DateTime.Now - date).TotalSeconds:N0}s ago\";\n\n    // Use a lock so background thread writes are safe\n    public object Sync { get; } = new object();\n    public bool IsReading { get; set; } = true;\n\n    private async Task ReadData()\n    {\n        var random = new Random();\n        while (IsReading)\n        {\n            await Task.Delay(100);\n            lock (Sync)\n            {\n                Values.Add(new DateTimePoint(DateTime.Now, random.Next(0, 10)));\n                if (Values.Count > 250) Values.RemoveAt(0);\n                Separators = GetSeparators();\n            }\n        }\n    }\n\n    private static double[] GetSeparators()\n    {\n        var now = DateTime.Now;\n        return [\n            now.AddSeconds(-25).Ticks,\n            now.AddSeconds(-20).Ticks,\n            now.AddSeconds(-15).Ticks,\n            now.AddSeconds(-10).Ticks,\n            now.AddSeconds(-5).Ticks,\n            now.Ticks\n        ];\n    }\n}\n```\n\n> **Threading note:** When updating chart data from a non-UI thread, use a lock object (`Sync`) and assign\n> it to the chart's `SyncContext` property so LiveCharts can coordinate reads/writes safely.\n\n---\n\n### Example 4 — Pie Chart with Named Slices\n\n```csharp\nnamespace ViewModelsSamples.Pies.Basic;\n\npublic class PieData(string name, double value)\n{\n    public string Name   { get; set; } = name;\n    public double[] Values { get; set; } = [value];\n}\n\npublic class ViewModel\n{\n    public PieData[] Data { get; set; } =\n    [\n        new(\"Mary\",    10),\n        new(\"John\",    20),\n        new(\"Alice\",   30),\n        new(\"Bob\",     40),\n        new(\"Charlie\", 50),\n    ];\n}\n```\n\n**WPF View (using XAML template):**\n\n```xml\n<lvc:PieChart SeriesSource=\"{Binding Data}\">\n    <lvc:PieChart.SeriesTemplate>\n        <DataTemplate>\n            <lvc:XamlPieSeries\n                SeriesName=\"{Binding Name}\"\n                Values=\"{Binding Values}\"/>\n        </DataTemplate>\n    </lvc:PieChart.SeriesTemplate>\n</lvc:PieChart>\n```\n\n---\n\n### Example 5 — Custom Mapper (CLI / Console / Server)\n\nRender a chart to an image without any UI framework using `SKCartesianChart`:\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\nusing LiveChartsCore.SkiaSharpView;\n\n// Custom data type\npublic class TempSample { public int Time { get; set; } public double Temperature { get; set; } }\n\nvar samples = new[]\n{\n    new TempSample { Time = 1, Temperature = 65.65 },\n    new TempSample { Time = 5, Temperature = 62.23 },\n    new TempSample { Time = 8, Temperature = 85.12 },\n};\n\nvar chart = new SKCartesianChart\n{\n    Width  = 900,\n    Height = 600,\n    Series = new[]\n    {\n        new LineSeries<TempSample>\n        {\n            Values  = samples,\n            Mapping = (sample, index) => new(sample.Time, sample.Temperature)\n        }\n    },\n    XAxes = new[] { new Axis { Labeler = value => $\"{value} s\" } },\n    YAxes = new[] { new Axis { Labeler = value => $\"{value} °C\" } },\n};\n\nchart.SaveImage(\"chart.png\");\n```\n\n---\n\n## Axes\n\nThe `CartesianChart` exposes `XAxes` and `YAxes` (both `IEnumerable<IAxis>`). Default: one `Axis` each.\n\n### Key Axis properties\n\n| Property | Description |\n|---|---|\n| `Labeler` | `Func<double, string>` — formats axis tick labels |\n| `Labels` | `IList<string>` — named labels (index-based, used for category axes) |\n| `MinLimit` / `MaxLimit` | Fix the visible range (used for zooming/panning) |\n| `MinStep` / `ForceStepToMin` | Force minimum separation between ticks |\n| `SeparatorsPaint` | Paint for grid lines |\n| `TicksPaint` | Paint for axis tick marks |\n| `NamePaint` | Paint for the axis name label |\n| `DataLabelsPaint` | Paint for data labels on the series |\n| `CrosshairPaint` | Paint for crosshair lines |\n| `IsVisible` | Show/hide the axis |\n| `Position` | `AxisPosition.Start` or `AxisPosition.End` |\n\n### Zooming and Panning\n\n```csharp\n// Enable X-axis zoom and pan:\nmyChart.ZoomMode = ZoomAndPanMode.X;\n\n// Enable both axes:\nmyChart.ZoomMode = ZoomAndPanMode.Both;\n\n// Disable:\nmyChart.ZoomMode = ZoomAndPanMode.None;\n```\n\nEach gesture also has its own flag (`PanX`, `ZoomX`, `PanY`, `ZoomY`) so zoom and pan can be enabled independently. The composites `X = PanX | ZoomX`, `Y = PanY | ZoomY` and `Both = X | Y` keep their original pan+zoom semantics.\n\n```csharp\n// Allow zooming on the X axis but disable panning (e.g. so pan gestures don't hide tooltips on mobile):\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX;\n\n// Zoom on X, pan on Y:\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY;\n```\n\n`ZoomAndPanMode` is a flags enum — combine values:\n```csharp\nmyChart.ZoomMode = ZoomAndPanMode.X | ZoomAndPanMode.NoFit | ZoomAndPanMode.NoZoomBySection;\n```\n\n### DateTime / TimeSpan Axes\n\nUse `DateTimePoint` or `TimeSpanPoint` for time-based X axes and format with a `Labeler`:\n\n```csharp\nXAxes = new[]\n{\n    new Axis\n    {\n        Labeler = value => new DateTime((long)value).ToString(\"HH:mm:ss\"),\n        UnitWidth = TimeSpan.FromSeconds(1).Ticks,\n        MinStep  = TimeSpan.FromSeconds(1).Ticks,\n    }\n};\n```\n\n---\n\n## Tooltips & Legends\n\n```csharp\n// Tooltip position options: Top (default), Bottom, Left, Right, Center, Hidden\nmyChart.TooltipPosition = TooltipPosition.Bottom;\n\n// Legend position: Hidden (default), Top, Bottom, Left, Right\nmyChart.LegendPosition = LegendPosition.Right;\n```\n\nCustom tooltips: implement `IChartTooltip<TDrawingContext>` and assign to `Chart.Tooltip`.  \nCustom legends: implement `IChartLegend<TDrawingContext>` and assign to `Chart.Legend`.\n\n---\n\n## Sections (Reference Lines / Bands)\n\n```csharp\nusing LiveChartsCore;\n\nmyChart.Sections = new[]\n{\n    new RectangularSection\n    {\n        Yi = 4,\n        Yj = 8,\n        Fill = new SolidColorPaint(new SKColor(255, 205, 210, 100))\n    }\n};\n```\n\n---\n\n## Drawing on Canvas\n\nUse `Chart.VisualElements` to overlay custom SkiaSharp drawing:\n\n```csharp\nmyChart.VisualElements = new[]\n{\n    new DrawnVisual\n    {\n        OnDraw = (canvas, chart) =>\n        {\n            canvas.DrawText(\"Hello!\", new SKPoint(100, 100), new SKPaint { Color = SKColors.Black });\n        }\n    }\n};\n```\n\n---\n\n## Server-Side / Console Chart Generation\n\nInstall only the core packages (no UI framework required):\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView\n```\n\nUse `SKCartesianChart`, `SKPieChart`, `SKPolarChart`, `SKGeoMap` — they all inherit from `InMemorySkiaSharpChart`\nand expose a `GetImage()` method that returns an `SKImage`:\n\n```csharp\nvar chart = new SKCartesianChart\n{\n    Width = 900, Height = 600,\n    Series = new ISeries[] { new LineSeries<int> { Values = new[] { 1, 2, 3 } } }\n};\n\n// Save to file:\nchart.SaveImage(\"output.png\");\n\n// Or get bytes for HTTP response:\nusing var image  = chart.GetImage();\nusing var data   = image.Encode(SKEncodedImageFormat.Png, 100);\nusing var stream = data.AsStream();\n```\n\n---\n\n## Multi-threading\n\nWhen modifying chart data from a background thread, always use a `lock`:\n\n```csharp\n// 1. Define a sync object in your ViewModel:\npublic object Sync { get; } = new object();\n\n// 2. Assign it to the chart control (XAML or code-behind):\n//    myChart.SyncContext = viewModel.Sync;\n\n// 3. Wrap all data mutations in the lock:\nlock (Sync)\n{\n    Values.Add(new ObservableValue(random.Next(0, 10)));\n    if (Values.Count > 200) Values.RemoveAt(0);\n}\n```\n\n---\n\n## Themes and Color Palettes\n\n```csharp\nLiveCharts.Configure(settings =>\n    settings\n        .AddDefaultTheme(theme =>\n            theme.OnInitialized(() =>\n            {\n                theme.AnimationsSpeed  = TimeSpan.FromMilliseconds(300);\n                theme.EasingFunction   = EasingFunctions.QuadraticOut;\n                theme.Colors           = ColorPalletes.MaterialDesign500;\n            })));\n```\n\nBuilt-in palettes: `MaterialDesign200`, `MaterialDesign500`, `MaterialDesign800`, `FluentDesign`, etc.\n\n---\n\n## Common Namespaces\n\n```csharp\nusing LiveChartsCore;                            // ISeries, IAxis, LiveCharts.Configure, etc.\nusing LiveChartsCore.Defaults;                   // ObservableValue, ObservablePoint, DateTimePoint, etc.\nusing LiveChartsCore.Kernel;                     // Coordinate, ChartEntityMetaData, IChartEntity\nusing LiveChartsCore.Measure;                    // ZoomAndPanMode, TooltipPosition, LegendPosition, etc.\nusing LiveChartsCore.SkiaSharpView;              // LineSeries, ColumnSeries, Axis, etc. (non-XAML)\nusing LiveChartsCore.SkiaSharpView.Painting;     // SolidColorPaint, LinearGradientPaint, etc.\nusing LiveChartsCore.SkiaSharpView.WPF;          // CartesianChart, PieChart (WPF controls)\nusing LiveChartsCore.SkiaSharpView.Avalonia;     // CartesianChart, PieChart (Avalonia controls)\nusing LiveChartsCore.SkiaSharpView.Maui;         // CartesianChart, PieChart (MAUI controls)\nusing LiveChartsCore.SkiaSharpView.SKCharts;     // SKCartesianChart, SKPieChart (server-side)\nusing SkiaSharp;                                 // SKColor, SKPoint, SKPaint, etc.\n```\n\n---\n\n## API Reference URL Pattern\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\nUse `latest` as the version for the most recent docs, or a specific version string.\n`{objectFullName}` uses CLI metadata naming (e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`).\n\nFull docs: `https://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}`\n\nWhere `{UIFramework}` ∈ `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`.\n\n---\n\n## Frequently Asked Questions\n\n**Q: My chart is blank / not showing.**  \nA: The chart control has no default size constraint. Set an explicit `Width` and `Height`, or ensure the\nparent layout does not collapse the control to zero size.\n\n**Q: Changes to my data don't update the chart.**  \nA: Use `ObservableCollection<T>` for the `Series` collection and the `Values` collection.\nFor property-level updates, implement `INotifyPropertyChanged` on your data class (or use `ObservableValue`).\n\n**Q: How do I use LiveCharts without SkiaSharp?**  \nA: Implement the Core drawing interfaces (`IDrawingContext`, etc.) and register your custom renderer.\nThe `VorticeSample` in the repository demonstrates this using DirectX11 via Vortice.Windows.\n\n**Q: Can I use LiveCharts in a Blazor Server app?**  \nA: The official package targets Blazor WASM. For server-side use, use `SKCartesianChart` to generate\nPNG/JPEG images on the server and serve them as `<img>` tags.\n\n**Q: How do I disable animations?**  \nA: Set `myChart.EasingFunction = null;` or `myChart.AnimationsSpeed = TimeSpan.Zero;`.\n"},"files":{".github/copilot-instructions.md":"# LiveCharts2 Copilot Instructions\n\nThis document helps coding agents work efficiently with the LiveCharts2 repository.\n\n## Repository Overview\n\nLiveCharts2 is a flexible, cross-platform charting library for .NET. It follows a layered architecture where:\n- **Core library** (`LiveChartsCore`) is platform-agnostic and handles all chart mathematics\n- **SkiaSharp backend** renders the charts using SkiaSharp\n- **Platform-specific views** provide UI controls for various frameworks (WPF, Avalonia, MAUI, Blazor, etc.)\n\n## Repository Structure\n\n```\nLiveCharts2/\n├── src/\n│   ├── LiveChartsCore/                    # Platform-agnostic core library\n│   │   ├── Kernel/                        # Core charting engine\n│   │   ├── Drawing/                       # Drawing abstractions\n│   │   ├── Motion/                        # Animation system\n│   │   ├── Measure/                       # Chart measurement logic\n│   │   └── [Series types]/                # Line, Bar, Pie, Scatter, etc.\n│   ├── skiasharp/                         # SkiaSharp rendering implementations\n│   │   ├── LiveChartsCore.SkiaSharp/      # Core SkiaSharp provider\n│   │   ├── LiveChartsCore.SkiaSharp.WPF/\n│   │   ├── LiveChartsCore.SkiaSharp.Avalonia/\n│   │   ├── LiveChartsCore.SkiaSharpView.Maui/\n│   │   ├── LiveChartsCore.SkiaSharpView.Blazor/\n│   │   └── [other platforms]/\n│   └── _Shared.Native/                    # Native platform interop\n├── samples/                               # Sample applications\n│   ├── ViewModelsSamples/                 # Shared ViewModels for all samples\n│   │   └── Index.cs                       # List of all sample paths\n│   ├── WPFSample/\n│   ├── AvaloniaSample/\n│   ├── MauiSample/\n│   ├── VorticeSample/                     # DirectX sample (core without SkiaSharp)\n│   └── [other platforms]/\n├── tests/\n│   ├── CoreTests/                         # Core unit tests using MSTest\n│   │   ├── ChartTests/                    # High-level chart tests\n│   │   ├── SeriesTests/                   # Series-specific tests\n│   │   ├── LayoutTests/                   # Layout tests\n│   │   ├── CoreObjectsTests/              # Core objects tests\n│   │   └── OtherTests/                    # Axes, events, etc.\n│   ├── SnapshotTests/                     # Snapshot/image comparison tests (net10.0)\n│   ├── UITests/                           # UI testing orchestrator\n│   │   └── Program.cs                     # Factos-based multi-platform test runner\n│   └── SharedUITests/                     # Shared UI tests (referenced by sample apps)\n│       ├── CartesianChartTests.cs\n│       ├── PieChartTests.cs\n│       ├── PolarChartTests.cs\n│       └── MapChartTests.cs\n├── docs/                                  # Documentation (Scriban templates)\n│   ├── samples/                           # Sample documentation templates\n│   ├── shared/                            # Reusable template fragments\n│   ├── cartesianChart/                    # Cartesian chart docs\n│   ├── piechart/                          # Pie chart docs\n│   └── polarchart/                        # Polar chart docs\n└── generators/                            # Code generators\n```\n\n## Key Architecture Concepts\n\n### 1. Layered Design\n- **LiveChartsCore**: Pure .NET, no UI dependencies, handles all calculations\n- **SkiaSharp Provider**: Implements `IDrawingProvider` to render using SkiaSharp\n- **Platform Views**: WPF/Avalonia/MAUI/etc. specific controls that host the renderer\n\n### 2. Multi-Platform Targeting\n\nCore projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) target:\n- `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **No mobile workloads required** to build the core library\n\n**Platform-specific view projects** (WPF, Avalonia, MAUI, etc.) have their own target framework requirements based on the platform.\n\n### 3. Sample Structure\n- **ViewModelsSamples**: Contains shared ViewModels used across all UI frameworks\n- **Index.cs**: Defines available samples as string paths (e.g., \"Lines/Basic\", \"Pies/Doughnut\")\n- Each platform sample project (WPF, Avalonia, etc.) references ViewModelsSamples and creates platform-specific views\n\n### 4. VorticeSample\nA special sample demonstrating how to use LiveChartsCore without SkiaSharp, using DirectX instead. This shows the core library is truly rendering-agnostic.\n\n## Building the Repository\n\n### Prerequisites\n- .NET SDK (see `global.json` for minimum version)\n- No workloads required for core projects\n- Platform-specific projects (MAUI, UNO, Avalonia Browser) require relevant workloads:\n  ```bash\n  dotnet workload install maui\n  dotnet workload install wasm-tools\n  ```\n\n### Build Methods\n\n#### Quick Build - Core Projects\n```bash\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n```\n\n#### Quick Build - Platform Views\n```bash\n# Build specific platform views (recommended for development)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n```\n\n#### Full Build (Windows)\n```bash\n# Build platform-specific projects individually\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj\n# Or use platform-specific solution files (see below)\n```\n\n#### Build with Solution Files\n```bash\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n```\n\n### Common Build Issues and Workarounds\n\n#### Issue: Missing workload errors (NETSDK1147)\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\n```\n\n**Context**: This error occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require workloads.\n\n**Workaround Options:**\n1. Install the required workload: `dotnet workload install maui`\n2. Build only the platform you need (e.g., WPF or Avalonia desktop on Windows)\n3. Use platform-specific solution files that don't include all targets\n\n#### Issue: SkiaSharp version conflicts\nThe project supports multiple SkiaSharp versions:\n- `MinSkiaSharpVersion`: 2.88.9 (minimum supported)\n- `LatestSkiaSharpVersion`: 3.119.0 (default for GPU support)\n\nDefined in `Directory.Build.props`.\n\n#### Issue: Multi-targeting complexity\nWhen building fails for specific targets, you can:\n1. Use `-f` to target specific framework: `dotnet build -f net8.0`\n2. Edit `TargetFrameworks` in .csproj to focus on needed platforms\n\n## Testing\n\n### Unit Tests (Core Library)\n\n**Location**: `tests/CoreTests/`\n\n**Framework**: MSTest with coverlet for code coverage\n\n**Run Tests:**\n```bash\ndotnet test tests/CoreTests/\n\n# Run for specific framework\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run with coverage\ndotnet test tests/CoreTests/ --collect:\"XPlat Code Coverage\"\n```\n\n**Test Structure:**\n- `ChartTests/`: High-level chart functionality\n- `SeriesTests/`: Tests for Line, Bar, Pie, Scatter, Heat, etc.\n- `LayoutTests/`: Stack and table layouts\n- `CoreObjectsTests/`: Transitions, colors, labels\n- `OtherTests/`: Axes, events, data providers, visual elements\n- `MockedObjects/`: Test helpers and mocks\n- `TestsInitializer.cs`: MSTest assembly initialization\n\n**Important**: Tests use `CoreMotionCanvas.IsTesting = true` to disable animations during testing.\n\n### Snapshot Tests\n\n**Location**: `tests/SnapshotTests/`\n\n**Framework**: MSTest, targets `net10.0`\n\nSnapshot tests render charts to images and compare them against stored reference snapshots. They are run in CI on Windows.\n\n**Run Tests:**\n```bash\ndotnet test tests/SnapshotTests/\n```\n\n### UI Testing\n\n**Location**: `tests/UITests/` (orchestrator) and `tests/SharedUITests/` (shared tests)\n\n**Framework**: [Factos](https://github.com/beto-rodriguez/Factos) - A multi-platform UI testing framework\n\n**How it works:**\n1. Shared UI tests are defined in `tests/SharedUITests/` (shared project)\n2. Each sample application references `SharedUITests` \n3. The `tests/UITests/Program.cs` orchestrator:\n   - Starts various sample applications (Avalonia, WPF, MAUI, Blazor, etc.)\n   - Connects to them via Factos\n   - Runs the shared UI tests against each platform\n4. Tests ensure charts render correctly across all supported UI frameworks\n\n**Test Coverage:**\n- `CartesianChartTests.cs`: Cartesian chart rendering and behavior\n- `PieChartTests.cs`: Pie/Doughnut chart tests\n- `PolarChartTests.cs`: Polar chart tests  \n- `MapChartTests.cs`: Map chart tests\n- `AvaloniaTests.cs`: Avalonia-specific tests\n\n**Running UI Tests:**\n```bash\n# Run UI tests (requires sample apps to be built)\ndotnet run --project tests/UITests/\n\n# Run against specific platform (see Program.cs for options)\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\ndotnet run --project tests/UITests/ -- --select maui --test-env \"tf=net10.0-windows10.0.19041.0\"\n```\n\n**Important Notes:**\n- UI testing requires the Factos package\n- Each platform may need specific prerequisites (emulators for mobile, browsers for web)\n- In Debug mode, tests use project references; in Release mode, they use NuGet packages\n- The orchestrator supports testing against multiple target frameworks\n- Mobile platforms (Android, iOS) require running emulators\n\n**Build Configuration for UI Tests:**\nUI test configuration is managed through MSBuild properties. When `UITesting=true` is set, samples include the shared UI test project.\n\n## Running Samples\n\n### Sample Applications\nEach platform has its own sample application that references `ViewModelsSamples`:\n\n```bash\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\n### Adding New Samples\n1. Add ViewModel class in `samples/ViewModelsSamples/[Category]/[Name].cs`\n2. Add path to `samples/ViewModelsSamples/Index.cs`\n3. Create platform-specific view files in each sample project (WPF, Avalonia, etc.)\n\n### Sample Platforms Reference\n\nThe following platforms each need a view for every sample. **ConsoleSample** and **VorticeSample** are excluded — they don't follow this pattern.\n\n| Platform | Root path | View file(s) | Base class | LVC namespace (xmlns:lvc) |\n|---|---|---|---|---|\n| **Avalonia** | `samples/AvaloniaSample/[Category]/[Name]/` | `View.axaml` + `View.axaml.cs` | `UserControl` | `using:LiveChartsCore.SkiaSharpView.Avalonia` |\n| **WPF** | `samples/WPFSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` | `clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF` |\n| **MAUI** | `samples/MauiSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `ContentPage` | `clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui` |\n| **WinUI** | `samples/WinUISample/WinUISample/Samples/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` (`sealed partial`) | `using:LiveChartsCore.SkiaSharpView.WinUI` |\n| **WinForms** | `samples/WinFormsSample/[Category]/[Name]/` | `View.cs` + `View.Designer.cs` + `View.resx` | `UserControl` (`partial`) | N/A — code-only |\n| **Blazor** | `samples/BlazorSample/Pages/[Category]/[Name]/` | `View.razor` | N/A — Razor component | `@using LiveChartsCore.SkiaSharpView.Blazor` |\n| **EtoForms** | `samples/EtoFormsSample/[Category]/[Name]/` | `View.cs` | `Panel` (non-partial) | N/A — code-only |\n| **UnoPlatform** | *(no separate files)* | Reuses `WinUISample` views via reflection | — | — |\n\n**Key facts for each platform:**\n\n- **All XAML platforms (Avalonia, WPF, MAUI, WinUI)** use `Activator.CreateInstance` with the pattern `{Platform}.{Category}.{Name}.View` to load views — so the **C# namespace must exactly match** `{PlatformPrefix}.{Category}.{Name}` and the class must be named `View`.\n- **WinForms** and **EtoForms** use the same reflection pattern. The view class must be `partial class View : UserControl` (WinForms) or `class View : Panel` (EtoForms).\n- **Blazor** uses Razor's `@page \"/{Category}/{Name}\"` directive for routing. The nav menu reads `ViewModelsSamples.Index.Samples` automatically.\n- **UnoPlatform** (`samples/UnoPlatformSample/`) loads views from the `WinUISample` assembly — no separate files are needed.\n\n**XAML DataContext / BindingContext patterns:**\n\n```xml\n<!-- Avalonia (View.axaml) -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\"\n             x:DataType=\"vms:ViewModel\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- WPF (View.xaml) -->\n<UserControl xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- MAUI (View.xaml) — ContentPage + XamlCompilation attribute on code-behind -->\n<ContentPage xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\"\n             x:DataType=\"vms:ViewModel\">\n    <ContentPage.BindingContext><vms:ViewModel/></ContentPage.BindingContext>\n</ContentPage>\n\n<!-- WinUI (View.xaml) — sealed partial class -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.WinUI\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n```\n\n**Code-only platforms (WinForms / EtoForms)** typically instantiate the ViewModel directly or inline the data:\n\n```csharp\n// WinForms — partial class View : UserControl\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nchart.Location = new System.Drawing.Point(0, 0);\nchart.Size = new System.Drawing.Size(50, 50);\nchart.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;\nControls.Add(chart);\n\n// EtoForms — class View : Panel (non-partial, no Designer file)\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nContent = new DynamicLayout(chart);\n```\n\n**WinForms `View.Designer.cs`** is always a minimal boilerplate — copy from any existing sample, just update the namespace.\n\n**UI-testing accessor** — most XAML views expose a `Chart` property under `#if UI_TESTING` for the Factos test runner:\n\n```csharp\n// XAML platforms (WPF, Avalonia, MAUI, WinUI)\n#if UI_TESTING\n    public SomeChartType Chart => chartNamedInXaml;\n#endif\n\n// EtoForms / WinForms\npublic SomeChartType Chart;  // public field, always present\n```\n\n**Blazor** exposes the chart via `@ref`:\n```razor\n<CartesianChart @ref=\"Chart\" .../>\n@code { public CartesianChart Chart; }\n```\n\n## Code Style and Conventions\n\n### Editor Config\nThe repository uses `.editorconfig` based on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with exceptions.\n\n**Key Style Rules:**\n- **Indentation**: 4 spaces\n- **Line endings**: LF, insert final newline\n- **Braces**: New line before open brace (Allman style)\n- **var usage**: Use `var` freely (explicitly allowed)\n- **Single-line if**: Allowed and preferred when line is short\n- **Naming**:\n  - Private/internal fields: `_camelCase`\n  - Static private fields: `s_camelCase`\n  - Constants: `PascalCase`\n- **Using directives**: Outside namespace\n\n### File Naming\n**Critical for auto-generated documentation:**\n- File names MUST match the class name exactly\n- `public class Hello` → `Hello.cs`\n- `public class Hello<T>` → `Hello.cs` (ignore generics)\n- Generic and non-generic with same name → same file (only if inheritance relationship)\n\n### Important Constants\nDefined in `Directory.Build.props`:\n- `LiveChartsVersion`: Current version (2.0.0-rc6.1)\n- `MinSkiaSharpVersion`: 2.88.9\n- `LatestSkiaSharpVersion`: 3.119.0\n- `LangVersion`: 14.0 (C# 14)\n\n## Build Configuration Properties\n\n### Rendering Settings\nRendering settings are configured via MSBuild properties:\n- `GPU`: Enable/disable GPU acceleration\n- `VSYNC`: Enable/disable vertical sync\n- `FPS`: Frame rate (10, 20, 30, 45, 60, 75, 90, 120)\n- `Diagnose`: Enable diagnostic mode\n\nThese create conditional compilation symbols for testing different rendering modes.\n\n### Development Flags\nIn `Directory.Build.props`:\n- `UseNuGetForSamples`: Use NuGet packages vs project references (default: false)\n- `UseNuGetForGenerator`: Use NuGet generator package (default: true)\n\n## CI/CD\n\n### GitHub Actions Workflows\n\n#### 1. Main CI (`livecharts.yml`)\n- Triggers: Pull requests\n- Runs on: `windows-2025` (pack/test), `ubuntu-24.04` (Linux/browser), `macos-26` (Mac/iOS)\n- Steps:\n  1. **Pack**: Builds NuGet packages for all platform libraries (core, skiasharp, WPF, Avalonia, MAUI, Blazor, WinUI, UNO, WinForms, Eto)\n  2. **test-core**: Runs `CoreTests` on `net8.0` and `net462`\n  3. **test-snapshot**: Runs `SnapshotTests`\n  4. **test-windows/linux/mac/browser/android/ios**: Runs Factos UI tests for each platform\n- On tag pushes (after tests pass): publishes packages to NuGet.org\n\n#### 2. Publish (`publish.yml`)\n- Handles NuGet package publishing\n\n**Note**: The CI uses NuGet packages (not project references) when running UI tests in Release mode.\n\n## Common Development Workflows\n\n### Adding a New Series Type\n1. Create series class in `src/LiveChartsCore/[SeriesType]/`\n2. Implement series interfaces (`ISeries`, etc.)\n3. Create SkiaSharp drawable in `src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/`\n4. Add tests in `tests/CoreTests/SeriesTests/`\n5. Create sample ViewModel in `samples/ViewModelsSamples/`\n6. Update `samples/ViewModelsSamples/Index.cs`\n\n### Adding Platform Support\n1. Create new project in `src/skiasharp/LiveChartsCore.SkiaSharpView.[Platform]/`\n2. Reference `LiveChartsCore.SkiaSharp` project\n3. Create platform-specific control classes\n4. Add shared code to `_Shared/` if applicable\n5. Create sample application in `samples/[Platform]Sample/`\n6. Add platform-specific solution file\n\n### Updating Documentation\n\n**Important**: Documentation files in the `docs/` folder are **Scriban templates**, not final markdown files.\n\n**How it works:**\n1. Template files are compiled by an external (non-open-source) repository\n2. Templates use [Scriban](https://github.com/scriban/scriban) - a fast, powerful, and lightweight text templating language\n3. Scriban supports custom functions and expressions embedded in the markdown\n\n**Common Scriban expressions you'll find:**\n\n**File inclusion** - Renders content from source files:\n```\n{{~ render \"~/../samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs\" ~}}\n{{~ render \"~/../samples/MauiSample/MauiProgram.cs\" ~}}\n{{~ render \"~/../samples/{samples_folder}/Events/Cartesian{view_extension}\" ~}}\n```\n\n**Conditionals** - Platform-specific content:\n```\n{{~ if xaml ~}}\n  Content for XAML platforms (WPF, Avalonia, UNO, WinUI, MAUI)\n{{~ end ~}}\n\n{{~ if winforms ~}}\n  Content specific to WinForms\n{{~ end ~}}\n```\n\n**Variables** - Dynamic content:\n```\n{{ website_url }}/docs/{{ platform }}/{{ version }}/About\n{{ assets_url }}/docs/{{ unique_name }}/result.gif\n{{ name | to_title_case }}\n{{ edit_source | replace_local_to_server }}\n```\n\n**Loops** - Iterate over collections:\n```\n{{~ for r in related_to ~}}\n  <a href=\"{{ compile this r.url }}\">{{ r.name }}</a>\n{{~ end ~}}\n```\n\n**Template structure:**\n- `docs/samples/[category]/[name]/template.md` - Sample documentation templates\n- `docs/shared/*.md` - Reusable template fragments included via `{{ render \"~/shared/...\" }}`\n- `docs/piechart/`, `docs/cartesianChart/`, etc. - Feature documentation with templates\n\n**When editing docs:**\n- Always edit the `.md` files as Scriban templates\n- Test template syntax (though final compilation happens externally)\n- Use `{{~ ~}}` syntax to strip whitespace around expressions\n- File paths in `render` are relative to the template location (use `~/../` for repo root)\n\n## Important Notes for Coding Agents\n\n### Do's\n- ✅ Use project references during development (not NuGet packages)\n- ✅ Follow the exact file naming convention (critical for docs)\n- ✅ Run tests after changes to core or series logic\n- ✅ Use platform-specific solution files for focused development\n- ✅ Consult `CONTRIBUTING.md` for detailed style guide\n- ✅ Use shared code in `_Shared/` folders when adding cross-platform features\n\n### Don'ts\n- ❌ Don't break multi-platform support when modifying core projects\n- ❌ Don't add platform-specific code to `LiveChartsCore` (keep it agnostic)\n- ❌ Don't ignore `.editorconfig` warnings\n- ❌ Don't remove or modify working tests without good reason\n- ❌ Don't add new dependencies without checking compatibility across all target frameworks\n\n### Special Considerations\n- The library supports .NET Framework 4.6.2 - maintain compatibility\n- SkiaSharp is abstracted - core library should work with other rendering engines\n- Animation system (`Motion/`) is critical - changes require extensive testing\n- Multi-threading: Chart updates can come from any thread; proper synchronization is essential\n\n## Quick Reference Commands\n\n```bash\n# === Building ===\n# Build core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Build platform-specific projects\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# === Install Workloads (for platform-specific projects) ===\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n\n# Check installed workloads\ndotnet workload list\n\n# === Testing ===\n# Run core unit tests\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run snapshot tests\ndotnet test tests/SnapshotTests/\n\n# Run UI tests (requires sample apps to build)\ndotnet run --project tests/UITests/\n\n# Run UI tests for specific platform\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n\n# === Running Samples ===\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n\n# === Troubleshooting ===\n# Clean build artifacts\ndotnet clean\nfind . -type d -name \"bin\" -o -name \"obj\" | xargs rm -rf\n\n# Restore packages\ndotnet restore\n\n# Check for workload issues\ndotnet workload restore --skip-sign-check\n```\n\n## Documented Errors and Workarounds\n\nThis section documents actual errors encountered when working with this repository and their solutions.\n\n### Error 1: NETSDK1147 - Missing Workloads\n\n**Error Message:**\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\nTo install these workloads, run the following command: dotnet workload restore\n```\n\n**Context**: This occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require any workloads.\n\n**Workarounds:**\n\n**Option 1: Install Required Workloads**\n```bash\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n```\n\n**Option 2: Build Platform-Specific Projects that don't need workloads**\n```bash\n# Build only WPF (Windows only)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\n\n# Build only Avalonia desktop (cross-platform)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\n```\n\n### Error 2: Visual Studio Component Required\n\n**Error Message:**\n```\nUnhandled exception: The imported file \"$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v$(VisualStudioVersion)/CodeSharing/Microsoft.CodeSharing.Common.Default.props\" does not exist and appears to be part of a Visual Studio component.\n```\n\n**Context**: Appears when running `dotnet workload restore` on non-Windows systems or when Visual Studio is not installed.\n\n**Why it happens**: The `src/skiasharp/_Shared.WinUI/_Shared.WinUI.shproj` shared project requires Visual Studio components that are Windows-specific.\n\n**Workaround**: This error can be ignored if you're not building WinUI projects. The workload installation succeeds despite this error. If you need to build WinUI:\n- Use Windows with Visual Studio 2022 installed\n- Use `msbuild` instead of `dotnet build` for WinUI projects\n\n### Error 3: Ambiguous Argument with Git\n\n**Error Message:**\n```\nfatal: ambiguous argument 'origin/branch-name': unknown revision or path not in the working tree.\n```\n\n**Context**: After fetching a branch with `git fetch origin branch-name`, trying to reference it as `origin/branch-name`.\n\n**Why it happens**: Git fetch stores the ref as `FETCH_HEAD`, not as a trackable remote branch.\n\n**Solution**: Use `FETCH_HEAD` or create a local tracking branch:\n```bash\n# Option 1: Use FETCH_HEAD directly\ngit log FETCH_HEAD\n\n# Option 2: Create tracking branch\ngit fetch origin main\ngit checkout -b main --track origin/main\n\n# Option 3: Fetch with branch creation\ngit fetch origin main:main\n```\n\n### Error 4: Package Not Found During Build\n\n**Context**: Sample applications may fail to build if NuGet packages are not found.\n\n**Why it happens**: `UseNuGetForSamples` flag in `Directory.Build.props` controls whether samples use project references or NuGet packages.\n\n**Solution**: Ensure you're using project references during development:\n```xml\n<!-- In Directory.Build.props -->\n<UseNuGetForSamples>false</UseNuGetForSamples>\n```\n\nOr restore NuGet packages if building from packages:\n```bash\ndotnet restore\n```\n\n### Error 5: Strong Name Assembly Conflicts\n\n**Context**: When building for .NET Framework 4.6.2, you may encounter assembly version conflicts.\n\n**Why it happens**: .NET Framework uses strong-named assemblies, and SkiaSharp has different versioning.\n\n**Referenced Issue**: https://github.com/mono/SkiaSharp/issues/3153\n\n**Solution**: The project is configured to handle this, but if you encounter issues:\n1. Clean the solution: `dotnet clean`\n2. Delete `bin` and `obj` folders\n3. Restore and rebuild: `dotnet restore && dotnet build`\n\n### Error 6: Test Build Failures on CI\n\n**Context**: UI tests may fail with target framework mismatches in CI.\n\n**Solution**: The UI test infrastructure uses special MSBuild properties:\n- `TestBuildTargetFramework`: Override target framework for test builds\n- `IsTestBuild`: Flag to indicate test build\n- `UITesting`: Flag to include shared UI tests\n\nExample from `tests/UITests/Program.cs`:\n```csharp\nMSBuildArg tf_n10w = new(\"TestBuildTargetFramework\", \"net10.0-windows\");\nMSBuildArg isTest = new(\"IsTestBuild\", \"true\");\n```\n\n## Troubleshooting\n\n### Problem: Can't build platform-specific projects - workload errors\n**Solution**: Install the required workload for the platform you're targeting (e.g., `dotnet workload install maui`). Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) build without any workloads.\n\n### Problem: SkiaSharp errors\n**Solution**: Check SkiaSharp version in `Directory.Build.props`, ensure NuGet restore succeeded\n\n### Problem: Tests fail with animation issues\n**Solution**: Verify `CoreMotionCanvas.IsTesting = true` in test initialization\n\n### Problem: Sample won't run\n**Solution**: Ensure platform-specific dependencies are installed (e.g., .NET Desktop Runtime for WPF)\n\n### Problem: Generator errors\n**Solution**: Check `UseNuGetForGenerator` setting and ensure LiveChartsGenerators package/project is available\n\n## Issue Reproduction & Fix Workflow\n\nWhen picking up a GitHub issue (reproduce → diagnose → fix → regression test → PR),\nfollow the canonical workflow at [`.claude/skills/repro-and-fix/SKILL.md`](../.claude/skills/repro-and-fix/SKILL.md).\nThat doc is the single source of truth for both Claude Code and Copilot Coding Agent —\nkeep edits there, not duplicated here.\n\nQuick reference for the dev-loop hooks the workflow relies on:\n\n- **`LVC_SAMPLE=<sample-path>`** — XAML samples (Avalonia / WPF / WinUI / MAUI / Uno) auto-navigate to the named sample on launch, e.g. `LVC_SAMPLE=VisualTest/Issue1986Repro`. Skips manual UI navigation for repros.\n- **`LVC_SCREENSHOT=<png-path>`** — Avalonia / WPF / WinUI samples render the main window to PNG via `RenderTargetBitmap` shortly after activation and exit. Captures scale to physical pixels on HiDPI.\n- **`LVC_SCREENSHOT_DELAY_MS=<ms>`** — overrides the 3 s default settle delay before the in-app screenshot is taken (use on slower CI hosts).\n- **`.claude/scripts/capture-window.{ps1,-macos.sh,-linux.sh}`** — per-OS PrintWindow / `screencapture` / `grim` fallbacks for platforms without an in-app capture path (MAUI, Uno).\n\nRepro views live under `samples/AvaloniaSample/VisualTest/Issue<N>Repro/` (or\nthe equivalent under whichever platform sample fits the bug). Their code-behind\nexposes helpers (e.g. `FindTemplatedGaugeSeries()`) that Factos UI tests call\ndirectly. Factos and `LVC_SAMPLE` navigate by path and don't need the repro\nregistered in `samples/ViewModelsSamples/Index.cs` — **do not commit changes\nto that file for a repro view.** It's shared across every platform sample,\nso a single-platform repro entry will crash the load on the other platforms.\n\n## Resources\n\n- **Main Documentation**: https://livecharts.dev\n- **Contributing Guide**: `CONTRIBUTING.md`\n- **Repository**: https://github.com/Live-Charts/LiveCharts2\n- **Code of Conduct**: `CODE_OF_CONDUCT.md`\n- **License**: MIT (see `LICENSE`)\n\n## Version Information\n\n- **Current Version**: 2.0.0-rc6.1 (Release Candidate)\n- **C# Language Version**: 14.0\n- **SkiaSharp**: 2.88.9 (min) to 3.119.0 (latest)\n- **Target Frameworks**: `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows` (core); plus platform-specific targets for view projects\n","CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nLiveCharts2 is a cross-platform .NET charting library with a layered architecture:\n- **`src/LiveChartsCore/`** — Platform-agnostic core (math, series, axes, animation). No UI dependencies. Targets `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp/`** — SkiaSharp rendering backend implementing the core drawing abstractions.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp.{Platform}/`** — Platform-specific view controls (WPF, Avalonia, MAUI, Blazor, WinForms, WinUI, Eto, UNO).\n- **`generators/LiveChartsGenerators/`** — Roslyn source generator for boilerplate reduction.\n\n## Build Commands\n\n```bash\n# Core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Platform-specific (examples)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n\n# Target a specific framework when multi-targeting causes issues\ndotnet build -f net8.0\n```\n\nMAUI/WASM projects require workloads: `dotnet workload install maui --skip-sign-check` / `dotnet workload install wasm-tools --skip-sign-check`. Core and desktop projects (WPF, Avalonia, WinForms) do not.\n\n## Testing\n\n```bash\n# Unit tests (MSTest) — primary test suite\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Snapshot tests (image comparison, net10.0 only)\ndotnet test tests/SnapshotTests/\n\n# UI tests via Factos (requires sample apps built)\ndotnet run --project tests/UITests/\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n```\n\nTests use `CoreMotionCanvas.IsTesting = true` to disable animations. UI tests are defined in `tests/SharedUITests/` (shared project) and run against each platform via the Factos orchestrator in `tests/UITests/`.\n\n## Running Samples\n\n```bash\ndotnet run --project samples/WPFSample/WPFSample.csproj\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\nSample ViewModels live in `samples/ViewModelsSamples/` and are shared across all platform samples. Each platform sample creates its own views. `samples/ViewModelsSamples/Index.cs` lists all available sample paths.\n\n## Architecture Details\n\n**Rendering pipeline**: Data → Core series engine (measurement, layout) → SkiaSharp drawables → Platform-native surface. The core is rendering-agnostic — `samples/VorticeSample/` demonstrates using DirectX instead of SkiaSharp.\n\n**Shared projects**: `src/skiasharp/_Shared/`, `_Shared.Xaml/`, `_Shared.WinUI/` contain code shared across platform views via MSBuild linked files (configured in `build/*.Build.props`).\n\n**Code generation**: `LiveChartsGenerators` is a Roslyn analyzer/generator. Controlled by `UseNuGetForGenerator` in `Directory.Build.props` (default: `true` = NuGet package).\n\n**Key build properties** (`Directory.Build.props`):\n- `UseNuGetForSamples`: `false` during development (project references), `true` for CI/release\n- `UITesting`: set to `true` to include shared UI tests in sample projects\n- `GPU`, `VSYNC`, `Diagnose`: rendering mode overrides for testing\n\n## Code Style\n\nBased on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with these exceptions (enforced via `.editorconfig`):\n- `var` is freely used everywhere (not restricted to explicit right-hand types)\n- Single-line `if` without braces is preferred when the line is short; break long lines rather than adding braces\n- Private fields: `_camelCase`, static private: `s_camelCase`, constants: `PascalCase`\n- 4-space indentation, Allman braces, LF line endings\n\n**File naming is critical**: file names must match the class name exactly (`Hello<T>` → `Hello.cs`). Generic and non-generic with the same name go in the same file (only when related by inheritance). This is required for automatic documentation generation.\n\n## Key Constraints\n\n- **Never add platform-specific code to `LiveChartsCore`** — it must remain platform-agnostic\n- **.NET Framework 4.6.2 compatibility must be maintained** (strong-named assemblies, `LiveCharts.snk`)\n- **SkiaSharp version range**: min 2.88.9, latest 3.119.0 — changes must respect both\n- **C# 14.0** language version\n- Animation system (`Motion/`) is core infrastructure — changes require extensive testing\n- Chart updates can arrive from any thread; synchronization is essential\n\n## Additional Documentation\n\nSee `.github/copilot-instructions.md` for extended guidance including: sample platform view patterns (XAML/code-only/Blazor), adding new series types, CI/CD workflow details, and documented build errors with workarounds.\n","llms.txt":"# LiveCharts2\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET built on top of SkiaSharp for rendering; it supports Cartesian, Pie, Polar, and GeoMap chart types with smooth, automatic animations. The library uses a layered architecture separating a platform-agnostic Core from a SkiaSharp-based Renderer and platform-specific Views (WPF, Avalonia, MAUI, Blazor, etc.), so adding a new platform requires minimal effort. LiveCharts2 targets .NET Framework 4.6.2, .NET Standard 2.0, and modern .NET, and uses `INotifyPropertyChanged`/`INotifyCollectionChanged` for zero-boilerplate automatic chart updates.\n\n> **⚠️ Important: This is LiveCharts v2. Do NOT use v0 syntax.**\n> The legacy v0 (`LiveCharts` / `LiveCharts.Wpf` NuGet packages) is obsolete and has a completely different API.\n> v0 source and samples: https://github.com/Live-Charts/Live-Charts\n> Always use the v2 packages listed below and the v2 documentation at https://livecharts.dev.\n\n## Supported UI Frameworks\n\n- **MAUI** — `LiveChartsCore.SkiaSharpView.Maui` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.maui\n- **Uno Platform (WinUI)** — `LiveChartsCore.SkiaSharpView.Uno.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.Uno.WinUI\n- **Avalonia** — `LiveChartsCore.SkiaSharpView.Avalonia` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.avalonia\n- **WPF** — `LiveChartsCore.SkiaSharpView.WPF` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.wpf\n- **WinForms** — `LiveChartsCore.SkiaSharpView.WinForms` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.winforms\n- **WinUI** — `LiveChartsCore.SkiaSharpView.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.winui\n- **Blazor (WASM)** — `LiveChartsCore.SkiaSharpView.Blazor` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.blazor\n- **Eto.Forms** — `LiveChartsCore.SkiaSharpView.Eto` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.eto\n\n## URL Templates\n\n### API Reference\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\n- `{objectFullName}` follows CLI (Common Language Infrastructure) metadata naming conventions, e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `{LiveChartsVersion}`: use `latest` for the latest version, or a specific version string (e.g. `2.0.0-rc6.1`)\n- Full list of available versions: `https://livecharts.dev/docs/{UIFramework}/list`\n  - `{UIFramework}` is one of: `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`\n\n**Examples:**\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.Avalonia.PieChart`\n\n### Documentation & Examples\n\n```\nhttps://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}\n```\n\n`{UIFramework}` and `{LiveChartsVersion}` are as described above.\n\nAvailable `{ArticleName}` values:\n\n**Overview**\n- `Overview.Installation`\n- `Overview.How%20it%20works`\n- `Overview.Automatic%20updates`\n- `Overview.Mappers`\n- `Overview.Paints`\n- `Overview.Animations`\n\n**Cartesian Chart**\n- `CartesianChart.Cartesian%20chart%20control`\n- `CartesianChart.Axes%20properties`\n- `CartesianChart.Tooltips`\n- `CartesianChart.Legends`\n- `CartesianChart.Line%20series%20properties`\n- `CartesianChart.Column%20series%20properties`\n- `CartesianChart.Scatter%20series%20properties`\n- `CartesianChart.Step%20line%20series%20properties`\n- `CartesianChart.Heat%20series%20properties`\n- `CartesianChart.Candle%20sticks%20series%20properties`\n- `CartesianChart.Stacked%20line%20series%20properties`\n- `CartesianChart.Stacked%20column%20series%20properties`\n- `CartesianChart.Stacked%20step%20line%20series%20properties`\n- `CartesianChart.Box%20series%20properties`\n\n**Pie Chart**\n- `PieChart.Pie%20chart%20control`\n- `PieChart.Pie%20series`\n- `PieChart.Gauges`\n\n**Polar Chart**\n- `PolarChart.Polar%20chart%20control`\n- `PolarChart.Polar%20line%20series`\n\n**GeoMap**\n- `GeoMap.GeoMap%20control`\n- `GeoMap.Heat%20land%20series`\n\n**About**\n- `About.About%20this%20samples`\n\n**Samples**\n- `samples.lines.basic`\n- `samples.lines.straight`\n- `samples.lines.area`\n- `samples.lines.custom`\n- `samples.lines.custompoints`\n- `samples.lines.autoupdate`\n- `samples.lines.xy`\n- `samples.lines.zoom`\n- `samples.steplines.basic`\n- `samples.stackedArea.basic`\n- `samples.stackedArea.stepArea`\n- `samples.bars.basic`\n- `samples.bars.withBackground`\n- `samples.bars.custom`\n- `samples.bars.spacing`\n- `samples.bars.layered`\n- `samples.bars.rowsWithLabels`\n- `samples.bars.delayedAnimation`\n- `samples.bars.race`\n- `samples.stackedBars.basic`\n- `samples.stackedBars.groups`\n- `samples.pies.basic`\n- `samples.pies.pushout`\n- `samples.pies.doughnut`\n- `samples.pies.outlabels`\n- `samples.pies.custom`\n- `samples.pies.icons`\n- `samples.pies.nightingaleRose`\n- `samples.pies.nested`\n- `samples.pies.gauge1`\n- `samples.pies.gauge2`\n- `samples.pies.gauge3`\n- `samples.pies.gauge4`\n- `samples.pies.gauge5`\n- `samples.pies.angularGauge`\n- `samples.error.basic`\n- `samples.box.basic`\n- `samples.scatter.basic`\n- `samples.scatter.bubbles`\n- `samples.scatter.custom`\n- `samples.financial.basicCandlesticks`\n- `samples.heat.basic`\n- `samples.polar.basic`\n- `samples.polar.radialArea`\n- `samples.polar.coordinates`\n- `samples.maps.world`\n- `samples.events.tutorial`\n- `samples.events.addPointOnClick`\n- `samples.axes.labelsFormat`\n- `samples.axes.labelsFormat2`\n- `samples.axes.multiple`\n- `samples.axes.shared`\n- `samples.axes.style`\n- `samples.axes.crosshairs`\n- `samples.axes.dateTimeScaled`\n- `samples.axes.timeSpanScaled`\n- `samples.axes.matchScale`\n- `samples.axes.logarithmic`\n- `samples.axes.customSeparatorsInterval`\n- `samples.axes.paging`\n- `samples.general.multiThreading`\n- `samples.general.realTime`\n- `samples.general.sections`\n- `samples.general.chartToImage`\n- `samples.general.visualElements`\n- `samples.general.visibility`\n- `samples.general.nullPoints`\n- `samples.general.customTooltips`\n- `samples.general.customLegends`\n- `samples.general.mapPoints`\n- `samples.general.drawOnCanvas`\n- `samples.general.conditionalDraw`\n- `samples.general.scrollable`\n- `samples.design.linearGradients`\n- `samples.design.radialGradients`\n- `samples.design.strokeDashArray`\n",".claude/skills/render-chart/SKILL.md":"---\nname: render-chart\ndescription: Use when the user asks to render, visualize, plot, or \"show me a chart of\" any kind of series data (line, column, row, scatter, stacked, candlestick, box, pie, polar, heat). Renders via the `lvc` CLI from a JSON spec — inline in your reply for simple charts you need to read, or in a new terminal window for interactive / color-dependent ones (heat maps, pies with many slices, anything with > 3 series the user wants to explore).\n---\n\n# render-chart\n\nThe user wants to *see* data as a chart. You have access to a renderer (`lvc`)\nthat writes LiveCharts to a terminal. Pick the right mode for the situation,\ninstall the tool if it's missing, and either inline the result in your reply\nor hand the user a live window.\n\n## Decision: inline vs live window\n\n| Situation | Mode | Why |\n| --- | --- | --- |\n| ≤ 3 series, line / column / row / stacked-bar / scatter, you need to *verify* the shape | `--no-color` inline | Plain Braille glyphs render in a fenced code block. You can read it; the user sees it. |\n| User said \"open this in a new window\" / \"let me play with it\" / \"zoom into this\" | `--live` in a new terminal | Interactive Sixel + mouse hover + wheel zoom + click-drag pan. The user explores; you can't read the result, so don't pretend to. |\n| Heat map | `--live` in a new terminal | Heat reads the gradient by color. Strip color and it's an undifferentiated blob. |\n| Pie with > 4 slices | `--live` in a new terminal | Outer labels collide and Pushout gaps stop reading at small canvas sizes. |\n| Anything where the *meaning* depends on color (gradient encodes magnitude, similar curves only separable by hue) | `--live` in a new terminal | Plain mode can't carry color information — see [[reference_claude_code_cli_ansi_passthrough]]. |\n| User asks to \"compare these two/three series\" with simple shapes | `--no-color` inline | Single bar series stays Braille; multi-bar uses textures; line series get end-of-line labels. Distinguishable without color. |\n\n**Default to `--no-color` inline** when you can read the chart — it keeps the\nconversation flowing and you can describe what's in it. Reserve `--live` for\nwhen there's genuinely no way to convey the information in monochrome glyphs.\n\n## Step 1 — make sure dotnet is installed\n\n```sh\ndotnet --version\n```\n\nIf that errors, the user needs the .NET 8 SDK or runtime. Point them at\n<https://dotnet.microsoft.com/download> and stop — don't try to install it\nfor them (admin install, varies per OS).\n\n## Step 2 — install `lvc` as a global tool (once)\n\n```sh\ndotnet tool install -g LiveChartsCore.Console.Cli\n```\n\nIf they already have it, this errors with \"already installed\" — that's fine.\nUpdate with `dotnet tool update -g LiveChartsCore.Console.Cli`.\n\nAfter install, `lvc` is on the user's PATH. Verify with:\n\n```sh\nlvc --json '{\"kind\":\"line\",\"series\":[{\"values\":[1,2,3,2,1]}]}' --no-color\n```\n\nYou should see a small Braille line chart in stdout.\n\n## Step 3 — write the JSON spec\n\nPass via `--json '<spec>'`, `--file path.json`, or pipe stdin.\n\n```json\n{\n  \"kind\": \"line\",\n  \"title\": \"optional\",\n  \"width\": 70,\n  \"height\": 20,\n  \"series\": [\n    {\n      \"name\": \"Signal\",\n      \"values\": [1, 2, 3, 4],\n      \"strokeThickness\": 2\n    }\n  ],\n  \"xAxis\": { \"name\": \"X\", \"labels\": [\"a\", \"b\", \"c\", \"d\"] },\n  \"yAxis\": { \"name\": \"Y\" }\n}\n```\n\n`kind` accepts: `line`, `column`, `row`, `step`, `scatter`, `stackedcolumn`,\n`stackedrow`, `stackedarea`, `candlestick`, `box`, `pie`, `polar`.\n\nSeries shape:\n- `values: number[]` — line / column / row / step / stacked / pie / polar\n- `points: number[][]` — scatter (`[x, y]`) / candlestick (`[open, high, close, low]`) / box (`[max, q3, q1, median, min]`)\n- `strokeThickness: number` — line / step (optional, default 1)\n\nFor pie: needs `--width ≥ 80 --height ≥ 30` (outer labels collide otherwise).\nFor stacked column / row with 2+ series: per-series textures auto-applied in\nplain mode; legend shows the texture next to each series name.\n\n## Step 4a — inline rendering (the common path)\n\n```sh\nlvc --json '<spec>' --no-color --width 70 --height 20\n```\n\nCapture the output and paste it back inside a fenced code block in your reply.\nCommonMark renders it monospace, the user sees the same glyphs you see.\n\nSizing: ~70×20 is a sweet spot. Smaller charts get cramped; larger ones might\nwrap weirdly in the user's terminal. Default to 70×20 unless the user asked\notherwise.\n\nRead what you rendered. Describe what's in it — \"the blue series climbs from\n~5 to ~12, the red oscillates around 8\" — so the user can sanity-check it\nmatches what they wanted. Don't claim \"the chart looks correct\" without\nnaming the actual shapes you see.\n\n## Step 4b — live window (interactive / color path)\n\nSpawn a new terminal so it doesn't block your conversation:\n\n**Windows (Windows Terminal):**\n```pwsh\nStart-Process wt.exe -ArgumentList '-d', $pwd.Path, 'pwsh', '-NoExit', '-NoLogo', '-Command', 'lvc --live --file demo.json'\n```\n\n**macOS (Terminal.app):**\n```sh\nosascript -e \"tell app \\\"Terminal\\\" to do script \\\"lvc --live --file $PWD/demo.json\\\"\"\n```\n\n**Linux (GNOME Terminal):**\n```sh\ngnome-terminal --working-directory=\"$PWD\" -- lvc --live --file demo.json\n```\n\nFor multi-line JSON, write a `demo.json` file first via the Write tool and\npass `--file` — avoids cross-shell quoting hell.\n\n**Critical:** you can't read the live window's contents. After launching,\ntell the user \"I opened a chart in a new window — what do you see?\" and\niterate from their feedback. Don't fabricate a description of what's\n\"probably there.\"\n\nIn the live window the user gets: mouse hover (tooltips), click-and-drag (pan),\nmouse wheel (zoom), `q` (quit), `r` (reset zoom), `+` / `-` (zoom at center).\n\n## Common pitfalls\n\n- **`--live --no-color`** is an error: live mode redraws frames in place via\n  ANSI escapes, which is exactly what `--no-color` strips. Pick one.\n- **`--live` with stdout redirected** errors out — it needs a real TTY. Always\n  spawn a new terminal window, never pipe `--live` output.\n- **`--mode sixel --no-color`** errors out — Sixel is a binary escape sequence\n  with no plain form. Drop `--mode sixel` or drop `--no-color`.\n- **Pie charts in plain mode at small canvases** collapse the disc to a sliver\n  because outer labels reserve margin space. Use `--width 80 --height 30`\n  minimum, or accept a smaller render in `--live` mode where the disc has\n  full canvas.\n- **Stacked bar plain mode with 1 series** keeps Braille `⣿` fills (no\n  textures kick in until 2+ bar series exist). This is intentional.\n- **You cannot see colors in the user's terminal from your own output.** Inline\n  ANSI escapes you write get collapsed to one inline-code style by the\n  CommonMark renderer — see [[reference_claude_code_cli_ansi_passthrough]].\n  This is why `--no-color` is the inline path: plain glyphs don't pretend to\n  carry color information.\n\n## When NOT to use this skill\n\n- The user asks to *edit chart configuration* in a LiveCharts app (XAML /\n  source-code view) — that's a code-edit task, not a rendering task.\n- The user wants to *understand* a chart they already have a screenshot of —\n  use vision on the image, not lvc.\n- The data is structural / hierarchical (trees, graphs, org charts) — lvc\n  only handles statistical chart kinds.\n",".claude/skills/repro-and-fix/SKILL.md":"---\nname: repro-and-fix\ndescription: Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. \"let's work on issue #1234\", a github.com/Live-Charts/LiveCharts2/issues/N URL, or \"reproduce and propose a fix\"). Implements the LiveCharts workflow end-to-end — worktree, in-sample repro view, auto-launched sample, screenshot/log verification, diagnosis, fix, separate regression-test commit, and PR — with minimal user interaction.\n---\n\n# repro-and-fix\n\nA user pointed you at a GitHub issue and asked you to reproduce + fix it. Run\nthe workflow below. The whole point is that the dev loop is *self-contained*:\nyou build the repro, launch the sample at that repro automatically, verify the\nbug yourself (screenshot or logs), fix it, verify the fix, and commit. Don't\nask the user for visual confirmations you can get yourself.\n\n> **Shared with Copilot Coding Agent.** `.github/copilot-instructions.md` links\n> here as the canonical issue → reproduce → fix → PR workflow. Edit this file\n> when changing the workflow; keep the Copilot doc as a thin pointer to avoid\n> drift.\n\n## When this skill applies\n\n- \"Let's work on https://github.com/Live-Charts/LiveCharts2/issues/N\"\n- \"Reproduce issue #N and propose a fix\"\n- \"Investigate this bug report: <URL>\"\n- A user paste of an issue URL with no other instruction\n\nIf the user is asking about *theory* (\"why does the gauge use a doughnut\ngeometry?\") or a *non-issue* task (refactor, doc update, perf), this skill is\nnot the right tool — fall back to general workflow.\n\n## Pick the platform that matches the issue\n\nRead the issue's **labels** and **repro snippet** to choose. The workflow is\nthe same on every XAML platform — only paths and launch commands change.\n\n| Platform | Sample dir                    | Launch project (Debug build)                                                | In-app screenshot |\n| -------- | ----------------------------- | --------------------------------------------------------------------------- | ----------------- |\n| Avalonia | `samples/AvaloniaSample/`     | `samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/.../*.Desktop.exe` | ✅ supported       |\n| WPF      | `samples/WPFSample/`          | `samples/WPFSample/.../WPFSample.exe`                                       | ✅ supported       |\n| WinUI    | `samples/WinUISample/WinUISample/` | `samples/WinUISample/WinUISample/.../WinUISample.exe`                  | ✅ supported       |\n| MAUI     | `samples/MauiSample/`         | per-platform; `dotnet build -t:Run -f net10.0-windows10.0.19041.0`          | ❌ use OS tool     |\n| Uno      | `samples/UnoPlatformSample/UnoPlatformSample/` | per-platform                                              | ❌ use OS tool     |\n\nIf the issue is platform-agnostic (a core engine bug), prefer Avalonia for the\nfastest dev loop on Windows (no WindowsAppSDK / packaged-build overhead).\n\n## Project conventions you must follow\n\nThese are durable rules from `~/.claude/projects/.../memory/MEMORY.md`. Re-read\nthe relevant memory file if uncertain — these are not optional:\n\n- **Worktree per issue.** Create `../LiveCharts2-fix-<issue>-<slug>` first\n  (`feedback_worktree_per_issue`). Don't work in the primary tree.\n- **One concept per commit.** Fix and regression test go in *separate* commits.\n  The regression-test commit must fail when the fix is reverted — verify this\n  before pushing (`feedback_commit_separation`).\n- **Snapshot tests for render-path changes.** If your fix touches paint, layout,\n  z-index, or draw order, run `tests/SnapshotTests/` before claiming done — unit\n  tests have missed catastrophic regressions\n  (`feedback_run_snapshots_for_render_changes`).\n- **Update docs when public API changes** in the same change set as a separate\n  commit (`feedback_update_docs_for_api`).\n- Check `Directory.Build.props` for `<LiveChartsVersion>` and use that value in\n  user-facing text (`project_current_version`).\n\n## Workflow\n\n### 1. Read the issue and decide if it still reproduces\n\n```bash\ngh issue view <N> --repo Live-Charts/LiveCharts2 --json title,body,labels,state,comments\n```\n\nPay attention to **comments**, not just the body. Issues commonly evolve:\n\n- The original symptom may already be fixed in main (commenter says \"newer\n  releases fixed this\") and the *current* bug is a downstream observation.\n  This is exactly what happened with #2008 — the `GaugeValue` TemplateBinding\n  bug in the title was already resolved; the live bug was a `CornerRadius=0`\n  override in the comments.\n- Multiple users may report different things in the same thread. Identify the\n  most recent reporter's actual symptom.\n\nIf you suspect the title bug is already fixed: build the original repro\nverbatim and verify *first*, before doing diagnosis. Cite the commenter who\nsaid it's fixed in your PR description.\n\n### 2. Set up the worktree\n\n```bash\ngit worktree add ../LiveCharts2-fix-<issue>-<short-slug> -b fix/issue-<N>-<short-slug>\n```\n\nAll edits, builds, and runs happen in the worktree. The primary tree stays\nclean for other work.\n\n### 3. Build the repro view (XAML platforms)\n\nThe repro convention is a **sample view inside the platform sample app**:\n\n```\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>.cs\n```\n\nMatch the issue's repro setup as closely as you can — same `ControlTemplate`\nshape, same property values, same paints. *Don't simplify* until you've\nconfirmed the bug fires; over-minimization can accidentally avoid the trigger.\n\nExisting repros to mirror:\n\n- `samples/AvaloniaSample/VisualTest/Issue1986Repro/` — TabControl + ScrollViewer\n- `samples/AvaloniaSample/VisualTest/Issue1417Repro/` — GeoMap reattach\n\nThe View's code-behind should expose helpers that a Factos test can call\n(e.g. `FindTemplatedGaugeSeries()`). This is how the regression test hooks in\nwithout going through the visual tree.\n\n**Do not commit changes to `samples/ViewModelsSamples/Index.cs` for repro\nviews.** Factos navigates to a sample by path via `LVC_SAMPLE` regardless of\nwhether the path is listed in the index, and the index is shared across every\nplatform sample. If you add `VisualTest/Issue<N>Repro` there and the view only\nexists in `samples/AvaloniaSample/`, every other platform sample (WPF, MAUI,\nWinUI, Uno) will throw when it loads the index. Leave the file untouched on\nyour branch.\n\nIf it's genuinely easier for your *local* dev loop to pick the repro from the\nsample selector dropdown rather than via `LVC_SAMPLE`, edit `Index.cs`\ntemporarily — but revert it before committing. `git restore\nsamples/ViewModelsSamples/Index.cs` before each commit, or just don't stage\nthe file.\n\n### 4. Auto-launch the sample at your repro\n\nAll XAML platform samples read `LVC_SAMPLE` at startup and load that sample\ninstead of the default landing screen. Set it before launching:\n\n```bash\n# bash / WSL\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nBuild first if needed: `dotnet build samples/<Platform>Sample/... -c Debug`.\n\n### 5. Verify the bug yourself\n\nTwo paths — pick based on the bug type:\n\n**A. In-app screenshot for visual bugs** (color, shape, position, rendering\nartifacts). Avalonia/WPF/WinUI samples support `LVC_SCREENSHOT`: when set,\nthe sample renders its main window via the framework's native\n`RenderTargetBitmap` after a short delay (default 3 s, override with\n`LVC_SCREENSHOT_DELAY_MS`) and exits. No external tooling, no race against\na screenshot tool launching too early. The capture is scaled to the\nwindow's physical pixels (`RenderScaling` on Avalonia,\n`VisualTreeHelper.GetDpi` on WPF) so HiDPI displays produce a sharp PNG\nthat matches what's on screen:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-before.png \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n$env:LVC_SCREENSHOT = \"$pwd\\.claude\\screenshots\\<N>-before.png\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nAfter it exits, `Read` the PNG. You're multimodal — describe what you see,\ncompare to a control sample (often `Pies/Gauge1` or `General/FirstChart` for\n\"what should this look like\"). If the bug is subtle (a few pixels), make the\nrepro larger (`Width=380`, `Height=380`) so it's clearly visible.\n\n**Fallback for MAUI/Uno or other-OS edge cases:** use the OS-appropriate\nhelper script. They all take `<ProcessName> <OutPath> [WaitSeconds]` and\npoll for the target window before capturing:\n\n| OS      | Script                                       | Underlying tool                            |\n| ------- | -------------------------------------------- | ------------------------------------------ |\n| Windows | `.claude/scripts/capture-window.ps1`         | `PrintWindow` via Win32 (works occluded)   |\n| macOS   | `.claude/scripts/capture-window-macos.sh`    | `osascript` + `screencapture -l <id>`      |\n| Linux   | `.claude/scripts/capture-window-linux.sh`    | `xdotool`+`import` / `swaymsg`+`grim` / `gnome-screenshot` |\n\nThe Linux script tries X11 → sway → GNOME in priority order; install the\nmatching package if none are present (the script prints the apt/dnf hint).\nUse these only when `LVC_SCREENSHOT` isn't supported on the target platform\n(MAUI, Uno) — for Avalonia/WPF/WinUI prefer in-app capture.\n\n**B. Console logs for state/dataflow bugs** (binding doesn't fire, value\ndoesn't propagate, event order is wrong):\n\nAdd temporary `Console.WriteLine` calls along the suspected path:\n\n```csharp\nConsole.WriteLine($\"[issue<N>] OnPropertyChanged: {change.Property.Name} old={change.OldValue} new={change.NewValue}\");\n```\n\nThe platform sample writes to stdout when launched from the terminal. Run via\nthe bash tool with `run_in_background=true` (no `LVC_SCREENSHOT` so the app\nstays open), wait a few seconds, kill the app, then `grep` the captured output\nfile. **Remove the diagnostics before committing.**\n\nIf neither approach decisively confirms the bug, escalate to the user with\n**one** well-framed question, not a chain of polling questions. Example:\n\n> \"The before-fix capture shows the gauge endcaps as flat, contrary to the\n> issue's screenshot. Did you toggle CornerRadius after the screenshot was\n> taken in the original report?\"\n\n### 6. Diagnose the root cause\n\nTrace from symptom backward through the rendering/data pipeline. Cross-check\nagainst `MEMORY.md` — many bugs in this repo have related ancestors\n(z-index issues, theme overrides, motion-property defaults, source-gen\nbehavior). If you find a matching memory note, use its diagnosis as a starting\npoint but verify against current code; memories go stale.\n\nCommon gotchas in this codebase:\n\n- **Theme overrides user-set values** when the user's value equals the DP\n  default — Avalonia skips `OnPropertyChanged` and `_userSets` never gets\n  populated. `XamlGaugeSeries.EndInit` syncs IsSet DPs as a remediation; if\n  you see this pattern in another wrapper, the same fix shape applies.\n- **Series controls aren't in the visual tree.** `OnInitialized` and\n  `TemplatedParent` may not fire/be set the way you'd expect. Use `EndInit`\n  instead.\n- **Theme rules run from the chart engine measure pass**, not at construction.\n  `_isInternalSet` + `_userSets` is the existing precedence mechanism — don't\n  reinvent it.\n- **Motion properties animate from a stale \"from\" value.** A value flip from\n  N→0 may render N for one frame.\n\n### 7. Write the regression test first\n\nTest-first: by the end of step 6 you understand the root cause and the\nobservable that would catch a regression. Write the test now, *before*\napplying the fix, and run it — it must fail for the right reason. A test\nwritten after the fix risks passing against both versions of the code; a\ntest that fails first proves it's gated on the broken behavior, and you\nskip the awkward \"comment out the fix, rebuild, re-run\" verification dance.\n\nTest choice depends on the bug nature:\n\n- **Programmatic state assertion** (the bug is in state propagation, not\n  pixels): Factos test in `tests/SharedUITests/`. Navigate to the repro,\n  query a helper method on the View that exposes the state under test,\n  assert. Gate by `#if <PLATFORM>_UI_TESTING` if platform-specific (most\n  XAML-platform-quirk bugs are).\n- **Pixel-perfect rendering**: snapshot test in `tests/SnapshotTests/`.\n- **Animation trajectory** (the bug is in per-frame interpolation, not the\n  final value — a bar pops to target instead of growing, a slice doesn't\n  sweep, a transition runs at the wrong speed, a refactor risks changing the\n  motion shape of an existing series): JSON animation baseline under\n  `tests/CoreTests/AnimationBaselines/` driven by\n  `tests/CoreTests/Helpers/SeriesAnimationCapture.cs`. The helper steps\n  `CoreMotionCanvas.DebugElapsedMilliseconds`, captures the visual's geometry\n  at each sample timestamp, and `AssertTrajectoryMatches` compares the\n  trajectory to a committed `.json`. First run writes the new trajectory to\n  `AnimationBaselinesNew/` and fails with a \"review and commit\" message —\n  inspect the file, then move it into `AnimationBaselines/`. Re-baseline the\n  same way: delete the JSON, re-run, move from `New/` back. On mismatch the\n  helper also drops `[EXPECTED]`/`[RESULT]` files into\n  `AnimationBaselinesDiff/` so you can diff them directly. Caller must use\n  `EasingFunctions.Lineal` + fixed `MinLimit`/`MaxLimit` so interpolation is\n  deterministic; the existing `tests/CoreTests/SeriesTests/*AnimationTests.cs`\n  files are the templates. Prefer this over a plain MSTest whenever the\n  observable is \"how the value changes between two states\" — a single\n  before/after assertion can't catch a regression that only mis-paints the\n  intermediate frames.\n- **Pure C# logic** (chart engine, motion, math): MSTest in\n  `tests/CoreTests/`.\n\nRun the test and confirm the failure message matches the symptom you saw in\nstep 5 — not, for example, a setup error or NullRef from missing test\ninfrastructure. If it fails for an unrelated reason, the test isn't yet\ncatching the bug; fix the test before moving on.\n\nTo run a single Factos UI test:\n\n```bash\n# In tests/UITests/Program.cs, set: var appToRun = \"<platform>-desktop\"\n# (avalonia-desktop / wpf-net10 / winui / maui / uno).\ndotnet build tests/UITests/UITests.csproj -c Debug\ncd tests/UITests/bin/Debug/net10.0 && dotnet UITests.dll\n# Revert the appToRun change before committing — it's a local dev-loop tweak.\n```\n\n### 8. Apply the fix\n\nSmallest possible change. Don't refactor surrounding code. Don't add\ncomments unless the WHY is non-obvious — but if the bug is a subtle\ninteraction (Avalonia behavior, theme precedence, source-gen quirk), a comment\nexplaining *why this fix is necessary* is warranted because future readers\nwon't reconstruct it from memory.\n\n### 9. Verify the fix\n\nRe-run the failing test from step 7 — it must now pass. Then re-run step 5\nwith the fix in place to capture an \"after\" screenshot at a sibling path and\ncompare visually:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-after.png \\\n  ./samples/<Platform>Sample/.../<Platform>Sample.exe\n```\n\n`Read` both images. Don't claim the fix works without comparing. The test\npassing is necessary but not sufficient for visual bugs — pixel-equivalent\noutput can still look subtly wrong if the assertion was too narrow.\n\n### 10. Commit and PR\n\nYou developed test-first, but commit fix-first. Two commits, in this order:\n\n1. `fix(<scope>): <one-line summary> (#<N>)` — only the fix.\n2. `test(<scope>): regression for <symptom> (#<N>)` — only the test +\n   repro view. Do not stage `samples/ViewModelsSamples/Index.cs`; see step 3\n   for why.\n\nWhy fix-first commit order despite test-first development: every commit on\nthe branch should be individually green so `git bisect` lands on a usable\nstate. If the test commit landed first it would be a failing-test commit\nthat bisect would (correctly) flag as broken. Fix-then-test keeps both\ncommits green while still satisfying the project rule that reverting the\nfix must surface the regression — revert commit 1 alone and the test from\ncommit 2 fails.\n\nCommit message style follows recent history (`git log --oneline -10`).\nBody: imperative, mention the root-cause mechanism, why the test catches it.\nEnd with the standard `Co-Authored-By` line.\n\nPush and open the PR with `gh pr create`. The PR body should include:\n\n- **Summary** bullet list (what changed, what it closes)\n- **Why** section (root cause walkthrough — the most valuable part)\n- **Test plan** checklist with what you actually verified locally\n\n### 11. Update memory\n\nAfter the PR is open, write a `project_issue_<N>.md` memory and add a one-line\nentry to `MEMORY.md`. Capture: **what was non-obvious** about the bug, what\ndiagnosis steps led to the fix, and what conventions/files the next person\nneeds. Don't re-document the code — just the insights.\n\n## Anti-patterns to avoid\n\n- **Asking the user \"is the bug visible now?\" repeatedly.** Capture a\n  screenshot or read logs. If you can't decide from one capture + one\n  question, you haven't framed the question precisely enough.\n- **Simplifying the repro before confirming.** A \"minimal\" repro that doesn't\n  trigger the bug is worse than a verbose one that does.\n- **Writing the test after the fix.** Develop test-first (step 7 before\n  step 8) so the failure is real and you don't have to comment out the fix\n  to verify the test catches anything. A test authored against\n  already-fixed code can pass for the wrong reason.\n- **Mixing fix + test + cleanup in one commit.** Project policy is strict\n  here — every fix needs a separately revertible test commit.\n- **Force-pushing for \"cleanliness\".** Never. Stack new commits.\n- **Trusting memory over code.** Memory files name specific functions and\n  files; verify they still exist before recommending — projects refactor.\n\n## Tooling reference\n\n- Issue triage: `gh issue view <N> --repo Live-Charts/LiveCharts2`\n- **Auto-launch sample**: `LVC_SAMPLE=<path>` env var (Avalonia, WPF, WinUI,\n  MAUI, Uno).\n- **In-app screenshot**: `LVC_SCREENSHOT=<path>` env var (Avalonia, WPF,\n  WinUI). Sample renders to PNG after `LVC_SCREENSHOT_DELAY_MS` (default\n  3000) and exits.\n- **External screenshot fallback** — one script per OS, all take the same\n  `<ProcessName> <OutPath> [WaitSeconds]` shape:\n  - Windows: `.claude/scripts/capture-window.ps1` (also accepts\n    `-WindowTitle <substring>` instead of `-ProcessName`)\n  - macOS:   `.claude/scripts/capture-window-macos.sh`\n  - Linux:   `.claude/scripts/capture-window-linux.sh` (X11 / sway / GNOME)\n- Factos UI tests: `tests/UITests/`, set `appToRun` in `Program.cs` for\n  local runs.\n- Build per-platform: `LiveCharts.<Platform>.slnx` solutions.\n","llms-full.txt":"# LiveCharts2 — Comprehensive Knowledge Base for LLMs\n\n> **⚠️ Version Warning:** This document covers **LiveCharts v2** (package prefix `LiveChartsCore.SkiaSharpView.*`).\n> The legacy **v0** (`LiveCharts` / `LiveCharts.Wpf`) is completely obsolete and has a different API.\n> Do NOT mix v0 and v2 syntax. v0 reference: https://github.com/Live-Charts/Live-Charts\n\n---\n\n## Overview\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET. It fixes the main design issues of its\npredecessor (v0), is focused on running everywhere, and improves flexibility. It uses **SkiaSharp** as its default\nrendering backend — a cross-platform 2D graphics API for .NET based on Google's Skia graphics library.\n\n- **Website / full docs:** https://livecharts.dev\n- **GitHub:** https://github.com/Live-Charts/LiveCharts2\n- **License:** MIT\n- **Current version:** 2.1.0 (check NuGet for latest stable/prerelease)\n- **Target frameworks (core):** `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **C# language version:** 14.0\n\n### Supported Platforms & NuGet Packages\n\n| Platform | NuGet package |\n|---|---|\n| MAUI | `LiveChartsCore.SkiaSharpView.Maui` |\n| Uno Platform (WinUI) | `LiveChartsCore.SkiaSharpView.Uno.WinUI` |\n| Avalonia | `LiveChartsCore.SkiaSharpView.Avalonia` |\n| WPF | `LiveChartsCore.SkiaSharpView.WPF` |\n| WinForms | `LiveChartsCore.SkiaSharpView.WinForms` |\n| WinUI | `LiveChartsCore.SkiaSharpView.WinUI` |\n| Blazor WASM | `LiveChartsCore.SkiaSharpView.Blazor` |\n| Eto.Forms | `LiveChartsCore.SkiaSharpView.Eto` |\n\nSkiaSharp minimum supported version: **2.88.9** (default: 3.119.0 for GPU support).\n\n---\n\n## Architecture\n\nThe library is divided into three main modules:\n\n### Core (`LiveChartsCore`)\n\nPlatform-agnostic. Contains:\n- A drawing **API** (interfaces) that defines all the shapes the library needs to build a chart\n- The charting engine: measures sizes, calculates positions for every geometry\n- The animation system (`Motion/` namespace) — `IAnimatable`, `MotionProperty`\n- Change-detection via `CollectionDeepObserver` (wraps `INotifyPropertyChanged` / `INotifyCollectionChanged`)\n- Series implementations: `LineSeries<T>`, `ColumnSeries<T>`, `PieSeries<T>`, `ScatterSeries<T>`, etc.\n\n### Renderer (`LiveChartsCore.SkiaSharp`)\n\nImplements the Core drawing API using SkiaSharp. Responsible for materializing geometry objects to pixels.\nYou can replace SkiaSharp with any other rendering engine (see `VorticeSample` using DirectX11 via Vortice.Windows).\n\n### View (platform packages)\n\nPlatform-specific controls (`CartesianChart`, `PieChart`, `PolarChart`, `GeoMap`) that:\n1. Ask the **Core** *what* to draw (geometry sizes and positions)\n2. Ask the **Renderer** *how* to draw it (render to the platform surface)\n\n### Animation System\n\nLiveCharts generates animations by producing many frames over time. Each animatable object has\n`MotionProperty` fields whose getter returns the *current interpolated value* for the current point\nin time — not the last assigned value. This means:\n\n```csharp\nvar line = new LineGeometry();\nline.X1 = 0;\nline.X1 = 100;\nvar x1 = line.X1; // returns 0 (animation has not elapsed yet)\n// After 5 seconds (of a 10s linear transition): line.X1 returns ~50\n```\n\n### Automatic Update Cycle\n\n1. User changes data (property or collection).\n2. `CollectionDeepObserver` detects the change via `INotifyPropertyChanged` / `INotifyCollectionChanged`.\n3. The chart **throttles** a *Measure request* (fires at most once every ~10 ms).\n4. On measure: Core recalculates geometry positions → Update cycle draws frames until all `MotionProperty` animations complete.\n\n---\n\n## Installation\n\n### Install via NuGet (pick your platform)\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView.WPF\ndotnet add package LiveChartsCore.SkiaSharpView.Avalonia\ndotnet add package LiveChartsCore.SkiaSharpView.Maui\ndotnet add package LiveChartsCore.SkiaSharpView.Blazor\ndotnet add package LiveChartsCore.SkiaSharpView.WinForms\ndotnet add package LiveChartsCore.SkiaSharpView.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Uno.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Eto\n```\n\n> **Note for WPF / WinForms:** By default these projects target `netX.0-windows`, but SkiaSharp 3 does not provide\n> a build for that TFM. Consider specifying a minimum Windows version: `net8.0-windows10.0.19041`.\n\n### Configure LiveCharts at startup\n\nCreate a `CustomLiveChartsExtensions` class (shared across all platforms):\n\n```csharp\nusing LiveChartsCore.Kernel;\nusing LiveChartsCore.SkiaSharpView;\n\npublic static partial class CustomLiveChartsExtensions\n{\n    public static LiveChartsSettings AddLiveChartsAppSettings(this LiveChartsSettings settings) =>\n        settings\n            .AddSkiaSharp()           // use SkiaSharp as renderer\n            .AddDefaultMappers()      // register built-in type mappers\n            .AddDefaultTheme()        // light/dark theme based on OS\n            // optionally register a mapper for a custom type:\n            .HasMap<City>((city, index) => new(index, city.Population));\n}\n```\n\n#### WPF — `App.xaml.cs`\n\n```csharp\nprotected override void OnStartup(StartupEventArgs e)\n{\n    base.OnStartup(e);\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n}\n```\n\n#### Avalonia — `App.axaml.cs`\n\n```csharp\npublic override void OnFrameworkInitializationCompleted()\n{\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    // ...\n}\n```\n\n#### MAUI — `MauiProgram.cs`\n\n```csharp\nbuilder\n    .UseMauiApp<App>()\n    .UseLiveCharts(config => config.AddLiveChartsAppSettings());\n```\n\n#### Blazor — `App.razor`\n\n```razor\n@inject IJSRuntime JS\n@code {\n    protected override async Task OnInitializedAsync()\n    {\n        LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    }\n}\n```\n\n---\n\n## Core Concepts\n\n### Series and Values\n\nEvery series is generic over its data type `T`. LiveCharts natively supports `short`, `int`, `long`, `float`,\n`double`, `decimal` and their nullable forms. It also provides observable wrappers:\n\n| Type | Use case |\n|---|---|\n| `ObservableValue` | Single Y value that notifies changes |\n| `ObservablePoint` | Explicit X and Y |\n| `WeightedPoint` | X, Y, Weight (bubble charts) |\n| `DateTimePoint` | X is `DateTime` |\n| `TimeSpanPoint` | X is `TimeSpan` |\n| `ObservablePolarPoint` | Polar charts |\n| `FinancialPoint` / `FinancialPointI` | OHLC candlestick charts |\n\n```csharp\n// simple array — static, no auto-update:\nnew LineSeries<double> { Values = new double[] { 1, 2, 3 } }\n\n// ObservableCollection — auto-updates when items are added/removed:\nvar values = new ObservableCollection<ObservableValue>();\nnew LineSeries<ObservableValue> { Values = values }\nvalues.Add(new ObservableValue(5));  // chart updates automatically\n```\n\n### Mappers\n\nUse a **mapper** to teach LiveCharts how to plot a custom type:\n\n```csharp\n// Per-series mapper:\nnew LineSeries<TempSample>\n{\n    Values = samples,\n    Mapping = (sample, index) => new Coordinate(sample.Time, sample.Temperature)\n}\n\n// Global mapper (applied to every series using TempSample):\nLiveCharts.Configure(config =>\n    config.HasMap<TempSample>((sample, index) => new Coordinate(sample.Time, sample.Temperature)));\n```\n\n### IChartEntity (high-performance custom types)\n\nImplement `IChartEntity` directly on your model for best performance (no delegate overhead per point):\n\n```csharp\npublic partial class TempSample : ObservableObject, IChartEntity\n{\n    [ObservableProperty] private int _time;\n    [ObservableProperty] private double _temperature;\n\n    public Coordinate Coordinate { get; protected set; }\n    public ChartEntityMetaData? MetaData { get; set; }\n\n    protected override void OnPropertyChanged(PropertyChangedEventArgs e)\n    {\n        Coordinate = new Coordinate(Time, Temperature);\n        base.OnPropertyChanged(e);\n    }\n}\n```\n\n### Paints\n\nA `Paint` is the v2 equivalent of WPF/Avalonia `Brush`. It wraps SkiaSharp's paint and adds animation support.\n\n```csharp\nusing SkiaSharp;\nusing LiveChartsCore.SkiaSharpView.Painting;\n\n// Solid color\nnew SolidColorPaint(SKColors.Blue) { StrokeThickness = 4 }\n\n// Linear gradient\nnew LinearGradientPaint(\n    new[] { new SKColor(255, 140, 148), new SKColor(220, 237, 194) },\n    new SKPoint(0.5f, 0),   // gradient start (center-top)\n    new SKPoint(0.5f, 1))   // gradient end   (center-bottom)\n\n// Radial gradient\nnew RadialGradientPaint(new SKColor(255, 96, 96), new SKColor(255, 234, 96))\n\n// null means \"do not draw\" (hides fill, stroke, etc.)\nFill = null\n```\n\nAvailable paint properties: `StrokeThickness`, `PathEffect` (for dashed lines), `ImageFilter`, etc.\n\n### Animations\n\nAll charts animate automatically. Customize with:\n\n```csharp\n// Chart-level speed:\nmyChart.AnimationsSpeed = TimeSpan.FromMilliseconds(300);\n\n// Easing function:\nmyChart.EasingFunction = EasingFunctions.BounceOut;\n\n// Disable animations:\nmyChart.AnimationsSpeed = TimeSpan.Zero;\n// or:\nmyChart.EasingFunction = null;\n```\n\nSeries and Axes also have their own `AnimationsSpeed` and `EasingFunction` properties\n(override the chart-level value when non-null).\n\n### Null / missing points\n\nSet a value to `null` or a `Coordinate` to `Coordinate.Empty` to create gaps:\n\n```csharp\nnew LineSeries<double?>\n{\n    Values = new double?[] { 2, 6, null, 3, 5 }\n}\n```\n\n### Hardware Acceleration (GPU)\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\n\nLiveCharts.Configure(c => c\n    .AddLiveChartsRenderSettings());  // see LiveChartsRenderSettings.cs in samples\n```\n\nGPU is disabled by default. On Avalonia/Uno with SkiaRenderer the GPU setting is ignored\n(the UI framework controls rendering).\n\n---\n\n## Chart Types\n\n### CartesianChart\n\nStandard X/Y chart. Hosts `Series` (collection of `ICartesianSeries`), `XAxes`, `YAxes`.\n\nSupports: `LineSeries`, `ColumnSeries`, `ScatterSeries`, `StepLineSeries`, `HeatSeries`,\n`CandlesticksSeries`, `StackedLineSeries`, `StackedColumnSeries`, `StackedStepLineSeries`, `BoxSeries`, `ErrorSeries`.\n\nKey properties: `Series`, `XAxes`, `YAxes`, `ZoomMode`, `AnimationsSpeed`, `TooltipPosition`, `LegendPosition`.\n\n### PieChart\n\nHosts `PieSeries<T>`. Used for pie, doughnut, gauge, and Nightingale rose charts.\n\n### PolarChart\n\nHosts `PolarLineSeries<T>` and `PolarScatterSeries<T>`. Uses polar (angle + radius) coordinates.\n\n### GeoMap\n\nDisplays geographic maps. Hosts `HeatLandSeries` to color countries/regions by value.\n\n---\n\n## XAML Integration (WPF, Avalonia, MAUI, WinUI)\n\n### XAML Types (Xaml-prefixed)\n\nEvery `Series<T>` and `Axis` has a XAML-friendly counterpart (prefix `Xaml`). These live in the visual tree\nand support data bindings, styles, hot-reload and designer previews:\n\n- `XamlLineSeries`, `XamlColumnSeries`, `XamlPieSeries`, `XamlScatterSeries`, etc.\n- `XamlAxis`, `XamlDrawnLabelVisual`\n\nThe non-Xaml types (`LineSeries<T>`, `ColumnSeries<T>`) are plain C# objects and do **not** live in the\nvisual tree — use them in ViewModels when you want to keep UI logic separate from SkiaSharp dependencies.\n\n### SeriesCollection (WPF / WinUI / Uno)\n\nWPF, WinUI and Uno use `SeriesCollection` as a container in XAML to hold multiple series children:\n\n```xml\n<lvc:CartesianChart.Series>\n    <lvc:SeriesCollection>\n        <lvc:XamlLineSeries Values=\"{Binding Values1}\"/>\n        <lvc:XamlColumnSeries Values=\"{Binding Values2}\"/>\n    </lvc:SeriesCollection>\n</lvc:CartesianChart.Series>\n```\n\nAvalonia and MAUI support multiple children directly (no wrapper needed).\n\n---\n\n## Code Examples\n\n### Example 1 — Basic Line Chart (WPF, code-behind + XAML MVVM)\n\n**ViewModel (shared, no UI dependencies):**\n\n```csharp\n// samples/ViewModelsSamples/Lines/Basic/ViewModel.cs\nnamespace ViewModelsSamples.Lines.Basic;\n\npublic class ViewModel\n{\n    public double[] Values1 { get; set; } = [2, 1, 3, 5, 3, 4, 6];\n    public int[]    Values2 { get; set; } = [4, 2, 5, 2, 4, 5, 3];\n}\n```\n\n**WPF View (View.xaml):**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Lines.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Lines.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n                <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n**Avalonia View (View.axaml):**\n\n```xml\n<UserControl\n    x:Class=\"AvaloniaSample.Lines.Basic.View\"\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n    xmlns:vms=\"using:ViewModelsSamples.Lines.Basic\"\n    x:DataType=\"vms:ViewModel\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 2 — Bar Chart with Axis Labels (WPF)\n\n**ViewModel:**\n\n```csharp\nnamespace ViewModelsSamples.Bars.Basic;\n\npublic class ViewModel\n{\n    public double[] MaryValues { get; set; } = [2, 5, 4];\n    public double[] AnaValues  { get; set; } = [3, 1, 6];\n    public string[] Labels     { get; set; } = [\"Category 1\", \"Category 2\", \"Category 3\"];\n}\n```\n\n**WPF View:**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Bars.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Bars.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart LegendPosition=\"Right\">\n\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlColumnSeries SeriesName=\"Mary\" Values=\"{Binding MaryValues}\"/>\n                <lvc:XamlColumnSeries SeriesName=\"Ana\"  Values=\"{Binding AnaValues}\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n\n        <lvc:CartesianChart.XAxes>\n            <lvc:AxesCollection>\n                <lvc:XamlAxis\n                    Labels=\"{Binding Labels}\"\n                    SeparatorsPaint=\"#c8c8c8\"\n                    SeparatorsAtCenter=\"False\"\n                    TicksPaint=\"#232323\"\n                    TicksAtCenter=\"True\"\n                    MinStep=\"1\"\n                    ForceStepToMin=\"True\"/>\n            </lvc:AxesCollection>\n        </lvc:CartesianChart.XAxes>\n\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 3 — Real-Time Chart (shared ViewModel, any platform)\n\nAdds a new `DateTimePoint` every 100 ms using `ObservableCollection` — the chart updates automatically\nbecause `ObservableCollection` implements `INotifyCollectionChanged`.\n\n```csharp\nusing System;\nusing System.Collections.ObjectModel;\nusing System.Threading.Tasks;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing LiveChartsCore.Defaults;\n\nnamespace ViewModelsSamples.General.RealTime;\n\npublic partial class ViewModel : ObservableObject\n{\n    public ViewModel() { _ = ReadData(); }\n\n    // 'partial' is required by CommunityToolkit.Mvvm source generator (C# 14 partial properties)\n    [ObservableProperty]\n    public partial double[] Separators { get; set; } = [];\n\n    public ObservableCollection<DateTimePoint> Values { get; set; } = [];\n\n    public Func<DateTime, string> LabelsFormatter { get; } =\n        date => (DateTime.Now - date).TotalSeconds < 1 ? \"now\" : $\"{(DateTime.Now - date).TotalSeconds:N0}s ago\";\n\n    // Use a lock so background thread writes are safe\n    public object Sync { get; } = new object();\n    public bool IsReading { get; set; } = true;\n\n    private async Task ReadData()\n    {\n        var random = new Random();\n        while (IsReading)\n        {\n            await Task.Delay(100);\n            lock (Sync)\n            {\n                Values.Add(new DateTimePoint(DateTime.Now, random.Next(0, 10)));\n                if (Values.Count > 250) Values.RemoveAt(0);\n                Separators = GetSeparators();\n            }\n        }\n    }\n\n    private static double[] GetSeparators()\n    {\n        var now = DateTime.Now;\n        return [\n            now.AddSeconds(-25).Ticks,\n            now.AddSeconds(-20).Ticks,\n            now.AddSeconds(-15).Ticks,\n            now.AddSeconds(-10).Ticks,\n            now.AddSeconds(-5).Ticks,\n            now.Ticks\n        ];\n    }\n}\n```\n\n> **Threading note:** When updating chart data from a non-UI thread, use a lock object (`Sync`) and assign\n> it to the chart's `SyncContext` property so LiveCharts can coordinate reads/writes safely.\n\n---\n\n### Example 4 — Pie Chart with Named Slices\n\n```csharp\nnamespace ViewModelsSamples.Pies.Basic;\n\npublic class PieData(string name, double value)\n{\n    public string Name   { get; set; } = name;\n    public double[] Values { get; set; } = [value];\n}\n\npublic class ViewModel\n{\n    public PieData[] Data { get; set; } =\n    [\n        new(\"Mary\",    10),\n        new(\"John\",    20),\n        new(\"Alice\",   30),\n        new(\"Bob\",     40),\n        new(\"Charlie\", 50),\n    ];\n}\n```\n\n**WPF View (using XAML template):**\n\n```xml\n<lvc:PieChart SeriesSource=\"{Binding Data}\">\n    <lvc:PieChart.SeriesTemplate>\n        <DataTemplate>\n            <lvc:XamlPieSeries\n                SeriesName=\"{Binding Name}\"\n                Values=\"{Binding Values}\"/>\n        </DataTemplate>\n    </lvc:PieChart.SeriesTemplate>\n</lvc:PieChart>\n```\n\n---\n\n### Example 5 — Custom Mapper (CLI / Console / Server)\n\nRender a chart to an image without any UI framework using `SKCartesianChart`:\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\nusing LiveChartsCore.SkiaSharpView;\n\n// Custom data type\npublic class TempSample { public int Time { get; set; } public double Temperature { get; set; } }\n\nvar samples = new[]\n{\n    new TempSample { Time = 1, Temperature = 65.65 },\n    new TempSample { Time = 5, Temperature = 62.23 },\n    new TempSample { Time = 8, Temperature = 85.12 },\n};\n\nvar chart = new SKCartesianChart\n{\n    Width  = 900,\n    Height = 600,\n    Series = new[]\n    {\n        new LineSeries<TempSample>\n        {\n            Values  = samples,\n            Mapping = (sample, index) => new(sample.Time, sample.Temperature)\n        }\n    },\n    XAxes = new[] { new Axis { Labeler = value => $\"{value} s\" } },\n    YAxes = new[] { new Axis { Labeler = value => $\"{value} °C\" } },\n};\n\nchart.SaveImage(\"chart.png\");\n```\n\n---\n\n## Axes\n\nThe `CartesianChart` exposes `XAxes` and `YAxes` (both `IEnumerable<IAxis>`). Default: one `Axis` each.\n\n### Key Axis properties\n\n| Property | Description |\n|---|---|\n| `Labeler` | `Func<double, string>` — formats axis tick labels |\n| `Labels` | `IList<string>` — named labels (index-based, used for category axes) |\n| `MinLimit` / `MaxLimit` | Fix the visible range (used for zooming/panning) |\n| `MinStep` / `ForceStepToMin` | Force minimum separation between ticks |\n| `SeparatorsPaint` | Paint for grid lines |\n| `TicksPaint` | Paint for axis tick marks |\n| `NamePaint` | Paint for the axis name label |\n| `DataLabelsPaint` | Paint for data labels on the series |\n| `CrosshairPaint` | Paint for crosshair lines |\n| `IsVisible` | Show/hide the axis |\n| `Position` | `AxisPosition.Start` or `AxisPosition.End` |\n\n### Zooming and Panning\n\n```csharp\n// Enable X-axis zoom and pan:\nmyChart.ZoomMode = ZoomAndPanMode.X;\n\n// Enable both axes:\nmyChart.ZoomMode = ZoomAndPanMode.Both;\n\n// Disable:\nmyChart.ZoomMode = ZoomAndPanMode.None;\n```\n\nEach gesture also has its own flag (`PanX`, `ZoomX`, `PanY`, `ZoomY`) so zoom and pan can be enabled independently. The composites `X = PanX | ZoomX`, `Y = PanY | ZoomY` and `Both = X | Y` keep their original pan+zoom semantics.\n\n```csharp\n// Allow zooming on the X axis but disable panning (e.g. so pan gestures don't hide tooltips on mobile):\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX;\n\n// Zoom on X, pan on Y:\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY;\n```\n\n`ZoomAndPanMode` is a flags enum — combine values:\n```csharp\nmyChart.ZoomMode = ZoomAndPanMode.X | ZoomAndPanMode.NoFit | ZoomAndPanMode.NoZoomBySection;\n```\n\n### DateTime / TimeSpan Axes\n\nUse `DateTimePoint` or `TimeSpanPoint` for time-based X axes and format with a `Labeler`:\n\n```csharp\nXAxes = new[]\n{\n    new Axis\n    {\n        Labeler = value => new DateTime((long)value).ToString(\"HH:mm:ss\"),\n        UnitWidth = TimeSpan.FromSeconds(1).Ticks,\n        MinStep  = TimeSpan.FromSeconds(1).Ticks,\n    }\n};\n```\n\n---\n\n## Tooltips & Legends\n\n```csharp\n// Tooltip position options: Top (default), Bottom, Left, Right, Center, Hidden\nmyChart.TooltipPosition = TooltipPosition.Bottom;\n\n// Legend position: Hidden (default), Top, Bottom, Left, Right\nmyChart.LegendPosition = LegendPosition.Right;\n```\n\nCustom tooltips: implement `IChartTooltip<TDrawingContext>` and assign to `Chart.Tooltip`.  \nCustom legends: implement `IChartLegend<TDrawingContext>` and assign to `Chart.Legend`.\n\n---\n\n## Sections (Reference Lines / Bands)\n\n```csharp\nusing LiveChartsCore;\n\nmyChart.Sections = new[]\n{\n    new RectangularSection\n    {\n        Yi = 4,\n        Yj = 8,\n        Fill = new SolidColorPaint(new SKColor(255, 205, 210, 100))\n    }\n};\n```\n\n---\n\n## Drawing on Canvas\n\nUse `Chart.VisualElements` to overlay custom SkiaSharp drawing:\n\n```csharp\nmyChart.VisualElements = new[]\n{\n    new DrawnVisual\n    {\n        OnDraw = (canvas, chart) =>\n        {\n            canvas.DrawText(\"Hello!\", new SKPoint(100, 100), new SKPaint { Color = SKColors.Black });\n        }\n    }\n};\n```\n\n---\n\n## Server-Side / Console Chart Generation\n\nInstall only the core packages (no UI framework required):\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView\n```\n\nUse `SKCartesianChart`, `SKPieChart`, `SKPolarChart`, `SKGeoMap` — they all inherit from `InMemorySkiaSharpChart`\nand expose a `GetImage()` method that returns an `SKImage`:\n\n```csharp\nvar chart = new SKCartesianChart\n{\n    Width = 900, Height = 600,\n    Series = new ISeries[] { new LineSeries<int> { Values = new[] { 1, 2, 3 } } }\n};\n\n// Save to file:\nchart.SaveImage(\"output.png\");\n\n// Or get bytes for HTTP response:\nusing var image  = chart.GetImage();\nusing var data   = image.Encode(SKEncodedImageFormat.Png, 100);\nusing var stream = data.AsStream();\n```\n\n---\n\n## Multi-threading\n\nWhen modifying chart data from a background thread, always use a `lock`:\n\n```csharp\n// 1. Define a sync object in your ViewModel:\npublic object Sync { get; } = new object();\n\n// 2. Assign it to the chart control (XAML or code-behind):\n//    myChart.SyncContext = viewModel.Sync;\n\n// 3. Wrap all data mutations in the lock:\nlock (Sync)\n{\n    Values.Add(new ObservableValue(random.Next(0, 10)));\n    if (Values.Count > 200) Values.RemoveAt(0);\n}\n```\n\n---\n\n## Themes and Color Palettes\n\n```csharp\nLiveCharts.Configure(settings =>\n    settings\n        .AddDefaultTheme(theme =>\n            theme.OnInitialized(() =>\n            {\n                theme.AnimationsSpeed  = TimeSpan.FromMilliseconds(300);\n                theme.EasingFunction   = EasingFunctions.QuadraticOut;\n                theme.Colors           = ColorPalletes.MaterialDesign500;\n            })));\n```\n\nBuilt-in palettes: `MaterialDesign200`, `MaterialDesign500`, `MaterialDesign800`, `FluentDesign`, etc.\n\n---\n\n## Common Namespaces\n\n```csharp\nusing LiveChartsCore;                            // ISeries, IAxis, LiveCharts.Configure, etc.\nusing LiveChartsCore.Defaults;                   // ObservableValue, ObservablePoint, DateTimePoint, etc.\nusing LiveChartsCore.Kernel;                     // Coordinate, ChartEntityMetaData, IChartEntity\nusing LiveChartsCore.Measure;                    // ZoomAndPanMode, TooltipPosition, LegendPosition, etc.\nusing LiveChartsCore.SkiaSharpView;              // LineSeries, ColumnSeries, Axis, etc. (non-XAML)\nusing LiveChartsCore.SkiaSharpView.Painting;     // SolidColorPaint, LinearGradientPaint, etc.\nusing LiveChartsCore.SkiaSharpView.WPF;          // CartesianChart, PieChart (WPF controls)\nusing LiveChartsCore.SkiaSharpView.Avalonia;     // CartesianChart, PieChart (Avalonia controls)\nusing LiveChartsCore.SkiaSharpView.Maui;         // CartesianChart, PieChart (MAUI controls)\nusing LiveChartsCore.SkiaSharpView.SKCharts;     // SKCartesianChart, SKPieChart (server-side)\nusing SkiaSharp;                                 // SKColor, SKPoint, SKPaint, etc.\n```\n\n---\n\n## API Reference URL Pattern\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\nUse `latest` as the version for the most recent docs, or a specific version string.\n`{objectFullName}` uses CLI metadata naming (e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`).\n\nFull docs: `https://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}`\n\nWhere `{UIFramework}` ∈ `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`.\n\n---\n\n## Frequently Asked Questions\n\n**Q: My chart is blank / not showing.**  \nA: The chart control has no default size constraint. Set an explicit `Width` and `Height`, or ensure the\nparent layout does not collapse the control to zero size.\n\n**Q: Changes to my data don't update the chart.**  \nA: Use `ObservableCollection<T>` for the `Series` collection and the `Values` collection.\nFor property-level updates, implement `INotifyPropertyChanged` on your data class (or use `ObservableValue`).\n\n**Q: How do I use LiveCharts without SkiaSharp?**  \nA: Implement the Core drawing interfaces (`IDrawingContext`, etc.) and register your custom renderer.\nThe `VorticeSample` in the repository demonstrates this using DirectX11 via Vortice.Windows.\n\n**Q: Can I use LiveCharts in a Blazor Server app?**  \nA: The official package targets Blazor WASM. For server-side use, use `SKCartesianChart` to generate\nPNG/JPEG images on the server and serve them as `<img>` tags.\n\n**Q: How do I disable animations?**  \nA: Set `myChart.EasingFunction = null;` or `myChart.AnimationsSpeed = TimeSpan.Zero;`.\n"},"items":[{"name":"llms-full.txt","path":"llms-full.txt","rawUrl":"https://raw.githubusercontent.com/Live-Charts/LiveCharts2/HEAD/llms-full.txt","title":"LLM Full Documentation Context","category":"root-instruction","format":"text","content":"# LiveCharts2 — Comprehensive Knowledge Base for LLMs\n\n> **⚠️ Version Warning:** This document covers **LiveCharts v2** (package prefix `LiveChartsCore.SkiaSharpView.*`).\n> The legacy **v0** (`LiveCharts` / `LiveCharts.Wpf`) is completely obsolete and has a different API.\n> Do NOT mix v0 and v2 syntax. v0 reference: https://github.com/Live-Charts/Live-Charts\n\n---\n\n## Overview\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET. It fixes the main design issues of its\npredecessor (v0), is focused on running everywhere, and improves flexibility. It uses **SkiaSharp** as its default\nrendering backend — a cross-platform 2D graphics API for .NET based on Google's Skia graphics library.\n\n- **Website / full docs:** https://livecharts.dev\n- **GitHub:** https://github.com/Live-Charts/LiveCharts2\n- **License:** MIT\n- **Current version:** 2.1.0 (check NuGet for latest stable/prerelease)\n- **Target frameworks (core):** `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **C# language version:** 14.0\n\n### Supported Platforms & NuGet Packages\n\n| Platform | NuGet package |\n|---|---|\n| MAUI | `LiveChartsCore.SkiaSharpView.Maui` |\n| Uno Platform (WinUI) | `LiveChartsCore.SkiaSharpView.Uno.WinUI` |\n| Avalonia | `LiveChartsCore.SkiaSharpView.Avalonia` |\n| WPF | `LiveChartsCore.SkiaSharpView.WPF` |\n| WinForms | `LiveChartsCore.SkiaSharpView.WinForms` |\n| WinUI | `LiveChartsCore.SkiaSharpView.WinUI` |\n| Blazor WASM | `LiveChartsCore.SkiaSharpView.Blazor` |\n| Eto.Forms | `LiveChartsCore.SkiaSharpView.Eto` |\n\nSkiaSharp minimum supported version: **2.88.9** (default: 3.119.0 for GPU support).\n\n---\n\n## Architecture\n\nThe library is divided into three main modules:\n\n### Core (`LiveChartsCore`)\n\nPlatform-agnostic. Contains:\n- A drawing **API** (interfaces) that defines all the shapes the library needs to build a chart\n- The charting engine: measures sizes, calculates positions for every geometry\n- The animation system (`Motion/` namespace) — `IAnimatable`, `MotionProperty`\n- Change-detection via `CollectionDeepObserver` (wraps `INotifyPropertyChanged` / `INotifyCollectionChanged`)\n- Series implementations: `LineSeries<T>`, `ColumnSeries<T>`, `PieSeries<T>`, `ScatterSeries<T>`, etc.\n\n### Renderer (`LiveChartsCore.SkiaSharp`)\n\nImplements the Core drawing API using SkiaSharp. Responsible for materializing geometry objects to pixels.\nYou can replace SkiaSharp with any other rendering engine (see `VorticeSample` using DirectX11 via Vortice.Windows).\n\n### View (platform packages)\n\nPlatform-specific controls (`CartesianChart`, `PieChart`, `PolarChart`, `GeoMap`) that:\n1. Ask the **Core** *what* to draw (geometry sizes and positions)\n2. Ask the **Renderer** *how* to draw it (render to the platform surface)\n\n### Animation System\n\nLiveCharts generates animations by producing many frames over time. Each animatable object has\n`MotionProperty` fields whose getter returns the *current interpolated value* for the current point\nin time — not the last assigned value. This means:\n\n```csharp\nvar line = new LineGeometry();\nline.X1 = 0;\nline.X1 = 100;\nvar x1 = line.X1; // returns 0 (animation has not elapsed yet)\n// After 5 seconds (of a 10s linear transition): line.X1 returns ~50\n```\n\n### Automatic Update Cycle\n\n1. User changes data (property or collection).\n2. `CollectionDeepObserver` detects the change via `INotifyPropertyChanged` / `INotifyCollectionChanged`.\n3. The chart **throttles** a *Measure request* (fires at most once every ~10 ms).\n4. On measure: Core recalculates geometry positions → Update cycle draws frames until all `MotionProperty` animations complete.\n\n---\n\n## Installation\n\n### Install via NuGet (pick your platform)\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView.WPF\ndotnet add package LiveChartsCore.SkiaSharpView.Avalonia\ndotnet add package LiveChartsCore.SkiaSharpView.Maui\ndotnet add package LiveChartsCore.SkiaSharpView.Blazor\ndotnet add package LiveChartsCore.SkiaSharpView.WinForms\ndotnet add package LiveChartsCore.SkiaSharpView.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Uno.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Eto\n```\n\n> **Note for WPF / WinForms:** By default these projects target `netX.0-windows`, but SkiaSharp 3 does not provide\n> a build for that TFM. Consider specifying a minimum Windows version: `net8.0-windows10.0.19041`.\n\n### Configure LiveCharts at startup\n\nCreate a `CustomLiveChartsExtensions` class (shared across all platforms):\n\n```csharp\nusing LiveChartsCore.Kernel;\nusing LiveChartsCore.SkiaSharpView;\n\npublic static partial class CustomLiveChartsExtensions\n{\n    public static LiveChartsSettings AddLiveChartsAppSettings(this LiveChartsSettings settings) =>\n        settings\n            .AddSkiaSharp()           // use SkiaSharp as renderer\n            .AddDefaultMappers()      // register built-in type mappers\n            .AddDefaultTheme()        // light/dark theme based on OS\n            // optionally register a mapper for a custom type:\n            .HasMap<City>((city, index) => new(index, city.Population));\n}\n```\n\n#### WPF — `App.xaml.cs`\n\n```csharp\nprotected override void OnStartup(StartupEventArgs e)\n{\n    base.OnStartup(e);\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n}\n```\n\n#### Avalonia — `App.axaml.cs`\n\n```csharp\npublic override void OnFrameworkInitializationCompleted()\n{\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    // ...\n}\n```\n\n#### MAUI — `MauiProgram.cs`\n\n```csharp\nbuilder\n    .UseMauiApp<App>()\n    .UseLiveCharts(config => config.AddLiveChartsAppSettings());\n```\n\n#### Blazor — `App.razor`\n\n```razor\n@inject IJSRuntime JS\n@code {\n    protected override async Task OnInitializedAsync()\n    {\n        LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    }\n}\n```\n\n---\n\n## Core Concepts\n\n### Series and Values\n\nEvery series is generic over its data type `T`. LiveCharts natively supports `short`, `int`, `long`, `float`,\n`double`, `decimal` and their nullable forms. It also provides observable wrappers:\n\n| Type | Use case |\n|---|---|\n| `ObservableValue` | Single Y value that notifies changes |\n| `ObservablePoint` | Explicit X and Y |\n| `WeightedPoint` | X, Y, Weight (bubble charts) |\n| `DateTimePoint` | X is `DateTime` |\n| `TimeSpanPoint` | X is `TimeSpan` |\n| `ObservablePolarPoint` | Polar charts |\n| `FinancialPoint` / `FinancialPointI` | OHLC candlestick charts |\n\n```csharp\n// simple array — static, no auto-update:\nnew LineSeries<double> { Values = new double[] { 1, 2, 3 } }\n\n// ObservableCollection — auto-updates when items are added/removed:\nvar values = new ObservableCollection<ObservableValue>();\nnew LineSeries<ObservableValue> { Values = values }\nvalues.Add(new ObservableValue(5));  // chart updates automatically\n```\n\n### Mappers\n\nUse a **mapper** to teach LiveCharts how to plot a custom type:\n\n```csharp\n// Per-series mapper:\nnew LineSeries<TempSample>\n{\n    Values = samples,\n    Mapping = (sample, index) => new Coordinate(sample.Time, sample.Temperature)\n}\n\n// Global mapper (applied to every series using TempSample):\nLiveCharts.Configure(config =>\n    config.HasMap<TempSample>((sample, index) => new Coordinate(sample.Time, sample.Temperature)));\n```\n\n### IChartEntity (high-performance custom types)\n\nImplement `IChartEntity` directly on your model for best performance (no delegate overhead per point):\n\n```csharp\npublic partial class TempSample : ObservableObject, IChartEntity\n{\n    [ObservableProperty] private int _time;\n    [ObservableProperty] private double _temperature;\n\n    public Coordinate Coordinate { get; protected set; }\n    public ChartEntityMetaData? MetaData { get; set; }\n\n    protected override void OnPropertyChanged(PropertyChangedEventArgs e)\n    {\n        Coordinate = new Coordinate(Time, Temperature);\n        base.OnPropertyChanged(e);\n    }\n}\n```\n\n### Paints\n\nA `Paint` is the v2 equivalent of WPF/Avalonia `Brush`. It wraps SkiaSharp's paint and adds animation support.\n\n```csharp\nusing SkiaSharp;\nusing LiveChartsCore.SkiaSharpView.Painting;\n\n// Solid color\nnew SolidColorPaint(SKColors.Blue) { StrokeThickness = 4 }\n\n// Linear gradient\nnew LinearGradientPaint(\n    new[] { new SKColor(255, 140, 148), new SKColor(220, 237, 194) },\n    new SKPoint(0.5f, 0),   // gradient start (center-top)\n    new SKPoint(0.5f, 1))   // gradient end   (center-bottom)\n\n// Radial gradient\nnew RadialGradientPaint(new SKColor(255, 96, 96), new SKColor(255, 234, 96))\n\n// null means \"do not draw\" (hides fill, stroke, etc.)\nFill = null\n```\n\nAvailable paint properties: `StrokeThickness`, `PathEffect` (for dashed lines), `ImageFilter`, etc.\n\n### Animations\n\nAll charts animate automatically. Customize with:\n\n```csharp\n// Chart-level speed:\nmyChart.AnimationsSpeed = TimeSpan.FromMilliseconds(300);\n\n// Easing function:\nmyChart.EasingFunction = EasingFunctions.BounceOut;\n\n// Disable animations:\nmyChart.AnimationsSpeed = TimeSpan.Zero;\n// or:\nmyChart.EasingFunction = null;\n```\n\nSeries and Axes also have their own `AnimationsSpeed` and `EasingFunction` properties\n(override the chart-level value when non-null).\n\n### Null / missing points\n\nSet a value to `null` or a `Coordinate` to `Coordinate.Empty` to create gaps:\n\n```csharp\nnew LineSeries<double?>\n{\n    Values = new double?[] { 2, 6, null, 3, 5 }\n}\n```\n\n### Hardware Acceleration (GPU)\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\n\nLiveCharts.Configure(c => c\n    .AddLiveChartsRenderSettings());  // see LiveChartsRenderSettings.cs in samples\n```\n\nGPU is disabled by default. On Avalonia/Uno with SkiaRenderer the GPU setting is ignored\n(the UI framework controls rendering).\n\n---\n\n## Chart Types\n\n### CartesianChart\n\nStandard X/Y chart. Hosts `Series` (collection of `ICartesianSeries`), `XAxes`, `YAxes`.\n\nSupports: `LineSeries`, `ColumnSeries`, `ScatterSeries`, `StepLineSeries`, `HeatSeries`,\n`CandlesticksSeries`, `StackedLineSeries`, `StackedColumnSeries`, `StackedStepLineSeries`, `BoxSeries`, `ErrorSeries`.\n\nKey properties: `Series`, `XAxes`, `YAxes`, `ZoomMode`, `AnimationsSpeed`, `TooltipPosition`, `LegendPosition`.\n\n### PieChart\n\nHosts `PieSeries<T>`. Used for pie, doughnut, gauge, and Nightingale rose charts.\n\n### PolarChart\n\nHosts `PolarLineSeries<T>` and `PolarScatterSeries<T>`. Uses polar (angle + radius) coordinates.\n\n### GeoMap\n\nDisplays geographic maps. Hosts `HeatLandSeries` to color countries/regions by value.\n\n---\n\n## XAML Integration (WPF, Avalonia, MAUI, WinUI)\n\n### XAML Types (Xaml-prefixed)\n\nEvery `Series<T>` and `Axis` has a XAML-friendly counterpart (prefix `Xaml`). These live in the visual tree\nand support data bindings, styles, hot-reload and designer previews:\n\n- `XamlLineSeries`, `XamlColumnSeries`, `XamlPieSeries`, `XamlScatterSeries`, etc.\n- `XamlAxis`, `XamlDrawnLabelVisual`\n\nThe non-Xaml types (`LineSeries<T>`, `ColumnSeries<T>`) are plain C# objects and do **not** live in the\nvisual tree — use them in ViewModels when you want to keep UI logic separate from SkiaSharp dependencies.\n\n### SeriesCollection (WPF / WinUI / Uno)\n\nWPF, WinUI and Uno use `SeriesCollection` as a container in XAML to hold multiple series children:\n\n```xml\n<lvc:CartesianChart.Series>\n    <lvc:SeriesCollection>\n        <lvc:XamlLineSeries Values=\"{Binding Values1}\"/>\n        <lvc:XamlColumnSeries Values=\"{Binding Values2}\"/>\n    </lvc:SeriesCollection>\n</lvc:CartesianChart.Series>\n```\n\nAvalonia and MAUI support multiple children directly (no wrapper needed).\n\n---\n\n## Code Examples\n\n### Example 1 — Basic Line Chart (WPF, code-behind + XAML MVVM)\n\n**ViewModel (shared, no UI dependencies):**\n\n```csharp\n// samples/ViewModelsSamples/Lines/Basic/ViewModel.cs\nnamespace ViewModelsSamples.Lines.Basic;\n\npublic class ViewModel\n{\n    public double[] Values1 { get; set; } = [2, 1, 3, 5, 3, 4, 6];\n    public int[]    Values2 { get; set; } = [4, 2, 5, 2, 4, 5, 3];\n}\n```\n\n**WPF View (View.xaml):**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Lines.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Lines.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n                <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n**Avalonia View (View.axaml):**\n\n```xml\n<UserControl\n    x:Class=\"AvaloniaSample.Lines.Basic.View\"\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n    xmlns:vms=\"using:ViewModelsSamples.Lines.Basic\"\n    x:DataType=\"vms:ViewModel\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 2 — Bar Chart with Axis Labels (WPF)\n\n**ViewModel:**\n\n```csharp\nnamespace ViewModelsSamples.Bars.Basic;\n\npublic class ViewModel\n{\n    public double[] MaryValues { get; set; } = [2, 5, 4];\n    public double[] AnaValues  { get; set; } = [3, 1, 6];\n    public string[] Labels     { get; set; } = [\"Category 1\", \"Category 2\", \"Category 3\"];\n}\n```\n\n**WPF View:**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Bars.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Bars.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart LegendPosition=\"Right\">\n\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlColumnSeries SeriesName=\"Mary\" Values=\"{Binding MaryValues}\"/>\n                <lvc:XamlColumnSeries SeriesName=\"Ana\"  Values=\"{Binding AnaValues}\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n\n        <lvc:CartesianChart.XAxes>\n            <lvc:AxesCollection>\n                <lvc:XamlAxis\n                    Labels=\"{Binding Labels}\"\n                    SeparatorsPaint=\"#c8c8c8\"\n                    SeparatorsAtCenter=\"False\"\n                    TicksPaint=\"#232323\"\n                    TicksAtCenter=\"True\"\n                    MinStep=\"1\"\n                    ForceStepToMin=\"True\"/>\n            </lvc:AxesCollection>\n        </lvc:CartesianChart.XAxes>\n\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 3 — Real-Time Chart (shared ViewModel, any platform)\n\nAdds a new `DateTimePoint` every 100 ms using `ObservableCollection` — the chart updates automatically\nbecause `ObservableCollection` implements `INotifyCollectionChanged`.\n\n```csharp\nusing System;\nusing System.Collections.ObjectModel;\nusing System.Threading.Tasks;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing LiveChartsCore.Defaults;\n\nnamespace ViewModelsSamples.General.RealTime;\n\npublic partial class ViewModel : ObservableObject\n{\n    public ViewModel() { _ = ReadData(); }\n\n    // 'partial' is required by CommunityToolkit.Mvvm source generator (C# 14 partial properties)\n    [ObservableProperty]\n    public partial double[] Separators { get; set; } = [];\n\n    public ObservableCollection<DateTimePoint> Values { get; set; } = [];\n\n    public Func<DateTime, string> LabelsFormatter { get; } =\n        date => (DateTime.Now - date).TotalSeconds < 1 ? \"now\" : $\"{(DateTime.Now - date).TotalSeconds:N0}s ago\";\n\n    // Use a lock so background thread writes are safe\n    public object Sync { get; } = new object();\n    public bool IsReading { get; set; } = true;\n\n    private async Task ReadData()\n    {\n        var random = new Random();\n        while (IsReading)\n        {\n            await Task.Delay(100);\n            lock (Sync)\n            {\n                Values.Add(new DateTimePoint(DateTime.Now, random.Next(0, 10)));\n                if (Values.Count > 250) Values.RemoveAt(0);\n                Separators = GetSeparators();\n            }\n        }\n    }\n\n    private static double[] GetSeparators()\n    {\n        var now = DateTime.Now;\n        return [\n            now.AddSeconds(-25).Ticks,\n            now.AddSeconds(-20).Ticks,\n            now.AddSeconds(-15).Ticks,\n            now.AddSeconds(-10).Ticks,\n            now.AddSeconds(-5).Ticks,\n            now.Ticks\n        ];\n    }\n}\n```\n\n> **Threading note:** When updating chart data from a non-UI thread, use a lock object (`Sync`) and assign\n> it to the chart's `SyncContext` property so LiveCharts can coordinate reads/writes safely.\n\n---\n\n### Example 4 — Pie Chart with Named Slices\n\n```csharp\nnamespace ViewModelsSamples.Pies.Basic;\n\npublic class PieData(string name, double value)\n{\n    public string Name   { get; set; } = name;\n    public double[] Values { get; set; } = [value];\n}\n\npublic class ViewModel\n{\n    public PieData[] Data { get; set; } =\n    [\n        new(\"Mary\",    10),\n        new(\"John\",    20),\n        new(\"Alice\",   30),\n        new(\"Bob\",     40),\n        new(\"Charlie\", 50),\n    ];\n}\n```\n\n**WPF View (using XAML template):**\n\n```xml\n<lvc:PieChart SeriesSource=\"{Binding Data}\">\n    <lvc:PieChart.SeriesTemplate>\n        <DataTemplate>\n            <lvc:XamlPieSeries\n                SeriesName=\"{Binding Name}\"\n                Values=\"{Binding Values}\"/>\n        </DataTemplate>\n    </lvc:PieChart.SeriesTemplate>\n</lvc:PieChart>\n```\n\n---\n\n### Example 5 — Custom Mapper (CLI / Console / Server)\n\nRender a chart to an image without any UI framework using `SKCartesianChart`:\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\nusing LiveChartsCore.SkiaSharpView;\n\n// Custom data type\npublic class TempSample { public int Time { get; set; } public double Temperature { get; set; } }\n\nvar samples = new[]\n{\n    new TempSample { Time = 1, Temperature = 65.65 },\n    new TempSample { Time = 5, Temperature = 62.23 },\n    new TempSample { Time = 8, Temperature = 85.12 },\n};\n\nvar chart = new SKCartesianChart\n{\n    Width  = 900,\n    Height = 600,\n    Series = new[]\n    {\n        new LineSeries<TempSample>\n        {\n            Values  = samples,\n            Mapping = (sample, index) => new(sample.Time, sample.Temperature)\n        }\n    },\n    XAxes = new[] { new Axis { Labeler = value => $\"{value} s\" } },\n    YAxes = new[] { new Axis { Labeler = value => $\"{value} °C\" } },\n};\n\nchart.SaveImage(\"chart.png\");\n```\n\n---\n\n## Axes\n\nThe `CartesianChart` exposes `XAxes` and `YAxes` (both `IEnumerable<IAxis>`). Default: one `Axis` each.\n\n### Key Axis properties\n\n| Property | Description |\n|---|---|\n| `Labeler` | `Func<double, string>` — formats axis tick labels |\n| `Labels` | `IList<string>` — named labels (index-based, used for category axes) |\n| `MinLimit` / `MaxLimit` | Fix the visible range (used for zooming/panning) |\n| `MinStep` / `ForceStepToMin` | Force minimum separation between ticks |\n| `SeparatorsPaint` | Paint for grid lines |\n| `TicksPaint` | Paint for axis tick marks |\n| `NamePaint` | Paint for the axis name label |\n| `DataLabelsPaint` | Paint for data labels on the series |\n| `CrosshairPaint` | Paint for crosshair lines |\n| `IsVisible` | Show/hide the axis |\n| `Position` | `AxisPosition.Start` or `AxisPosition.End` |\n\n### Zooming and Panning\n\n```csharp\n// Enable X-axis zoom and pan:\nmyChart.ZoomMode = ZoomAndPanMode.X;\n\n// Enable both axes:\nmyChart.ZoomMode = ZoomAndPanMode.Both;\n\n// Disable:\nmyChart.ZoomMode = ZoomAndPanMode.None;\n```\n\nEach gesture also has its own flag (`PanX`, `ZoomX`, `PanY`, `ZoomY`) so zoom and pan can be enabled independently. The composites `X = PanX | ZoomX`, `Y = PanY | ZoomY` and `Both = X | Y` keep their original pan+zoom semantics.\n\n```csharp\n// Allow zooming on the X axis but disable panning (e.g. so pan gestures don't hide tooltips on mobile):\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX;\n\n// Zoom on X, pan on Y:\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY;\n```\n\n`ZoomAndPanMode` is a flags enum — combine values:\n```csharp\nmyChart.ZoomMode = ZoomAndPanMode.X | ZoomAndPanMode.NoFit | ZoomAndPanMode.NoZoomBySection;\n```\n\n### DateTime / TimeSpan Axes\n\nUse `DateTimePoint` or `TimeSpanPoint` for time-based X axes and format with a `Labeler`:\n\n```csharp\nXAxes = new[]\n{\n    new Axis\n    {\n        Labeler = value => new DateTime((long)value).ToString(\"HH:mm:ss\"),\n        UnitWidth = TimeSpan.FromSeconds(1).Ticks,\n        MinStep  = TimeSpan.FromSeconds(1).Ticks,\n    }\n};\n```\n\n---\n\n## Tooltips & Legends\n\n```csharp\n// Tooltip position options: Top (default), Bottom, Left, Right, Center, Hidden\nmyChart.TooltipPosition = TooltipPosition.Bottom;\n\n// Legend position: Hidden (default), Top, Bottom, Left, Right\nmyChart.LegendPosition = LegendPosition.Right;\n```\n\nCustom tooltips: implement `IChartTooltip<TDrawingContext>` and assign to `Chart.Tooltip`.  \nCustom legends: implement `IChartLegend<TDrawingContext>` and assign to `Chart.Legend`.\n\n---\n\n## Sections (Reference Lines / Bands)\n\n```csharp\nusing LiveChartsCore;\n\nmyChart.Sections = new[]\n{\n    new RectangularSection\n    {\n        Yi = 4,\n        Yj = 8,\n        Fill = new SolidColorPaint(new SKColor(255, 205, 210, 100))\n    }\n};\n```\n\n---\n\n## Drawing on Canvas\n\nUse `Chart.VisualElements` to overlay custom SkiaSharp drawing:\n\n```csharp\nmyChart.VisualElements = new[]\n{\n    new DrawnVisual\n    {\n        OnDraw = (canvas, chart) =>\n        {\n            canvas.DrawText(\"Hello!\", new SKPoint(100, 100), new SKPaint { Color = SKColors.Black });\n        }\n    }\n};\n```\n\n---\n\n## Server-Side / Console Chart Generation\n\nInstall only the core packages (no UI framework required):\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView\n```\n\nUse `SKCartesianChart`, `SKPieChart`, `SKPolarChart`, `SKGeoMap` — they all inherit from `InMemorySkiaSharpChart`\nand expose a `GetImage()` method that returns an `SKImage`:\n\n```csharp\nvar chart = new SKCartesianChart\n{\n    Width = 900, Height = 600,\n    Series = new ISeries[] { new LineSeries<int> { Values = new[] { 1, 2, 3 } } }\n};\n\n// Save to file:\nchart.SaveImage(\"output.png\");\n\n// Or get bytes for HTTP response:\nusing var image  = chart.GetImage();\nusing var data   = image.Encode(SKEncodedImageFormat.Png, 100);\nusing var stream = data.AsStream();\n```\n\n---\n\n## Multi-threading\n\nWhen modifying chart data from a background thread, always use a `lock`:\n\n```csharp\n// 1. Define a sync object in your ViewModel:\npublic object Sync { get; } = new object();\n\n// 2. Assign it to the chart control (XAML or code-behind):\n//    myChart.SyncContext = viewModel.Sync;\n\n// 3. Wrap all data mutations in the lock:\nlock (Sync)\n{\n    Values.Add(new ObservableValue(random.Next(0, 10)));\n    if (Values.Count > 200) Values.RemoveAt(0);\n}\n```\n\n---\n\n## Themes and Color Palettes\n\n```csharp\nLiveCharts.Configure(settings =>\n    settings\n        .AddDefaultTheme(theme =>\n            theme.OnInitialized(() =>\n            {\n                theme.AnimationsSpeed  = TimeSpan.FromMilliseconds(300);\n                theme.EasingFunction   = EasingFunctions.QuadraticOut;\n                theme.Colors           = ColorPalletes.MaterialDesign500;\n            })));\n```\n\nBuilt-in palettes: `MaterialDesign200`, `MaterialDesign500`, `MaterialDesign800`, `FluentDesign`, etc.\n\n---\n\n## Common Namespaces\n\n```csharp\nusing LiveChartsCore;                            // ISeries, IAxis, LiveCharts.Configure, etc.\nusing LiveChartsCore.Defaults;                   // ObservableValue, ObservablePoint, DateTimePoint, etc.\nusing LiveChartsCore.Kernel;                     // Coordinate, ChartEntityMetaData, IChartEntity\nusing LiveChartsCore.Measure;                    // ZoomAndPanMode, TooltipPosition, LegendPosition, etc.\nusing LiveChartsCore.SkiaSharpView;              // LineSeries, ColumnSeries, Axis, etc. (non-XAML)\nusing LiveChartsCore.SkiaSharpView.Painting;     // SolidColorPaint, LinearGradientPaint, etc.\nusing LiveChartsCore.SkiaSharpView.WPF;          // CartesianChart, PieChart (WPF controls)\nusing LiveChartsCore.SkiaSharpView.Avalonia;     // CartesianChart, PieChart (Avalonia controls)\nusing LiveChartsCore.SkiaSharpView.Maui;         // CartesianChart, PieChart (MAUI controls)\nusing LiveChartsCore.SkiaSharpView.SKCharts;     // SKCartesianChart, SKPieChart (server-side)\nusing SkiaSharp;                                 // SKColor, SKPoint, SKPaint, etc.\n```\n\n---\n\n## API Reference URL Pattern\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\nUse `latest` as the version for the most recent docs, or a specific version string.\n`{objectFullName}` uses CLI metadata naming (e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`).\n\nFull docs: `https://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}`\n\nWhere `{UIFramework}` ∈ `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`.\n\n---\n\n## Frequently Asked Questions\n\n**Q: My chart is blank / not showing.**  \nA: The chart control has no default size constraint. Set an explicit `Width` and `Height`, or ensure the\nparent layout does not collapse the control to zero size.\n\n**Q: Changes to my data don't update the chart.**  \nA: Use `ObservableCollection<T>` for the `Series` collection and the `Values` collection.\nFor property-level updates, implement `INotifyPropertyChanged` on your data class (or use `ObservableValue`).\n\n**Q: How do I use LiveCharts without SkiaSharp?**  \nA: Implement the Core drawing interfaces (`IDrawingContext`, etc.) and register your custom renderer.\nThe `VorticeSample` in the repository demonstrates this using DirectX11 via Vortice.Windows.\n\n**Q: Can I use LiveCharts in a Blazor Server app?**  \nA: The official package targets Blazor WASM. For server-side use, use `SKCartesianChart` to generate\nPNG/JPEG images on the server and serve them as `<img>` tags.\n\n**Q: How do I disable animations?**  \nA: Set `myChart.EasingFunction = null;` or `myChart.AnimationsSpeed = TimeSpan.Zero;`.\n","isInternal":false,"tokens":6877,"sizeBytes":26660},{"name":"llms.txt","path":"llms.txt","rawUrl":"https://raw.githubusercontent.com/Live-Charts/LiveCharts2/HEAD/llms.txt","title":"LLM Index & Context Digest","category":"root-instruction","format":"text","content":"# LiveCharts2\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET built on top of SkiaSharp for rendering; it supports Cartesian, Pie, Polar, and GeoMap chart types with smooth, automatic animations. The library uses a layered architecture separating a platform-agnostic Core from a SkiaSharp-based Renderer and platform-specific Views (WPF, Avalonia, MAUI, Blazor, etc.), so adding a new platform requires minimal effort. LiveCharts2 targets .NET Framework 4.6.2, .NET Standard 2.0, and modern .NET, and uses `INotifyPropertyChanged`/`INotifyCollectionChanged` for zero-boilerplate automatic chart updates.\n\n> **⚠️ Important: This is LiveCharts v2. Do NOT use v0 syntax.**\n> The legacy v0 (`LiveCharts` / `LiveCharts.Wpf` NuGet packages) is obsolete and has a completely different API.\n> v0 source and samples: https://github.com/Live-Charts/Live-Charts\n> Always use the v2 packages listed below and the v2 documentation at https://livecharts.dev.\n\n## Supported UI Frameworks\n\n- **MAUI** — `LiveChartsCore.SkiaSharpView.Maui` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.maui\n- **Uno Platform (WinUI)** — `LiveChartsCore.SkiaSharpView.Uno.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.Uno.WinUI\n- **Avalonia** — `LiveChartsCore.SkiaSharpView.Avalonia` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.avalonia\n- **WPF** — `LiveChartsCore.SkiaSharpView.WPF` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.wpf\n- **WinForms** — `LiveChartsCore.SkiaSharpView.WinForms` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.winforms\n- **WinUI** — `LiveChartsCore.SkiaSharpView.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.winui\n- **Blazor (WASM)** — `LiveChartsCore.SkiaSharpView.Blazor` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.blazor\n- **Eto.Forms** — `LiveChartsCore.SkiaSharpView.Eto` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.eto\n\n## URL Templates\n\n### API Reference\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\n- `{objectFullName}` follows CLI (Common Language Infrastructure) metadata naming conventions, e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `{LiveChartsVersion}`: use `latest` for the latest version, or a specific version string (e.g. `2.0.0-rc6.1`)\n- Full list of available versions: `https://livecharts.dev/docs/{UIFramework}/list`\n  - `{UIFramework}` is one of: `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`\n\n**Examples:**\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.Avalonia.PieChart`\n\n### Documentation & Examples\n\n```\nhttps://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}\n```\n\n`{UIFramework}` and `{LiveChartsVersion}` are as described above.\n\nAvailable `{ArticleName}` values:\n\n**Overview**\n- `Overview.Installation`\n- `Overview.How%20it%20works`\n- `Overview.Automatic%20updates`\n- `Overview.Mappers`\n- `Overview.Paints`\n- `Overview.Animations`\n\n**Cartesian Chart**\n- `CartesianChart.Cartesian%20chart%20control`\n- `CartesianChart.Axes%20properties`\n- `CartesianChart.Tooltips`\n- `CartesianChart.Legends`\n- `CartesianChart.Line%20series%20properties`\n- `CartesianChart.Column%20series%20properties`\n- `CartesianChart.Scatter%20series%20properties`\n- `CartesianChart.Step%20line%20series%20properties`\n- `CartesianChart.Heat%20series%20properties`\n- `CartesianChart.Candle%20sticks%20series%20properties`\n- `CartesianChart.Stacked%20line%20series%20properties`\n- `CartesianChart.Stacked%20column%20series%20properties`\n- `CartesianChart.Stacked%20step%20line%20series%20properties`\n- `CartesianChart.Box%20series%20properties`\n\n**Pie Chart**\n- `PieChart.Pie%20chart%20control`\n- `PieChart.Pie%20series`\n- `PieChart.Gauges`\n\n**Polar Chart**\n- `PolarChart.Polar%20chart%20control`\n- `PolarChart.Polar%20line%20series`\n\n**GeoMap**\n- `GeoMap.GeoMap%20control`\n- `GeoMap.Heat%20land%20series`\n\n**About**\n- `About.About%20this%20samples`\n\n**Samples**\n- `samples.lines.basic`\n- `samples.lines.straight`\n- `samples.lines.area`\n- `samples.lines.custom`\n- `samples.lines.custompoints`\n- `samples.lines.autoupdate`\n- `samples.lines.xy`\n- `samples.lines.zoom`\n- `samples.steplines.basic`\n- `samples.stackedArea.basic`\n- `samples.stackedArea.stepArea`\n- `samples.bars.basic`\n- `samples.bars.withBackground`\n- `samples.bars.custom`\n- `samples.bars.spacing`\n- `samples.bars.layered`\n- `samples.bars.rowsWithLabels`\n- `samples.bars.delayedAnimation`\n- `samples.bars.race`\n- `samples.stackedBars.basic`\n- `samples.stackedBars.groups`\n- `samples.pies.basic`\n- `samples.pies.pushout`\n- `samples.pies.doughnut`\n- `samples.pies.outlabels`\n- `samples.pies.custom`\n- `samples.pies.icons`\n- `samples.pies.nightingaleRose`\n- `samples.pies.nested`\n- `samples.pies.gauge1`\n- `samples.pies.gauge2`\n- `samples.pies.gauge3`\n- `samples.pies.gauge4`\n- `samples.pies.gauge5`\n- `samples.pies.angularGauge`\n- `samples.error.basic`\n- `samples.box.basic`\n- `samples.scatter.basic`\n- `samples.scatter.bubbles`\n- `samples.scatter.custom`\n- `samples.financial.basicCandlesticks`\n- `samples.heat.basic`\n- `samples.polar.basic`\n- `samples.polar.radialArea`\n- `samples.polar.coordinates`\n- `samples.maps.world`\n- `samples.events.tutorial`\n- `samples.events.addPointOnClick`\n- `samples.axes.labelsFormat`\n- `samples.axes.labelsFormat2`\n- `samples.axes.multiple`\n- `samples.axes.shared`\n- `samples.axes.style`\n- `samples.axes.crosshairs`\n- `samples.axes.dateTimeScaled`\n- `samples.axes.timeSpanScaled`\n- `samples.axes.matchScale`\n- `samples.axes.logarithmic`\n- `samples.axes.customSeparatorsInterval`\n- `samples.axes.paging`\n- `samples.general.multiThreading`\n- `samples.general.realTime`\n- `samples.general.sections`\n- `samples.general.chartToImage`\n- `samples.general.visualElements`\n- `samples.general.visibility`\n- `samples.general.nullPoints`\n- `samples.general.customTooltips`\n- `samples.general.customLegends`\n- `samples.general.mapPoints`\n- `samples.general.drawOnCanvas`\n- `samples.general.conditionalDraw`\n- `samples.general.scrollable`\n- `samples.design.linearGradients`\n- `samples.design.radialGradients`\n- `samples.design.strokeDashArray`\n","isInternal":false,"tokens":1775,"sizeBytes":6326},{"name":"SKILL.md","path":".claude/skills/render-chart/SKILL.md","rawUrl":"https://raw.githubusercontent.com/Live-Charts/LiveCharts2/HEAD/.claude/skills/render-chart/SKILL.md","title":"render-chart","category":"anthropic-skill","format":"markdown","content":"---\nname: render-chart\ndescription: Use when the user asks to render, visualize, plot, or \"show me a chart of\" any kind of series data (line, column, row, scatter, stacked, candlestick, box, pie, polar, heat). Renders via the `lvc` CLI from a JSON spec — inline in your reply for simple charts you need to read, or in a new terminal window for interactive / color-dependent ones (heat maps, pies with many slices, anything with > 3 series the user wants to explore).\n---\n\n# render-chart\n\nThe user wants to *see* data as a chart. You have access to a renderer (`lvc`)\nthat writes LiveCharts to a terminal. Pick the right mode for the situation,\ninstall the tool if it's missing, and either inline the result in your reply\nor hand the user a live window.\n\n## Decision: inline vs live window\n\n| Situation | Mode | Why |\n| --- | --- | --- |\n| ≤ 3 series, line / column / row / stacked-bar / scatter, you need to *verify* the shape | `--no-color` inline | Plain Braille glyphs render in a fenced code block. You can read it; the user sees it. |\n| User said \"open this in a new window\" / \"let me play with it\" / \"zoom into this\" | `--live` in a new terminal | Interactive Sixel + mouse hover + wheel zoom + click-drag pan. The user explores; you can't read the result, so don't pretend to. |\n| Heat map | `--live` in a new terminal | Heat reads the gradient by color. Strip color and it's an undifferentiated blob. |\n| Pie with > 4 slices | `--live` in a new terminal | Outer labels collide and Pushout gaps stop reading at small canvas sizes. |\n| Anything where the *meaning* depends on color (gradient encodes magnitude, similar curves only separable by hue) | `--live` in a new terminal | Plain mode can't carry color information — see [[reference_claude_code_cli_ansi_passthrough]]. |\n| User asks to \"compare these two/three series\" with simple shapes | `--no-color` inline | Single bar series stays Braille; multi-bar uses textures; line series get end-of-line labels. Distinguishable without color. |\n\n**Default to `--no-color` inline** when you can read the chart — it keeps the\nconversation flowing and you can describe what's in it. Reserve `--live` for\nwhen there's genuinely no way to convey the information in monochrome glyphs.\n\n## Step 1 — make sure dotnet is installed\n\n```sh\ndotnet --version\n```\n\nIf that errors, the user needs the .NET 8 SDK or runtime. Point them at\n<https://dotnet.microsoft.com/download> and stop — don't try to install it\nfor them (admin install, varies per OS).\n\n## Step 2 — install `lvc` as a global tool (once)\n\n```sh\ndotnet tool install -g LiveChartsCore.Console.Cli\n```\n\nIf they already have it, this errors with \"already installed\" — that's fine.\nUpdate with `dotnet tool update -g LiveChartsCore.Console.Cli`.\n\nAfter install, `lvc` is on the user's PATH. Verify with:\n\n```sh\nlvc --json '{\"kind\":\"line\",\"series\":[{\"values\":[1,2,3,2,1]}]}' --no-color\n```\n\nYou should see a small Braille line chart in stdout.\n\n## Step 3 — write the JSON spec\n\nPass via `--json '<spec>'`, `--file path.json`, or pipe stdin.\n\n```json\n{\n  \"kind\": \"line\",\n  \"title\": \"optional\",\n  \"width\": 70,\n  \"height\": 20,\n  \"series\": [\n    {\n      \"name\": \"Signal\",\n      \"values\": [1, 2, 3, 4],\n      \"strokeThickness\": 2\n    }\n  ],\n  \"xAxis\": { \"name\": \"X\", \"labels\": [\"a\", \"b\", \"c\", \"d\"] },\n  \"yAxis\": { \"name\": \"Y\" }\n}\n```\n\n`kind` accepts: `line`, `column`, `row`, `step`, `scatter`, `stackedcolumn`,\n`stackedrow`, `stackedarea`, `candlestick`, `box`, `pie`, `polar`.\n\nSeries shape:\n- `values: number[]` — line / column / row / step / stacked / pie / polar\n- `points: number[][]` — scatter (`[x, y]`) / candlestick (`[open, high, close, low]`) / box (`[max, q3, q1, median, min]`)\n- `strokeThickness: number` — line / step (optional, default 1)\n\nFor pie: needs `--width ≥ 80 --height ≥ 30` (outer labels collide otherwise).\nFor stacked column / row with 2+ series: per-series textures auto-applied in\nplain mode; legend shows the texture next to each series name.\n\n## Step 4a — inline rendering (the common path)\n\n```sh\nlvc --json '<spec>' --no-color --width 70 --height 20\n```\n\nCapture the output and paste it back inside a fenced code block in your reply.\nCommonMark renders it monospace, the user sees the same glyphs you see.\n\nSizing: ~70×20 is a sweet spot. Smaller charts get cramped; larger ones might\nwrap weirdly in the user's terminal. Default to 70×20 unless the user asked\notherwise.\n\nRead what you rendered. Describe what's in it — \"the blue series climbs from\n~5 to ~12, the red oscillates around 8\" — so the user can sanity-check it\nmatches what they wanted. Don't claim \"the chart looks correct\" without\nnaming the actual shapes you see.\n\n## Step 4b — live window (interactive / color path)\n\nSpawn a new terminal so it doesn't block your conversation:\n\n**Windows (Windows Terminal):**\n```pwsh\nStart-Process wt.exe -ArgumentList '-d', $pwd.Path, 'pwsh', '-NoExit', '-NoLogo', '-Command', 'lvc --live --file demo.json'\n```\n\n**macOS (Terminal.app):**\n```sh\nosascript -e \"tell app \\\"Terminal\\\" to do script \\\"lvc --live --file $PWD/demo.json\\\"\"\n```\n\n**Linux (GNOME Terminal):**\n```sh\ngnome-terminal --working-directory=\"$PWD\" -- lvc --live --file demo.json\n```\n\nFor multi-line JSON, write a `demo.json` file first via the Write tool and\npass `--file` — avoids cross-shell quoting hell.\n\n**Critical:** you can't read the live window's contents. After launching,\ntell the user \"I opened a chart in a new window — what do you see?\" and\niterate from their feedback. Don't fabricate a description of what's\n\"probably there.\"\n\nIn the live window the user gets: mouse hover (tooltips), click-and-drag (pan),\nmouse wheel (zoom), `q` (quit), `r` (reset zoom), `+` / `-` (zoom at center).\n\n## Common pitfalls\n\n- **`--live --no-color`** is an error: live mode redraws frames in place via\n  ANSI escapes, which is exactly what `--no-color` strips. Pick one.\n- **`--live` with stdout redirected** errors out — it needs a real TTY. Always\n  spawn a new terminal window, never pipe `--live` output.\n- **`--mode sixel --no-color`** errors out — Sixel is a binary escape sequence\n  with no plain form. Drop `--mode sixel` or drop `--no-color`.\n- **Pie charts in plain mode at small canvases** collapse the disc to a sliver\n  because outer labels reserve margin space. Use `--width 80 --height 30`\n  minimum, or accept a smaller render in `--live` mode where the disc has\n  full canvas.\n- **Stacked bar plain mode with 1 series** keeps Braille `⣿` fills (no\n  textures kick in until 2+ bar series exist). This is intentional.\n- **You cannot see colors in the user's terminal from your own output.** Inline\n  ANSI escapes you write get collapsed to one inline-code style by the\n  CommonMark renderer — see [[reference_claude_code_cli_ansi_passthrough]].\n  This is why `--no-color` is the inline path: plain glyphs don't pretend to\n  carry color information.\n\n## When NOT to use this skill\n\n- The user asks to *edit chart configuration* in a LiveCharts app (XAML /\n  source-code view) — that's a code-edit task, not a rendering task.\n- The user wants to *understand* a chart they already have a screenshot of —\n  use vision on the image, not lvc.\n- The data is structural / hierarchical (trees, graphs, org charts) — lvc\n  only handles statistical chart kinds.\n","frontmatter":{"name":"render-chart","description":"Use when the user asks to render, visualize, plot, or \"show me a chart of\" any kind of series data (line, column, row, scatter, stacked, candlestick, box, pie, polar, heat). Renders via the `lvc` CLI from a JSON spec — inline in your reply for simple charts you need to read, or in a new terminal window for interactive / color-dependent ones (heat maps, pies with many slices, anything with > 3 series the user wants to explore)."},"isInternal":false,"tokens":1966,"sizeBytes":7317},{"name":"SKILL.md","path":".claude/skills/repro-and-fix/SKILL.md","rawUrl":"https://raw.githubusercontent.com/Live-Charts/LiveCharts2/HEAD/.claude/skills/repro-and-fix/SKILL.md","title":"repro-and-fix","category":"anthropic-skill","format":"markdown","content":"---\nname: repro-and-fix\ndescription: Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. \"let's work on issue #1234\", a github.com/Live-Charts/LiveCharts2/issues/N URL, or \"reproduce and propose a fix\"). Implements the LiveCharts workflow end-to-end — worktree, in-sample repro view, auto-launched sample, screenshot/log verification, diagnosis, fix, separate regression-test commit, and PR — with minimal user interaction.\n---\n\n# repro-and-fix\n\nA user pointed you at a GitHub issue and asked you to reproduce + fix it. Run\nthe workflow below. The whole point is that the dev loop is *self-contained*:\nyou build the repro, launch the sample at that repro automatically, verify the\nbug yourself (screenshot or logs), fix it, verify the fix, and commit. Don't\nask the user for visual confirmations you can get yourself.\n\n> **Shared with Copilot Coding Agent.** `.github/copilot-instructions.md` links\n> here as the canonical issue → reproduce → fix → PR workflow. Edit this file\n> when changing the workflow; keep the Copilot doc as a thin pointer to avoid\n> drift.\n\n## When this skill applies\n\n- \"Let's work on https://github.com/Live-Charts/LiveCharts2/issues/N\"\n- \"Reproduce issue #N and propose a fix\"\n- \"Investigate this bug report: <URL>\"\n- A user paste of an issue URL with no other instruction\n\nIf the user is asking about *theory* (\"why does the gauge use a doughnut\ngeometry?\") or a *non-issue* task (refactor, doc update, perf), this skill is\nnot the right tool — fall back to general workflow.\n\n## Pick the platform that matches the issue\n\nRead the issue's **labels** and **repro snippet** to choose. The workflow is\nthe same on every XAML platform — only paths and launch commands change.\n\n| Platform | Sample dir                    | Launch project (Debug build)                                                | In-app screenshot |\n| -------- | ----------------------------- | --------------------------------------------------------------------------- | ----------------- |\n| Avalonia | `samples/AvaloniaSample/`     | `samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/.../*.Desktop.exe` | ✅ supported       |\n| WPF      | `samples/WPFSample/`          | `samples/WPFSample/.../WPFSample.exe`                                       | ✅ supported       |\n| WinUI    | `samples/WinUISample/WinUISample/` | `samples/WinUISample/WinUISample/.../WinUISample.exe`                  | ✅ supported       |\n| MAUI     | `samples/MauiSample/`         | per-platform; `dotnet build -t:Run -f net10.0-windows10.0.19041.0`          | ❌ use OS tool     |\n| Uno      | `samples/UnoPlatformSample/UnoPlatformSample/` | per-platform                                              | ❌ use OS tool     |\n\nIf the issue is platform-agnostic (a core engine bug), prefer Avalonia for the\nfastest dev loop on Windows (no WindowsAppSDK / packaged-build overhead).\n\n## Project conventions you must follow\n\nThese are durable rules from `~/.claude/projects/.../memory/MEMORY.md`. Re-read\nthe relevant memory file if uncertain — these are not optional:\n\n- **Worktree per issue.** Create `../LiveCharts2-fix-<issue>-<slug>` first\n  (`feedback_worktree_per_issue`). Don't work in the primary tree.\n- **One concept per commit.** Fix and regression test go in *separate* commits.\n  The regression-test commit must fail when the fix is reverted — verify this\n  before pushing (`feedback_commit_separation`).\n- **Snapshot tests for render-path changes.** If your fix touches paint, layout,\n  z-index, or draw order, run `tests/SnapshotTests/` before claiming done — unit\n  tests have missed catastrophic regressions\n  (`feedback_run_snapshots_for_render_changes`).\n- **Update docs when public API changes** in the same change set as a separate\n  commit (`feedback_update_docs_for_api`).\n- Check `Directory.Build.props` for `<LiveChartsVersion>` and use that value in\n  user-facing text (`project_current_version`).\n\n## Workflow\n\n### 1. Read the issue and decide if it still reproduces\n\n```bash\ngh issue view <N> --repo Live-Charts/LiveCharts2 --json title,body,labels,state,comments\n```\n\nPay attention to **comments**, not just the body. Issues commonly evolve:\n\n- The original symptom may already be fixed in main (commenter says \"newer\n  releases fixed this\") and the *current* bug is a downstream observation.\n  This is exactly what happened with #2008 — the `GaugeValue` TemplateBinding\n  bug in the title was already resolved; the live bug was a `CornerRadius=0`\n  override in the comments.\n- Multiple users may report different things in the same thread. Identify the\n  most recent reporter's actual symptom.\n\nIf you suspect the title bug is already fixed: build the original repro\nverbatim and verify *first*, before doing diagnosis. Cite the commenter who\nsaid it's fixed in your PR description.\n\n### 2. Set up the worktree\n\n```bash\ngit worktree add ../LiveCharts2-fix-<issue>-<short-slug> -b fix/issue-<N>-<short-slug>\n```\n\nAll edits, builds, and runs happen in the worktree. The primary tree stays\nclean for other work.\n\n### 3. Build the repro view (XAML platforms)\n\nThe repro convention is a **sample view inside the platform sample app**:\n\n```\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>.cs\n```\n\nMatch the issue's repro setup as closely as you can — same `ControlTemplate`\nshape, same property values, same paints. *Don't simplify* until you've\nconfirmed the bug fires; over-minimization can accidentally avoid the trigger.\n\nExisting repros to mirror:\n\n- `samples/AvaloniaSample/VisualTest/Issue1986Repro/` — TabControl + ScrollViewer\n- `samples/AvaloniaSample/VisualTest/Issue1417Repro/` — GeoMap reattach\n\nThe View's code-behind should expose helpers that a Factos test can call\n(e.g. `FindTemplatedGaugeSeries()`). This is how the regression test hooks in\nwithout going through the visual tree.\n\n**Do not commit changes to `samples/ViewModelsSamples/Index.cs` for repro\nviews.** Factos navigates to a sample by path via `LVC_SAMPLE` regardless of\nwhether the path is listed in the index, and the index is shared across every\nplatform sample. If you add `VisualTest/Issue<N>Repro` there and the view only\nexists in `samples/AvaloniaSample/`, every other platform sample (WPF, MAUI,\nWinUI, Uno) will throw when it loads the index. Leave the file untouched on\nyour branch.\n\nIf it's genuinely easier for your *local* dev loop to pick the repro from the\nsample selector dropdown rather than via `LVC_SAMPLE`, edit `Index.cs`\ntemporarily — but revert it before committing. `git restore\nsamples/ViewModelsSamples/Index.cs` before each commit, or just don't stage\nthe file.\n\n### 4. Auto-launch the sample at your repro\n\nAll XAML platform samples read `LVC_SAMPLE` at startup and load that sample\ninstead of the default landing screen. Set it before launching:\n\n```bash\n# bash / WSL\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nBuild first if needed: `dotnet build samples/<Platform>Sample/... -c Debug`.\n\n### 5. Verify the bug yourself\n\nTwo paths — pick based on the bug type:\n\n**A. In-app screenshot for visual bugs** (color, shape, position, rendering\nartifacts). Avalonia/WPF/WinUI samples support `LVC_SCREENSHOT`: when set,\nthe sample renders its main window via the framework's native\n`RenderTargetBitmap` after a short delay (default 3 s, override with\n`LVC_SCREENSHOT_DELAY_MS`) and exits. No external tooling, no race against\na screenshot tool launching too early. The capture is scaled to the\nwindow's physical pixels (`RenderScaling` on Avalonia,\n`VisualTreeHelper.GetDpi` on WPF) so HiDPI displays produce a sharp PNG\nthat matches what's on screen:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-before.png \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n$env:LVC_SCREENSHOT = \"$pwd\\.claude\\screenshots\\<N>-before.png\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nAfter it exits, `Read` the PNG. You're multimodal — describe what you see,\ncompare to a control sample (often `Pies/Gauge1` or `General/FirstChart` for\n\"what should this look like\"). If the bug is subtle (a few pixels), make the\nrepro larger (`Width=380`, `Height=380`) so it's clearly visible.\n\n**Fallback for MAUI/Uno or other-OS edge cases:** use the OS-appropriate\nhelper script. They all take `<ProcessName> <OutPath> [WaitSeconds]` and\npoll for the target window before capturing:\n\n| OS      | Script                                       | Underlying tool                            |\n| ------- | -------------------------------------------- | ------------------------------------------ |\n| Windows | `.claude/scripts/capture-window.ps1`         | `PrintWindow` via Win32 (works occluded)   |\n| macOS   | `.claude/scripts/capture-window-macos.sh`    | `osascript` + `screencapture -l <id>`      |\n| Linux   | `.claude/scripts/capture-window-linux.sh`    | `xdotool`+`import` / `swaymsg`+`grim` / `gnome-screenshot` |\n\nThe Linux script tries X11 → sway → GNOME in priority order; install the\nmatching package if none are present (the script prints the apt/dnf hint).\nUse these only when `LVC_SCREENSHOT` isn't supported on the target platform\n(MAUI, Uno) — for Avalonia/WPF/WinUI prefer in-app capture.\n\n**B. Console logs for state/dataflow bugs** (binding doesn't fire, value\ndoesn't propagate, event order is wrong):\n\nAdd temporary `Console.WriteLine` calls along the suspected path:\n\n```csharp\nConsole.WriteLine($\"[issue<N>] OnPropertyChanged: {change.Property.Name} old={change.OldValue} new={change.NewValue}\");\n```\n\nThe platform sample writes to stdout when launched from the terminal. Run via\nthe bash tool with `run_in_background=true` (no `LVC_SCREENSHOT` so the app\nstays open), wait a few seconds, kill the app, then `grep` the captured output\nfile. **Remove the diagnostics before committing.**\n\nIf neither approach decisively confirms the bug, escalate to the user with\n**one** well-framed question, not a chain of polling questions. Example:\n\n> \"The before-fix capture shows the gauge endcaps as flat, contrary to the\n> issue's screenshot. Did you toggle CornerRadius after the screenshot was\n> taken in the original report?\"\n\n### 6. Diagnose the root cause\n\nTrace from symptom backward through the rendering/data pipeline. Cross-check\nagainst `MEMORY.md` — many bugs in this repo have related ancestors\n(z-index issues, theme overrides, motion-property defaults, source-gen\nbehavior). If you find a matching memory note, use its diagnosis as a starting\npoint but verify against current code; memories go stale.\n\nCommon gotchas in this codebase:\n\n- **Theme overrides user-set values** when the user's value equals the DP\n  default — Avalonia skips `OnPropertyChanged` and `_userSets` never gets\n  populated. `XamlGaugeSeries.EndInit` syncs IsSet DPs as a remediation; if\n  you see this pattern in another wrapper, the same fix shape applies.\n- **Series controls aren't in the visual tree.** `OnInitialized` and\n  `TemplatedParent` may not fire/be set the way you'd expect. Use `EndInit`\n  instead.\n- **Theme rules run from the chart engine measure pass**, not at construction.\n  `_isInternalSet` + `_userSets` is the existing precedence mechanism — don't\n  reinvent it.\n- **Motion properties animate from a stale \"from\" value.** A value flip from\n  N→0 may render N for one frame.\n\n### 7. Write the regression test first\n\nTest-first: by the end of step 6 you understand the root cause and the\nobservable that would catch a regression. Write the test now, *before*\napplying the fix, and run it — it must fail for the right reason. A test\nwritten after the fix risks passing against both versions of the code; a\ntest that fails first proves it's gated on the broken behavior, and you\nskip the awkward \"comment out the fix, rebuild, re-run\" verification dance.\n\nTest choice depends on the bug nature:\n\n- **Programmatic state assertion** (the bug is in state propagation, not\n  pixels): Factos test in `tests/SharedUITests/`. Navigate to the repro,\n  query a helper method on the View that exposes the state under test,\n  assert. Gate by `#if <PLATFORM>_UI_TESTING` if platform-specific (most\n  XAML-platform-quirk bugs are).\n- **Pixel-perfect rendering**: snapshot test in `tests/SnapshotTests/`.\n- **Animation trajectory** (the bug is in per-frame interpolation, not the\n  final value — a bar pops to target instead of growing, a slice doesn't\n  sweep, a transition runs at the wrong speed, a refactor risks changing the\n  motion shape of an existing series): JSON animation baseline under\n  `tests/CoreTests/AnimationBaselines/` driven by\n  `tests/CoreTests/Helpers/SeriesAnimationCapture.cs`. The helper steps\n  `CoreMotionCanvas.DebugElapsedMilliseconds`, captures the visual's geometry\n  at each sample timestamp, and `AssertTrajectoryMatches` compares the\n  trajectory to a committed `.json`. First run writes the new trajectory to\n  `AnimationBaselinesNew/` and fails with a \"review and commit\" message —\n  inspect the file, then move it into `AnimationBaselines/`. Re-baseline the\n  same way: delete the JSON, re-run, move from `New/` back. On mismatch the\n  helper also drops `[EXPECTED]`/`[RESULT]` files into\n  `AnimationBaselinesDiff/` so you can diff them directly. Caller must use\n  `EasingFunctions.Lineal` + fixed `MinLimit`/`MaxLimit` so interpolation is\n  deterministic; the existing `tests/CoreTests/SeriesTests/*AnimationTests.cs`\n  files are the templates. Prefer this over a plain MSTest whenever the\n  observable is \"how the value changes between two states\" — a single\n  before/after assertion can't catch a regression that only mis-paints the\n  intermediate frames.\n- **Pure C# logic** (chart engine, motion, math): MSTest in\n  `tests/CoreTests/`.\n\nRun the test and confirm the failure message matches the symptom you saw in\nstep 5 — not, for example, a setup error or NullRef from missing test\ninfrastructure. If it fails for an unrelated reason, the test isn't yet\ncatching the bug; fix the test before moving on.\n\nTo run a single Factos UI test:\n\n```bash\n# In tests/UITests/Program.cs, set: var appToRun = \"<platform>-desktop\"\n# (avalonia-desktop / wpf-net10 / winui / maui / uno).\ndotnet build tests/UITests/UITests.csproj -c Debug\ncd tests/UITests/bin/Debug/net10.0 && dotnet UITests.dll\n# Revert the appToRun change before committing — it's a local dev-loop tweak.\n```\n\n### 8. Apply the fix\n\nSmallest possible change. Don't refactor surrounding code. Don't add\ncomments unless the WHY is non-obvious — but if the bug is a subtle\ninteraction (Avalonia behavior, theme precedence, source-gen quirk), a comment\nexplaining *why this fix is necessary* is warranted because future readers\nwon't reconstruct it from memory.\n\n### 9. Verify the fix\n\nRe-run the failing test from step 7 — it must now pass. Then re-run step 5\nwith the fix in place to capture an \"after\" screenshot at a sibling path and\ncompare visually:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-after.png \\\n  ./samples/<Platform>Sample/.../<Platform>Sample.exe\n```\n\n`Read` both images. Don't claim the fix works without comparing. The test\npassing is necessary but not sufficient for visual bugs — pixel-equivalent\noutput can still look subtly wrong if the assertion was too narrow.\n\n### 10. Commit and PR\n\nYou developed test-first, but commit fix-first. Two commits, in this order:\n\n1. `fix(<scope>): <one-line summary> (#<N>)` — only the fix.\n2. `test(<scope>): regression for <symptom> (#<N>)` — only the test +\n   repro view. Do not stage `samples/ViewModelsSamples/Index.cs`; see step 3\n   for why.\n\nWhy fix-first commit order despite test-first development: every commit on\nthe branch should be individually green so `git bisect` lands on a usable\nstate. If the test commit landed first it would be a failing-test commit\nthat bisect would (correctly) flag as broken. Fix-then-test keeps both\ncommits green while still satisfying the project rule that reverting the\nfix must surface the regression — revert commit 1 alone and the test from\ncommit 2 fails.\n\nCommit message style follows recent history (`git log --oneline -10`).\nBody: imperative, mention the root-cause mechanism, why the test catches it.\nEnd with the standard `Co-Authored-By` line.\n\nPush and open the PR with `gh pr create`. The PR body should include:\n\n- **Summary** bullet list (what changed, what it closes)\n- **Why** section (root cause walkthrough — the most valuable part)\n- **Test plan** checklist with what you actually verified locally\n\n### 11. Update memory\n\nAfter the PR is open, write a `project_issue_<N>.md` memory and add a one-line\nentry to `MEMORY.md`. Capture: **what was non-obvious** about the bug, what\ndiagnosis steps led to the fix, and what conventions/files the next person\nneeds. Don't re-document the code — just the insights.\n\n## Anti-patterns to avoid\n\n- **Asking the user \"is the bug visible now?\" repeatedly.** Capture a\n  screenshot or read logs. If you can't decide from one capture + one\n  question, you haven't framed the question precisely enough.\n- **Simplifying the repro before confirming.** A \"minimal\" repro that doesn't\n  trigger the bug is worse than a verbose one that does.\n- **Writing the test after the fix.** Develop test-first (step 7 before\n  step 8) so the failure is real and you don't have to comment out the fix\n  to verify the test catches anything. A test authored against\n  already-fixed code can pass for the wrong reason.\n- **Mixing fix + test + cleanup in one commit.** Project policy is strict\n  here — every fix needs a separately revertible test commit.\n- **Force-pushing for \"cleanliness\".** Never. Stack new commits.\n- **Trusting memory over code.** Memory files name specific functions and\n  files; verify they still exist before recommending — projects refactor.\n\n## Tooling reference\n\n- Issue triage: `gh issue view <N> --repo Live-Charts/LiveCharts2`\n- **Auto-launch sample**: `LVC_SAMPLE=<path>` env var (Avalonia, WPF, WinUI,\n  MAUI, Uno).\n- **In-app screenshot**: `LVC_SCREENSHOT=<path>` env var (Avalonia, WPF,\n  WinUI). Sample renders to PNG after `LVC_SCREENSHOT_DELAY_MS` (default\n  3000) and exits.\n- **External screenshot fallback** — one script per OS, all take the same\n  `<ProcessName> <OutPath> [WaitSeconds]` shape:\n  - Windows: `.claude/scripts/capture-window.ps1` (also accepts\n    `-WindowTitle <substring>` instead of `-ProcessName`)\n  - macOS:   `.claude/scripts/capture-window-macos.sh`\n  - Linux:   `.claude/scripts/capture-window-linux.sh` (X11 / sway / GNOME)\n- Factos UI tests: `tests/UITests/`, set `appToRun` in `Program.cs` for\n  local runs.\n- Build per-platform: `LiveCharts.<Platform>.slnx` solutions.\n","frontmatter":{"name":"repro-and-fix","description":"Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. \"let's work on issue"},"isInternal":false,"tokens":4751,"sizeBytes":19146},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/Live-Charts/LiveCharts2/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nLiveCharts2 is a cross-platform .NET charting library with a layered architecture:\n- **`src/LiveChartsCore/`** — Platform-agnostic core (math, series, axes, animation). No UI dependencies. Targets `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp/`** — SkiaSharp rendering backend implementing the core drawing abstractions.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp.{Platform}/`** — Platform-specific view controls (WPF, Avalonia, MAUI, Blazor, WinForms, WinUI, Eto, UNO).\n- **`generators/LiveChartsGenerators/`** — Roslyn source generator for boilerplate reduction.\n\n## Build Commands\n\n```bash\n# Core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Platform-specific (examples)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n\n# Target a specific framework when multi-targeting causes issues\ndotnet build -f net8.0\n```\n\nMAUI/WASM projects require workloads: `dotnet workload install maui --skip-sign-check` / `dotnet workload install wasm-tools --skip-sign-check`. Core and desktop projects (WPF, Avalonia, WinForms) do not.\n\n## Testing\n\n```bash\n# Unit tests (MSTest) — primary test suite\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Snapshot tests (image comparison, net10.0 only)\ndotnet test tests/SnapshotTests/\n\n# UI tests via Factos (requires sample apps built)\ndotnet run --project tests/UITests/\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n```\n\nTests use `CoreMotionCanvas.IsTesting = true` to disable animations. UI tests are defined in `tests/SharedUITests/` (shared project) and run against each platform via the Factos orchestrator in `tests/UITests/`.\n\n## Running Samples\n\n```bash\ndotnet run --project samples/WPFSample/WPFSample.csproj\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\nSample ViewModels live in `samples/ViewModelsSamples/` and are shared across all platform samples. Each platform sample creates its own views. `samples/ViewModelsSamples/Index.cs` lists all available sample paths.\n\n## Architecture Details\n\n**Rendering pipeline**: Data → Core series engine (measurement, layout) → SkiaSharp drawables → Platform-native surface. The core is rendering-agnostic — `samples/VorticeSample/` demonstrates using DirectX instead of SkiaSharp.\n\n**Shared projects**: `src/skiasharp/_Shared/`, `_Shared.Xaml/`, `_Shared.WinUI/` contain code shared across platform views via MSBuild linked files (configured in `build/*.Build.props`).\n\n**Code generation**: `LiveChartsGenerators` is a Roslyn analyzer/generator. Controlled by `UseNuGetForGenerator` in `Directory.Build.props` (default: `true` = NuGet package).\n\n**Key build properties** (`Directory.Build.props`):\n- `UseNuGetForSamples`: `false` during development (project references), `true` for CI/release\n- `UITesting`: set to `true` to include shared UI tests in sample projects\n- `GPU`, `VSYNC`, `Diagnose`: rendering mode overrides for testing\n\n## Code Style\n\nBased on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with these exceptions (enforced via `.editorconfig`):\n- `var` is freely used everywhere (not restricted to explicit right-hand types)\n- Single-line `if` without braces is preferred when the line is short; break long lines rather than adding braces\n- Private fields: `_camelCase`, static private: `s_camelCase`, constants: `PascalCase`\n- 4-space indentation, Allman braces, LF line endings\n\n**File naming is critical**: file names must match the class name exactly (`Hello<T>` → `Hello.cs`). Generic and non-generic with the same name go in the same file (only when related by inheritance). This is required for automatic documentation generation.\n\n## Key Constraints\n\n- **Never add platform-specific code to `LiveChartsCore`** — it must remain platform-agnostic\n- **.NET Framework 4.6.2 compatibility must be maintained** (strong-named assemblies, `LiveCharts.snk`)\n- **SkiaSharp version range**: min 2.88.9, latest 3.119.0 — changes must respect both\n- **C# 14.0** language version\n- Animation system (`Motion/`) is core infrastructure — changes require extensive testing\n- Chart updates can arrive from any thread; synchronization is essential\n\n## Additional Documentation\n\nSee `.github/copilot-instructions.md` for extended guidance including: sample platform view patterns (XAML/code-only/Blazor), adding new series types, CI/CD workflow details, and documented build errors with workarounds.\n","isInternal":false,"tokens":1283,"sizeBytes":5159},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/Live-Charts/LiveCharts2/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# LiveCharts2 Copilot Instructions\n\nThis document helps coding agents work efficiently with the LiveCharts2 repository.\n\n## Repository Overview\n\nLiveCharts2 is a flexible, cross-platform charting library for .NET. It follows a layered architecture where:\n- **Core library** (`LiveChartsCore`) is platform-agnostic and handles all chart mathematics\n- **SkiaSharp backend** renders the charts using SkiaSharp\n- **Platform-specific views** provide UI controls for various frameworks (WPF, Avalonia, MAUI, Blazor, etc.)\n\n## Repository Structure\n\n```\nLiveCharts2/\n├── src/\n│   ├── LiveChartsCore/                    # Platform-agnostic core library\n│   │   ├── Kernel/                        # Core charting engine\n│   │   ├── Drawing/                       # Drawing abstractions\n│   │   ├── Motion/                        # Animation system\n│   │   ├── Measure/                       # Chart measurement logic\n│   │   └── [Series types]/                # Line, Bar, Pie, Scatter, etc.\n│   ├── skiasharp/                         # SkiaSharp rendering implementations\n│   │   ├── LiveChartsCore.SkiaSharp/      # Core SkiaSharp provider\n│   │   ├── LiveChartsCore.SkiaSharp.WPF/\n│   │   ├── LiveChartsCore.SkiaSharp.Avalonia/\n│   │   ├── LiveChartsCore.SkiaSharpView.Maui/\n│   │   ├── LiveChartsCore.SkiaSharpView.Blazor/\n│   │   └── [other platforms]/\n│   └── _Shared.Native/                    # Native platform interop\n├── samples/                               # Sample applications\n│   ├── ViewModelsSamples/                 # Shared ViewModels for all samples\n│   │   └── Index.cs                       # List of all sample paths\n│   ├── WPFSample/\n│   ├── AvaloniaSample/\n│   ├── MauiSample/\n│   ├── VorticeSample/                     # DirectX sample (core without SkiaSharp)\n│   └── [other platforms]/\n├── tests/\n│   ├── CoreTests/                         # Core unit tests using MSTest\n│   │   ├── ChartTests/                    # High-level chart tests\n│   │   ├── SeriesTests/                   # Series-specific tests\n│   │   ├── LayoutTests/                   # Layout tests\n│   │   ├── CoreObjectsTests/              # Core objects tests\n│   │   └── OtherTests/                    # Axes, events, etc.\n│   ├── SnapshotTests/                     # Snapshot/image comparison tests (net10.0)\n│   ├── UITests/                           # UI testing orchestrator\n│   │   └── Program.cs                     # Factos-based multi-platform test runner\n│   └── SharedUITests/                     # Shared UI tests (referenced by sample apps)\n│       ├── CartesianChartTests.cs\n│       ├── PieChartTests.cs\n│       ├── PolarChartTests.cs\n│       └── MapChartTests.cs\n├── docs/                                  # Documentation (Scriban templates)\n│   ├── samples/                           # Sample documentation templates\n│   ├── shared/                            # Reusable template fragments\n│   ├── cartesianChart/                    # Cartesian chart docs\n│   ├── piechart/                          # Pie chart docs\n│   └── polarchart/                        # Polar chart docs\n└── generators/                            # Code generators\n```\n\n## Key Architecture Concepts\n\n### 1. Layered Design\n- **LiveChartsCore**: Pure .NET, no UI dependencies, handles all calculations\n- **SkiaSharp Provider**: Implements `IDrawingProvider` to render using SkiaSharp\n- **Platform Views**: WPF/Avalonia/MAUI/etc. specific controls that host the renderer\n\n### 2. Multi-Platform Targeting\n\nCore projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) target:\n- `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **No mobile workloads required** to build the core library\n\n**Platform-specific view projects** (WPF, Avalonia, MAUI, etc.) have their own target framework requirements based on the platform.\n\n### 3. Sample Structure\n- **ViewModelsSamples**: Contains shared ViewModels used across all UI frameworks\n- **Index.cs**: Defines available samples as string paths (e.g., \"Lines/Basic\", \"Pies/Doughnut\")\n- Each platform sample project (WPF, Avalonia, etc.) references ViewModelsSamples and creates platform-specific views\n\n### 4. VorticeSample\nA special sample demonstrating how to use LiveChartsCore without SkiaSharp, using DirectX instead. This shows the core library is truly rendering-agnostic.\n\n## Building the Repository\n\n### Prerequisites\n- .NET SDK (see `global.json` for minimum version)\n- No workloads required for core projects\n- Platform-specific projects (MAUI, UNO, Avalonia Browser) require relevant workloads:\n  ```bash\n  dotnet workload install maui\n  dotnet workload install wasm-tools\n  ```\n\n### Build Methods\n\n#### Quick Build - Core Projects\n```bash\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n```\n\n#### Quick Build - Platform Views\n```bash\n# Build specific platform views (recommended for development)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n```\n\n#### Full Build (Windows)\n```bash\n# Build platform-specific projects individually\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj\n# Or use platform-specific solution files (see below)\n```\n\n#### Build with Solution Files\n```bash\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n```\n\n### Common Build Issues and Workarounds\n\n#### Issue: Missing workload errors (NETSDK1147)\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\n```\n\n**Context**: This error occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require workloads.\n\n**Workaround Options:**\n1. Install the required workload: `dotnet workload install maui`\n2. Build only the platform you need (e.g., WPF or Avalonia desktop on Windows)\n3. Use platform-specific solution files that don't include all targets\n\n#### Issue: SkiaSharp version conflicts\nThe project supports multiple SkiaSharp versions:\n- `MinSkiaSharpVersion`: 2.88.9 (minimum supported)\n- `LatestSkiaSharpVersion`: 3.119.0 (default for GPU support)\n\nDefined in `Directory.Build.props`.\n\n#### Issue: Multi-targeting complexity\nWhen building fails for specific targets, you can:\n1. Use `-f` to target specific framework: `dotnet build -f net8.0`\n2. Edit `TargetFrameworks` in .csproj to focus on needed platforms\n\n## Testing\n\n### Unit Tests (Core Library)\n\n**Location**: `tests/CoreTests/`\n\n**Framework**: MSTest with coverlet for code coverage\n\n**Run Tests:**\n```bash\ndotnet test tests/CoreTests/\n\n# Run for specific framework\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run with coverage\ndotnet test tests/CoreTests/ --collect:\"XPlat Code Coverage\"\n```\n\n**Test Structure:**\n- `ChartTests/`: High-level chart functionality\n- `SeriesTests/`: Tests for Line, Bar, Pie, Scatter, Heat, etc.\n- `LayoutTests/`: Stack and table layouts\n- `CoreObjectsTests/`: Transitions, colors, labels\n- `OtherTests/`: Axes, events, data providers, visual elements\n- `MockedObjects/`: Test helpers and mocks\n- `TestsInitializer.cs`: MSTest assembly initialization\n\n**Important**: Tests use `CoreMotionCanvas.IsTesting = true` to disable animations during testing.\n\n### Snapshot Tests\n\n**Location**: `tests/SnapshotTests/`\n\n**Framework**: MSTest, targets `net10.0`\n\nSnapshot tests render charts to images and compare them against stored reference snapshots. They are run in CI on Windows.\n\n**Run Tests:**\n```bash\ndotnet test tests/SnapshotTests/\n```\n\n### UI Testing\n\n**Location**: `tests/UITests/` (orchestrator) and `tests/SharedUITests/` (shared tests)\n\n**Framework**: [Factos](https://github.com/beto-rodriguez/Factos) - A multi-platform UI testing framework\n\n**How it works:**\n1. Shared UI tests are defined in `tests/SharedUITests/` (shared project)\n2. Each sample application references `SharedUITests` \n3. The `tests/UITests/Program.cs` orchestrator:\n   - Starts various sample applications (Avalonia, WPF, MAUI, Blazor, etc.)\n   - Connects to them via Factos\n   - Runs the shared UI tests against each platform\n4. Tests ensure charts render correctly across all supported UI frameworks\n\n**Test Coverage:**\n- `CartesianChartTests.cs`: Cartesian chart rendering and behavior\n- `PieChartTests.cs`: Pie/Doughnut chart tests\n- `PolarChartTests.cs`: Polar chart tests  \n- `MapChartTests.cs`: Map chart tests\n- `AvaloniaTests.cs`: Avalonia-specific tests\n\n**Running UI Tests:**\n```bash\n# Run UI tests (requires sample apps to be built)\ndotnet run --project tests/UITests/\n\n# Run against specific platform (see Program.cs for options)\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\ndotnet run --project tests/UITests/ -- --select maui --test-env \"tf=net10.0-windows10.0.19041.0\"\n```\n\n**Important Notes:**\n- UI testing requires the Factos package\n- Each platform may need specific prerequisites (emulators for mobile, browsers for web)\n- In Debug mode, tests use project references; in Release mode, they use NuGet packages\n- The orchestrator supports testing against multiple target frameworks\n- Mobile platforms (Android, iOS) require running emulators\n\n**Build Configuration for UI Tests:**\nUI test configuration is managed through MSBuild properties. When `UITesting=true` is set, samples include the shared UI test project.\n\n## Running Samples\n\n### Sample Applications\nEach platform has its own sample application that references `ViewModelsSamples`:\n\n```bash\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\n### Adding New Samples\n1. Add ViewModel class in `samples/ViewModelsSamples/[Category]/[Name].cs`\n2. Add path to `samples/ViewModelsSamples/Index.cs`\n3. Create platform-specific view files in each sample project (WPF, Avalonia, etc.)\n\n### Sample Platforms Reference\n\nThe following platforms each need a view for every sample. **ConsoleSample** and **VorticeSample** are excluded — they don't follow this pattern.\n\n| Platform | Root path | View file(s) | Base class | LVC namespace (xmlns:lvc) |\n|---|---|---|---|---|\n| **Avalonia** | `samples/AvaloniaSample/[Category]/[Name]/` | `View.axaml` + `View.axaml.cs` | `UserControl` | `using:LiveChartsCore.SkiaSharpView.Avalonia` |\n| **WPF** | `samples/WPFSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` | `clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF` |\n| **MAUI** | `samples/MauiSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `ContentPage` | `clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui` |\n| **WinUI** | `samples/WinUISample/WinUISample/Samples/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` (`sealed partial`) | `using:LiveChartsCore.SkiaSharpView.WinUI` |\n| **WinForms** | `samples/WinFormsSample/[Category]/[Name]/` | `View.cs` + `View.Designer.cs` + `View.resx` | `UserControl` (`partial`) | N/A — code-only |\n| **Blazor** | `samples/BlazorSample/Pages/[Category]/[Name]/` | `View.razor` | N/A — Razor component | `@using LiveChartsCore.SkiaSharpView.Blazor` |\n| **EtoForms** | `samples/EtoFormsSample/[Category]/[Name]/` | `View.cs` | `Panel` (non-partial) | N/A — code-only |\n| **UnoPlatform** | *(no separate files)* | Reuses `WinUISample` views via reflection | — | — |\n\n**Key facts for each platform:**\n\n- **All XAML platforms (Avalonia, WPF, MAUI, WinUI)** use `Activator.CreateInstance` with the pattern `{Platform}.{Category}.{Name}.View` to load views — so the **C# namespace must exactly match** `{PlatformPrefix}.{Category}.{Name}` and the class must be named `View`.\n- **WinForms** and **EtoForms** use the same reflection pattern. The view class must be `partial class View : UserControl` (WinForms) or `class View : Panel` (EtoForms).\n- **Blazor** uses Razor's `@page \"/{Category}/{Name}\"` directive for routing. The nav menu reads `ViewModelsSamples.Index.Samples` automatically.\n- **UnoPlatform** (`samples/UnoPlatformSample/`) loads views from the `WinUISample` assembly — no separate files are needed.\n\n**XAML DataContext / BindingContext patterns:**\n\n```xml\n<!-- Avalonia (View.axaml) -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\"\n             x:DataType=\"vms:ViewModel\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- WPF (View.xaml) -->\n<UserControl xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- MAUI (View.xaml) — ContentPage + XamlCompilation attribute on code-behind -->\n<ContentPage xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\"\n             x:DataType=\"vms:ViewModel\">\n    <ContentPage.BindingContext><vms:ViewModel/></ContentPage.BindingContext>\n</ContentPage>\n\n<!-- WinUI (View.xaml) — sealed partial class -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.WinUI\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n```\n\n**Code-only platforms (WinForms / EtoForms)** typically instantiate the ViewModel directly or inline the data:\n\n```csharp\n// WinForms — partial class View : UserControl\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nchart.Location = new System.Drawing.Point(0, 0);\nchart.Size = new System.Drawing.Size(50, 50);\nchart.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;\nControls.Add(chart);\n\n// EtoForms — class View : Panel (non-partial, no Designer file)\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nContent = new DynamicLayout(chart);\n```\n\n**WinForms `View.Designer.cs`** is always a minimal boilerplate — copy from any existing sample, just update the namespace.\n\n**UI-testing accessor** — most XAML views expose a `Chart` property under `#if UI_TESTING` for the Factos test runner:\n\n```csharp\n// XAML platforms (WPF, Avalonia, MAUI, WinUI)\n#if UI_TESTING\n    public SomeChartType Chart => chartNamedInXaml;\n#endif\n\n// EtoForms / WinForms\npublic SomeChartType Chart;  // public field, always present\n```\n\n**Blazor** exposes the chart via `@ref`:\n```razor\n<CartesianChart @ref=\"Chart\" .../>\n@code { public CartesianChart Chart; }\n```\n\n## Code Style and Conventions\n\n### Editor Config\nThe repository uses `.editorconfig` based on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with exceptions.\n\n**Key Style Rules:**\n- **Indentation**: 4 spaces\n- **Line endings**: LF, insert final newline\n- **Braces**: New line before open brace (Allman style)\n- **var usage**: Use `var` freely (explicitly allowed)\n- **Single-line if**: Allowed and preferred when line is short\n- **Naming**:\n  - Private/internal fields: `_camelCase`\n  - Static private fields: `s_camelCase`\n  - Constants: `PascalCase`\n- **Using directives**: Outside namespace\n\n### File Naming\n**Critical for auto-generated documentation:**\n- File names MUST match the class name exactly\n- `public class Hello` → `Hello.cs`\n- `public class Hello<T>` → `Hello.cs` (ignore generics)\n- Generic and non-generic with same name → same file (only if inheritance relationship)\n\n### Important Constants\nDefined in `Directory.Build.props`:\n- `LiveChartsVersion`: Current version (2.0.0-rc6.1)\n- `MinSkiaSharpVersion`: 2.88.9\n- `LatestSkiaSharpVersion`: 3.119.0\n- `LangVersion`: 14.0 (C# 14)\n\n## Build Configuration Properties\n\n### Rendering Settings\nRendering settings are configured via MSBuild properties:\n- `GPU`: Enable/disable GPU acceleration\n- `VSYNC`: Enable/disable vertical sync\n- `FPS`: Frame rate (10, 20, 30, 45, 60, 75, 90, 120)\n- `Diagnose`: Enable diagnostic mode\n\nThese create conditional compilation symbols for testing different rendering modes.\n\n### Development Flags\nIn `Directory.Build.props`:\n- `UseNuGetForSamples`: Use NuGet packages vs project references (default: false)\n- `UseNuGetForGenerator`: Use NuGet generator package (default: true)\n\n## CI/CD\n\n### GitHub Actions Workflows\n\n#### 1. Main CI (`livecharts.yml`)\n- Triggers: Pull requests\n- Runs on: `windows-2025` (pack/test), `ubuntu-24.04` (Linux/browser), `macos-26` (Mac/iOS)\n- Steps:\n  1. **Pack**: Builds NuGet packages for all platform libraries (core, skiasharp, WPF, Avalonia, MAUI, Blazor, WinUI, UNO, WinForms, Eto)\n  2. **test-core**: Runs `CoreTests` on `net8.0` and `net462`\n  3. **test-snapshot**: Runs `SnapshotTests`\n  4. **test-windows/linux/mac/browser/android/ios**: Runs Factos UI tests for each platform\n- On tag pushes (after tests pass): publishes packages to NuGet.org\n\n#### 2. Publish (`publish.yml`)\n- Handles NuGet package publishing\n\n**Note**: The CI uses NuGet packages (not project references) when running UI tests in Release mode.\n\n## Common Development Workflows\n\n### Adding a New Series Type\n1. Create series class in `src/LiveChartsCore/[SeriesType]/`\n2. Implement series interfaces (`ISeries`, etc.)\n3. Create SkiaSharp drawable in `src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/`\n4. Add tests in `tests/CoreTests/SeriesTests/`\n5. Create sample ViewModel in `samples/ViewModelsSamples/`\n6. Update `samples/ViewModelsSamples/Index.cs`\n\n### Adding Platform Support\n1. Create new project in `src/skiasharp/LiveChartsCore.SkiaSharpView.[Platform]/`\n2. Reference `LiveChartsCore.SkiaSharp` project\n3. Create platform-specific control classes\n4. Add shared code to `_Shared/` if applicable\n5. Create sample application in `samples/[Platform]Sample/`\n6. Add platform-specific solution file\n\n### Updating Documentation\n\n**Important**: Documentation files in the `docs/` folder are **Scriban templates**, not final markdown files.\n\n**How it works:**\n1. Template files are compiled by an external (non-open-source) repository\n2. Templates use [Scriban](https://github.com/scriban/scriban) - a fast, powerful, and lightweight text templating language\n3. Scriban supports custom functions and expressions embedded in the markdown\n\n**Common Scriban expressions you'll find:**\n\n**File inclusion** - Renders content from source files:\n```\n{{~ render \"~/../samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs\" ~}}\n{{~ render \"~/../samples/MauiSample/MauiProgram.cs\" ~}}\n{{~ render \"~/../samples/{samples_folder}/Events/Cartesian{view_extension}\" ~}}\n```\n\n**Conditionals** - Platform-specific content:\n```\n{{~ if xaml ~}}\n  Content for XAML platforms (WPF, Avalonia, UNO, WinUI, MAUI)\n{{~ end ~}}\n\n{{~ if winforms ~}}\n  Content specific to WinForms\n{{~ end ~}}\n```\n\n**Variables** - Dynamic content:\n```\n{{ website_url }}/docs/{{ platform }}/{{ version }}/About\n{{ assets_url }}/docs/{{ unique_name }}/result.gif\n{{ name | to_title_case }}\n{{ edit_source | replace_local_to_server }}\n```\n\n**Loops** - Iterate over collections:\n```\n{{~ for r in related_to ~}}\n  <a href=\"{{ compile this r.url }}\">{{ r.name }}</a>\n{{~ end ~}}\n```\n\n**Template structure:**\n- `docs/samples/[category]/[name]/template.md` - Sample documentation templates\n- `docs/shared/*.md` - Reusable template fragments included via `{{ render \"~/shared/...\" }}`\n- `docs/piechart/`, `docs/cartesianChart/`, etc. - Feature documentation with templates\n\n**When editing docs:**\n- Always edit the `.md` files as Scriban templates\n- Test template syntax (though final compilation happens externally)\n- Use `{{~ ~}}` syntax to strip whitespace around expressions\n- File paths in `render` are relative to the template location (use `~/../` for repo root)\n\n## Important Notes for Coding Agents\n\n### Do's\n- ✅ Use project references during development (not NuGet packages)\n- ✅ Follow the exact file naming convention (critical for docs)\n- ✅ Run tests after changes to core or series logic\n- ✅ Use platform-specific solution files for focused development\n- ✅ Consult `CONTRIBUTING.md` for detailed style guide\n- ✅ Use shared code in `_Shared/` folders when adding cross-platform features\n\n### Don'ts\n- ❌ Don't break multi-platform support when modifying core projects\n- ❌ Don't add platform-specific code to `LiveChartsCore` (keep it agnostic)\n- ❌ Don't ignore `.editorconfig` warnings\n- ❌ Don't remove or modify working tests without good reason\n- ❌ Don't add new dependencies without checking compatibility across all target frameworks\n\n### Special Considerations\n- The library supports .NET Framework 4.6.2 - maintain compatibility\n- SkiaSharp is abstracted - core library should work with other rendering engines\n- Animation system (`Motion/`) is critical - changes require extensive testing\n- Multi-threading: Chart updates can come from any thread; proper synchronization is essential\n\n## Quick Reference Commands\n\n```bash\n# === Building ===\n# Build core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Build platform-specific projects\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# === Install Workloads (for platform-specific projects) ===\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n\n# Check installed workloads\ndotnet workload list\n\n# === Testing ===\n# Run core unit tests\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run snapshot tests\ndotnet test tests/SnapshotTests/\n\n# Run UI tests (requires sample apps to build)\ndotnet run --project tests/UITests/\n\n# Run UI tests for specific platform\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n\n# === Running Samples ===\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n\n# === Troubleshooting ===\n# Clean build artifacts\ndotnet clean\nfind . -type d -name \"bin\" -o -name \"obj\" | xargs rm -rf\n\n# Restore packages\ndotnet restore\n\n# Check for workload issues\ndotnet workload restore --skip-sign-check\n```\n\n## Documented Errors and Workarounds\n\nThis section documents actual errors encountered when working with this repository and their solutions.\n\n### Error 1: NETSDK1147 - Missing Workloads\n\n**Error Message:**\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\nTo install these workloads, run the following command: dotnet workload restore\n```\n\n**Context**: This occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require any workloads.\n\n**Workarounds:**\n\n**Option 1: Install Required Workloads**\n```bash\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n```\n\n**Option 2: Build Platform-Specific Projects that don't need workloads**\n```bash\n# Build only WPF (Windows only)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\n\n# Build only Avalonia desktop (cross-platform)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\n```\n\n### Error 2: Visual Studio Component Required\n\n**Error Message:**\n```\nUnhandled exception: The imported file \"$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v$(VisualStudioVersion)/CodeSharing/Microsoft.CodeSharing.Common.Default.props\" does not exist and appears to be part of a Visual Studio component.\n```\n\n**Context**: Appears when running `dotnet workload restore` on non-Windows systems or when Visual Studio is not installed.\n\n**Why it happens**: The `src/skiasharp/_Shared.WinUI/_Shared.WinUI.shproj` shared project requires Visual Studio components that are Windows-specific.\n\n**Workaround**: This error can be ignored if you're not building WinUI projects. The workload installation succeeds despite this error. If you need to build WinUI:\n- Use Windows with Visual Studio 2022 installed\n- Use `msbuild` instead of `dotnet build` for WinUI projects\n\n### Error 3: Ambiguous Argument with Git\n\n**Error Message:**\n```\nfatal: ambiguous argument 'origin/branch-name': unknown revision or path not in the working tree.\n```\n\n**Context**: After fetching a branch with `git fetch origin branch-name`, trying to reference it as `origin/branch-name`.\n\n**Why it happens**: Git fetch stores the ref as `FETCH_HEAD`, not as a trackable remote branch.\n\n**Solution**: Use `FETCH_HEAD` or create a local tracking branch:\n```bash\n# Option 1: Use FETCH_HEAD directly\ngit log FETCH_HEAD\n\n# Option 2: Create tracking branch\ngit fetch origin main\ngit checkout -b main --track origin/main\n\n# Option 3: Fetch with branch creation\ngit fetch origin main:main\n```\n\n### Error 4: Package Not Found During Build\n\n**Context**: Sample applications may fail to build if NuGet packages are not found.\n\n**Why it happens**: `UseNuGetForSamples` flag in `Directory.Build.props` controls whether samples use project references or NuGet packages.\n\n**Solution**: Ensure you're using project references during development:\n```xml\n<!-- In Directory.Build.props -->\n<UseNuGetForSamples>false</UseNuGetForSamples>\n```\n\nOr restore NuGet packages if building from packages:\n```bash\ndotnet restore\n```\n\n### Error 5: Strong Name Assembly Conflicts\n\n**Context**: When building for .NET Framework 4.6.2, you may encounter assembly version conflicts.\n\n**Why it happens**: .NET Framework uses strong-named assemblies, and SkiaSharp has different versioning.\n\n**Referenced Issue**: https://github.com/mono/SkiaSharp/issues/3153\n\n**Solution**: The project is configured to handle this, but if you encounter issues:\n1. Clean the solution: `dotnet clean`\n2. Delete `bin` and `obj` folders\n3. Restore and rebuild: `dotnet restore && dotnet build`\n\n### Error 6: Test Build Failures on CI\n\n**Context**: UI tests may fail with target framework mismatches in CI.\n\n**Solution**: The UI test infrastructure uses special MSBuild properties:\n- `TestBuildTargetFramework`: Override target framework for test builds\n- `IsTestBuild`: Flag to indicate test build\n- `UITesting`: Flag to include shared UI tests\n\nExample from `tests/UITests/Program.cs`:\n```csharp\nMSBuildArg tf_n10w = new(\"TestBuildTargetFramework\", \"net10.0-windows\");\nMSBuildArg isTest = new(\"IsTestBuild\", \"true\");\n```\n\n## Troubleshooting\n\n### Problem: Can't build platform-specific projects - workload errors\n**Solution**: Install the required workload for the platform you're targeting (e.g., `dotnet workload install maui`). Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) build without any workloads.\n\n### Problem: SkiaSharp errors\n**Solution**: Check SkiaSharp version in `Directory.Build.props`, ensure NuGet restore succeeded\n\n### Problem: Tests fail with animation issues\n**Solution**: Verify `CoreMotionCanvas.IsTesting = true` in test initialization\n\n### Problem: Sample won't run\n**Solution**: Ensure platform-specific dependencies are installed (e.g., .NET Desktop Runtime for WPF)\n\n### Problem: Generator errors\n**Solution**: Check `UseNuGetForGenerator` setting and ensure LiveChartsGenerators package/project is available\n\n## Issue Reproduction & Fix Workflow\n\nWhen picking up a GitHub issue (reproduce → diagnose → fix → regression test → PR),\nfollow the canonical workflow at [`.claude/skills/repro-and-fix/SKILL.md`](../.claude/skills/repro-and-fix/SKILL.md).\nThat doc is the single source of truth for both Claude Code and Copilot Coding Agent —\nkeep edits there, not duplicated here.\n\nQuick reference for the dev-loop hooks the workflow relies on:\n\n- **`LVC_SAMPLE=<sample-path>`** — XAML samples (Avalonia / WPF / WinUI / MAUI / Uno) auto-navigate to the named sample on launch, e.g. `LVC_SAMPLE=VisualTest/Issue1986Repro`. Skips manual UI navigation for repros.\n- **`LVC_SCREENSHOT=<png-path>`** — Avalonia / WPF / WinUI samples render the main window to PNG via `RenderTargetBitmap` shortly after activation and exit. Captures scale to physical pixels on HiDPI.\n- **`LVC_SCREENSHOT_DELAY_MS=<ms>`** — overrides the 3 s default settle delay before the in-app screenshot is taken (use on slower CI hosts).\n- **`.claude/scripts/capture-window.{ps1,-macos.sh,-linux.sh}`** — per-OS PrintWindow / `screencapture` / `grim` fallbacks for platforms without an in-app capture path (MAUI, Uno).\n\nRepro views live under `samples/AvaloniaSample/VisualTest/Issue<N>Repro/` (or\nthe equivalent under whichever platform sample fits the bug). Their code-behind\nexposes helpers (e.g. `FindTemplatedGaugeSeries()`) that Factos UI tests call\ndirectly. Factos and `LVC_SAMPLE` navigate by path and don't need the repro\nregistered in `samples/ViewModelsSamples/Index.cs` — **do not commit changes\nto that file for a repro view.** It's shared across every platform sample,\nso a single-platform repro entry will crash the load on the other platforms.\n\n## Resources\n\n- **Main Documentation**: https://livecharts.dev\n- **Contributing Guide**: `CONTRIBUTING.md`\n- **Repository**: https://github.com/Live-Charts/LiveCharts2\n- **Code of Conduct**: `CODE_OF_CONDUCT.md`\n- **License**: MIT (see `LICENSE`)\n\n## Version Information\n\n- **Current Version**: 2.0.0-rc6.1 (Release Candidate)\n- **C# Language Version**: 14.0\n- **SkiaSharp**: 2.88.9 (min) to 3.119.0 (latest)\n- **Target Frameworks**: `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows` (core); plus platform-specific targets for view projects\n","isInternal":false,"tokens":7727,"sizeBytes":31136}],"systemPromptSnippet":"<yakaai_skills repo=\"Live-Charts/LiveCharts2\">\n<!-- File: llms-full.txt (Tokens: ~6877 | Category: root-instruction) -->\n# LiveCharts2 — Comprehensive Knowledge Base for LLMs\n\n> **⚠️ Version Warning:** This document covers **LiveCharts v2** (package prefix `LiveChartsCore.SkiaSharpView.*`).\n> The legacy **v0** (`LiveCharts` / `LiveCharts.Wpf`) is completely obsolete and has a different API.\n> Do NOT mix v0 and v2 syntax. v0 reference: https://github.com/Live-Charts/Live-Charts\n\n---\n\n## Overview\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET. It fixes the main design issues of its\npredecessor (v0), is focused on running everywhere, and improves flexibility. It uses **SkiaSharp** as its default\nrendering backend — a cross-platform 2D graphics API for .NET based on Google's Skia graphics library.\n\n- **Website / full docs:** https://livecharts.dev\n- **GitHub:** https://github.com/Live-Charts/LiveCharts2\n- **License:** MIT\n- **Current version:** 2.1.0 (check NuGet for latest stable/prerelease)\n- **Target frameworks (core):** `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **C# language version:** 14.0\n\n### Supported Platforms & NuGet Packages\n\n| Platform | NuGet package |\n|---|---|\n| MAUI | `LiveChartsCore.SkiaSharpView.Maui` |\n| Uno Platform (WinUI) | `LiveChartsCore.SkiaSharpView.Uno.WinUI` |\n| Avalonia | `LiveChartsCore.SkiaSharpView.Avalonia` |\n| WPF | `LiveChartsCore.SkiaSharpView.WPF` |\n| WinForms | `LiveChartsCore.SkiaSharpView.WinForms` |\n| WinUI | `LiveChartsCore.SkiaSharpView.WinUI` |\n| Blazor WASM | `LiveChartsCore.SkiaSharpView.Blazor` |\n| Eto.Forms | `LiveChartsCore.SkiaSharpView.Eto` |\n\nSkiaSharp minimum supported version: **2.88.9** (default: 3.119.0 for GPU support).\n\n---\n\n## Architecture\n\nThe library is divided into three main modules:\n\n### Core (`LiveChartsCore`)\n\nPlatform-agnostic. Contains:\n- A drawing **API** (interfaces) that defines all the shapes the library needs to build a chart\n- The charting engine: measures sizes, calculates positions for every geometry\n- The animation system (`Motion/` namespace) — `IAnimatable`, `MotionProperty`\n- Change-detection via `CollectionDeepObserver` (wraps `INotifyPropertyChanged` / `INotifyCollectionChanged`)\n- Series implementations: `LineSeries<T>`, `ColumnSeries<T>`, `PieSeries<T>`, `ScatterSeries<T>`, etc.\n\n### Renderer (`LiveChartsCore.SkiaSharp`)\n\nImplements the Core drawing API using SkiaSharp. Responsible for materializing geometry objects to pixels.\nYou can replace SkiaSharp with any other rendering engine (see `VorticeSample` using DirectX11 via Vortice.Windows).\n\n### View (platform packages)\n\nPlatform-specific controls (`CartesianChart`, `PieChart`, `PolarChart`, `GeoMap`) that:\n1. Ask the **Core** *what* to draw (geometry sizes and positions)\n2. Ask the **Renderer** *how* to draw it (render to the platform surface)\n\n### Animation System\n\nLiveCharts generates animations by producing many frames over time. Each animatable object has\n`MotionProperty` fields whose getter returns the *current interpolated value* for the current point\nin time — not the last assigned value. This means:\n\n```csharp\nvar line = new LineGeometry();\nline.X1 = 0;\nline.X1 = 100;\nvar x1 = line.X1; // returns 0 (animation has not elapsed yet)\n// After 5 seconds (of a 10s linear transition): line.X1 returns ~50\n```\n\n### Automatic Update Cycle\n\n1. User changes data (property or collection).\n2. `CollectionDeepObserver` detects the change via `INotifyPropertyChanged` / `INotifyCollectionChanged`.\n3. The chart **throttles** a *Measure request* (fires at most once every ~10 ms).\n4. On measure: Core recalculates geometry positions → Update cycle draws frames until all `MotionProperty` animations complete.\n\n---\n\n## Installation\n\n### Install via NuGet (pick your platform)\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView.WPF\ndotnet add package LiveChartsCore.SkiaSharpView.Avalonia\ndotnet add package LiveChartsCore.SkiaSharpView.Maui\ndotnet add package LiveChartsCore.SkiaSharpView.Blazor\ndotnet add package LiveChartsCore.SkiaSharpView.WinForms\ndotnet add package LiveChartsCore.SkiaSharpView.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Uno.WinUI\ndotnet add package LiveChartsCore.SkiaSharpView.Eto\n```\n\n> **Note for WPF / WinForms:** By default these projects target `netX.0-windows`, but SkiaSharp 3 does not provide\n> a build for that TFM. Consider specifying a minimum Windows version: `net8.0-windows10.0.19041`.\n\n### Configure LiveCharts at startup\n\nCreate a `CustomLiveChartsExtensions` class (shared across all platforms):\n\n```csharp\nusing LiveChartsCore.Kernel;\nusing LiveChartsCore.SkiaSharpView;\n\npublic static partial class CustomLiveChartsExtensions\n{\n    public static LiveChartsSettings AddLiveChartsAppSettings(this LiveChartsSettings settings) =>\n        settings\n            .AddSkiaSharp()           // use SkiaSharp as renderer\n            .AddDefaultMappers()      // register built-in type mappers\n            .AddDefaultTheme()        // light/dark theme based on OS\n            // optionally register a mapper for a custom type:\n            .HasMap<City>((city, index) => new(index, city.Population));\n}\n```\n\n#### WPF — `App.xaml.cs`\n\n```csharp\nprotected override void OnStartup(StartupEventArgs e)\n{\n    base.OnStartup(e);\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n}\n```\n\n#### Avalonia — `App.axaml.cs`\n\n```csharp\npublic override void OnFrameworkInitializationCompleted()\n{\n    LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    // ...\n}\n```\n\n#### MAUI — `MauiProgram.cs`\n\n```csharp\nbuilder\n    .UseMauiApp<App>()\n    .UseLiveCharts(config => config.AddLiveChartsAppSettings());\n```\n\n#### Blazor — `App.razor`\n\n```razor\n@inject IJSRuntime JS\n@code {\n    protected override async Task OnInitializedAsync()\n    {\n        LiveCharts.Configure(c => c.AddLiveChartsAppSettings());\n    }\n}\n```\n\n---\n\n## Core Concepts\n\n### Series and Values\n\nEvery series is generic over its data type `T`. LiveCharts natively supports `short`, `int`, `long`, `float`,\n`double`, `decimal` and their nullable forms. It also provides observable wrappers:\n\n| Type | Use case |\n|---|---|\n| `ObservableValue` | Single Y value that notifies changes |\n| `ObservablePoint` | Explicit X and Y |\n| `WeightedPoint` | X, Y, Weight (bubble charts) |\n| `DateTimePoint` | X is `DateTime` |\n| `TimeSpanPoint` | X is `TimeSpan` |\n| `ObservablePolarPoint` | Polar charts |\n| `FinancialPoint` / `FinancialPointI` | OHLC candlestick charts |\n\n```csharp\n// simple array — static, no auto-update:\nnew LineSeries<double> { Values = new double[] { 1, 2, 3 } }\n\n// ObservableCollection — auto-updates when items are added/removed:\nvar values = new ObservableCollection<ObservableValue>();\nnew LineSeries<ObservableValue> { Values = values }\nvalues.Add(new ObservableValue(5));  // chart updates automatically\n```\n\n### Mappers\n\nUse a **mapper** to teach LiveCharts how to plot a custom type:\n\n```csharp\n// Per-series mapper:\nnew LineSeries<TempSample>\n{\n    Values = samples,\n    Mapping = (sample, index) => new Coordinate(sample.Time, sample.Temperature)\n}\n\n// Global mapper (applied to every series using TempSample):\nLiveCharts.Configure(config =>\n    config.HasMap<TempSample>((sample, index) => new Coordinate(sample.Time, sample.Temperature)));\n```\n\n### IChartEntity (high-performance custom types)\n\nImplement `IChartEntity` directly on your model for best performance (no delegate overhead per point):\n\n```csharp\npublic partial class TempSample : ObservableObject, IChartEntity\n{\n    [ObservableProperty] private int _time;\n    [ObservableProperty] private double _temperature;\n\n    public Coordinate Coordinate { get; protected set; }\n    public ChartEntityMetaData? MetaData { get; set; }\n\n    protected override void OnPropertyChanged(PropertyChangedEventArgs e)\n    {\n        Coordinate = new Coordinate(Time, Temperature);\n        base.OnPropertyChanged(e);\n    }\n}\n```\n\n### Paints\n\nA `Paint` is the v2 equivalent of WPF/Avalonia `Brush`. It wraps SkiaSharp's paint and adds animation support.\n\n```csharp\nusing SkiaSharp;\nusing LiveChartsCore.SkiaSharpView.Painting;\n\n// Solid color\nnew SolidColorPaint(SKColors.Blue) { StrokeThickness = 4 }\n\n// Linear gradient\nnew LinearGradientPaint(\n    new[] { new SKColor(255, 140, 148), new SKColor(220, 237, 194) },\n    new SKPoint(0.5f, 0),   // gradient start (center-top)\n    new SKPoint(0.5f, 1))   // gradient end   (center-bottom)\n\n// Radial gradient\nnew RadialGradientPaint(new SKColor(255, 96, 96), new SKColor(255, 234, 96))\n\n// null means \"do not draw\" (hides fill, stroke, etc.)\nFill = null\n```\n\nAvailable paint properties: `StrokeThickness`, `PathEffect` (for dashed lines), `ImageFilter`, etc.\n\n### Animations\n\nAll charts animate automatically. Customize with:\n\n```csharp\n// Chart-level speed:\nmyChart.AnimationsSpeed = TimeSpan.FromMilliseconds(300);\n\n// Easing function:\nmyChart.EasingFunction = EasingFunctions.BounceOut;\n\n// Disable animations:\nmyChart.AnimationsSpeed = TimeSpan.Zero;\n// or:\nmyChart.EasingFunction = null;\n```\n\nSeries and Axes also have their own `AnimationsSpeed` and `EasingFunction` properties\n(override the chart-level value when non-null).\n\n### Null / missing points\n\nSet a value to `null` or a `Coordinate` to `Coordinate.Empty` to create gaps:\n\n```csharp\nnew LineSeries<double?>\n{\n    Values = new double?[] { 2, 6, null, 3, 5 }\n}\n```\n\n### Hardware Acceleration (GPU)\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\n\nLiveCharts.Configure(c => c\n    .AddLiveChartsRenderSettings());  // see LiveChartsRenderSettings.cs in samples\n```\n\nGPU is disabled by default. On Avalonia/Uno with SkiaRenderer the GPU setting is ignored\n(the UI framework controls rendering).\n\n---\n\n## Chart Types\n\n### CartesianChart\n\nStandard X/Y chart. Hosts `Series` (collection of `ICartesianSeries`), `XAxes`, `YAxes`.\n\nSupports: `LineSeries`, `ColumnSeries`, `ScatterSeries`, `StepLineSeries`, `HeatSeries`,\n`CandlesticksSeries`, `StackedLineSeries`, `StackedColumnSeries`, `StackedStepLineSeries`, `BoxSeries`, `ErrorSeries`.\n\nKey properties: `Series`, `XAxes`, `YAxes`, `ZoomMode`, `AnimationsSpeed`, `TooltipPosition`, `LegendPosition`.\n\n### PieChart\n\nHosts `PieSeries<T>`. Used for pie, doughnut, gauge, and Nightingale rose charts.\n\n### PolarChart\n\nHosts `PolarLineSeries<T>` and `PolarScatterSeries<T>`. Uses polar (angle + radius) coordinates.\n\n### GeoMap\n\nDisplays geographic maps. Hosts `HeatLandSeries` to color countries/regions by value.\n\n---\n\n## XAML Integration (WPF, Avalonia, MAUI, WinUI)\n\n### XAML Types (Xaml-prefixed)\n\nEvery `Series<T>` and `Axis` has a XAML-friendly counterpart (prefix `Xaml`). These live in the visual tree\nand support data bindings, styles, hot-reload and designer previews:\n\n- `XamlLineSeries`, `XamlColumnSeries`, `XamlPieSeries`, `XamlScatterSeries`, etc.\n- `XamlAxis`, `XamlDrawnLabelVisual`\n\nThe non-Xaml types (`LineSeries<T>`, `ColumnSeries<T>`) are plain C# objects and do **not** live in the\nvisual tree — use them in ViewModels when you want to keep UI logic separate from SkiaSharp dependencies.\n\n### SeriesCollection (WPF / WinUI / Uno)\n\nWPF, WinUI and Uno use `SeriesCollection` as a container in XAML to hold multiple series children:\n\n```xml\n<lvc:CartesianChart.Series>\n    <lvc:SeriesCollection>\n        <lvc:XamlLineSeries Values=\"{Binding Values1}\"/>\n        <lvc:XamlColumnSeries Values=\"{Binding Values2}\"/>\n    </lvc:SeriesCollection>\n</lvc:CartesianChart.Series>\n```\n\nAvalonia and MAUI support multiple children directly (no wrapper needed).\n\n---\n\n## Code Examples\n\n### Example 1 — Basic Line Chart (WPF, code-behind + XAML MVVM)\n\n**ViewModel (shared, no UI dependencies):**\n\n```csharp\n// samples/ViewModelsSamples/Lines/Basic/ViewModel.cs\nnamespace ViewModelsSamples.Lines.Basic;\n\npublic class ViewModel\n{\n    public double[] Values1 { get; set; } = [2, 1, 3, 5, 3, 4, 6];\n    public int[]    Values2 { get; set; } = [4, 2, 5, 2, 4, 5, 3];\n}\n```\n\n**WPF View (View.xaml):**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Lines.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Lines.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n                <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n**Avalonia View (View.axaml):**\n\n```xml\n<UserControl\n    x:Class=\"AvaloniaSample.Lines.Basic.View\"\n    xmlns=\"https://github.com/avaloniaui\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n    xmlns:vms=\"using:ViewModelsSamples.Lines.Basic\"\n    x:DataType=\"vms:ViewModel\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart>\n        <lvc:CartesianChart.Series>\n            <lvc:XamlLineSeries Values=\"{Binding Values1}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n            <lvc:XamlLineSeries Values=\"{Binding Values2}\" Fill=\"{x:Null}\" GeometrySize=\"20\"/>\n        </lvc:CartesianChart.Series>\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 2 — Bar Chart with Axis Labels (WPF)\n\n**ViewModel:**\n\n```csharp\nnamespace ViewModelsSamples.Bars.Basic;\n\npublic class ViewModel\n{\n    public double[] MaryValues { get; set; } = [2, 5, 4];\n    public double[] AnaValues  { get; set; } = [3, 1, 6];\n    public string[] Labels     { get; set; } = [\"Category 1\", \"Category 2\", \"Category 3\"];\n}\n```\n\n**WPF View:**\n\n```xml\n<UserControl\n    x:Class=\"WPFSample.Bars.Basic.View\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n    xmlns:vms=\"clr-namespace:ViewModelsSamples.Bars.Basic;assembly=ViewModelsSamples\">\n\n    <UserControl.DataContext>\n        <vms:ViewModel/>\n    </UserControl.DataContext>\n\n    <lvc:CartesianChart LegendPosition=\"Right\">\n\n        <lvc:CartesianChart.Series>\n            <lvc:SeriesCollection>\n                <lvc:XamlColumnSeries SeriesName=\"Mary\" Values=\"{Binding MaryValues}\"/>\n                <lvc:XamlColumnSeries SeriesName=\"Ana\"  Values=\"{Binding AnaValues}\"/>\n            </lvc:SeriesCollection>\n        </lvc:CartesianChart.Series>\n\n        <lvc:CartesianChart.XAxes>\n            <lvc:AxesCollection>\n                <lvc:XamlAxis\n                    Labels=\"{Binding Labels}\"\n                    SeparatorsPaint=\"#c8c8c8\"\n                    SeparatorsAtCenter=\"False\"\n                    TicksPaint=\"#232323\"\n                    TicksAtCenter=\"True\"\n                    MinStep=\"1\"\n                    ForceStepToMin=\"True\"/>\n            </lvc:AxesCollection>\n        </lvc:CartesianChart.XAxes>\n\n    </lvc:CartesianChart>\n\n</UserControl>\n```\n\n---\n\n### Example 3 — Real-Time Chart (shared ViewModel, any platform)\n\nAdds a new `DateTimePoint` every 100 ms using `ObservableCollection` — the chart updates automatically\nbecause `ObservableCollection` implements `INotifyCollectionChanged`.\n\n```csharp\nusing System;\nusing System.Collections.ObjectModel;\nusing System.Threading.Tasks;\nusing CommunityToolkit.Mvvm.ComponentModel;\nusing LiveChartsCore.Defaults;\n\nnamespace ViewModelsSamples.General.RealTime;\n\npublic partial class ViewModel : ObservableObject\n{\n    public ViewModel() { _ = ReadData(); }\n\n    // 'partial' is required by CommunityToolkit.Mvvm source generator (C# 14 partial properties)\n    [ObservableProperty]\n    public partial double[] Separators { get; set; } = [];\n\n    public ObservableCollection<DateTimePoint> Values { get; set; } = [];\n\n    public Func<DateTime, string> LabelsFormatter { get; } =\n        date => (DateTime.Now - date).TotalSeconds < 1 ? \"now\" : $\"{(DateTime.Now - date).TotalSeconds:N0}s ago\";\n\n    // Use a lock so background thread writes are safe\n    public object Sync { get; } = new object();\n    public bool IsReading { get; set; } = true;\n\n    private async Task ReadData()\n    {\n        var random = new Random();\n        while (IsReading)\n        {\n            await Task.Delay(100);\n            lock (Sync)\n            {\n                Values.Add(new DateTimePoint(DateTime.Now, random.Next(0, 10)));\n                if (Values.Count > 250) Values.RemoveAt(0);\n                Separators = GetSeparators();\n            }\n        }\n    }\n\n    private static double[] GetSeparators()\n    {\n        var now = DateTime.Now;\n        return [\n            now.AddSeconds(-25).Ticks,\n            now.AddSeconds(-20).Ticks,\n            now.AddSeconds(-15).Ticks,\n            now.AddSeconds(-10).Ticks,\n            now.AddSeconds(-5).Ticks,\n            now.Ticks\n        ];\n    }\n}\n```\n\n> **Threading note:** When updating chart data from a non-UI thread, use a lock object (`Sync`) and assign\n> it to the chart's `SyncContext` property so LiveCharts can coordinate reads/writes safely.\n\n---\n\n### Example 4 — Pie Chart with Named Slices\n\n```csharp\nnamespace ViewModelsSamples.Pies.Basic;\n\npublic class PieData(string name, double value)\n{\n    public string Name   { get; set; } = name;\n    public double[] Values { get; set; } = [value];\n}\n\npublic class ViewModel\n{\n    public PieData[] Data { get; set; } =\n    [\n        new(\"Mary\",    10),\n        new(\"John\",    20),\n        new(\"Alice\",   30),\n        new(\"Bob\",     40),\n        new(\"Charlie\", 50),\n    ];\n}\n```\n\n**WPF View (using XAML template):**\n\n```xml\n<lvc:PieChart SeriesSource=\"{Binding Data}\">\n    <lvc:PieChart.SeriesTemplate>\n        <DataTemplate>\n            <lvc:XamlPieSeries\n                SeriesName=\"{Binding Name}\"\n                Values=\"{Binding Values}\"/>\n        </DataTemplate>\n    </lvc:PieChart.SeriesTemplate>\n</lvc:PieChart>\n```\n\n---\n\n### Example 5 — Custom Mapper (CLI / Console / Server)\n\nRender a chart to an image without any UI framework using `SKCartesianChart`:\n\n```csharp\nusing LiveChartsCore.SkiaSharpView.SKCharts;\nusing LiveChartsCore.SkiaSharpView;\n\n// Custom data type\npublic class TempSample { public int Time { get; set; } public double Temperature { get; set; } }\n\nvar samples = new[]\n{\n    new TempSample { Time = 1, Temperature = 65.65 },\n    new TempSample { Time = 5, Temperature = 62.23 },\n    new TempSample { Time = 8, Temperature = 85.12 },\n};\n\nvar chart = new SKCartesianChart\n{\n    Width  = 900,\n    Height = 600,\n    Series = new[]\n    {\n        new LineSeries<TempSample>\n        {\n            Values  = samples,\n            Mapping = (sample, index) => new(sample.Time, sample.Temperature)\n        }\n    },\n    XAxes = new[] { new Axis { Labeler = value => $\"{value} s\" } },\n    YAxes = new[] { new Axis { Labeler = value => $\"{value} °C\" } },\n};\n\nchart.SaveImage(\"chart.png\");\n```\n\n---\n\n## Axes\n\nThe `CartesianChart` exposes `XAxes` and `YAxes` (both `IEnumerable<IAxis>`). Default: one `Axis` each.\n\n### Key Axis properties\n\n| Property | Description |\n|---|---|\n| `Labeler` | `Func<double, string>` — formats axis tick labels |\n| `Labels` | `IList<string>` — named labels (index-based, used for category axes) |\n| `MinLimit` / `MaxLimit` | Fix the visible range (used for zooming/panning) |\n| `MinStep` / `ForceStepToMin` | Force minimum separation between ticks |\n| `SeparatorsPaint` | Paint for grid lines |\n| `TicksPaint` | Paint for axis tick marks |\n| `NamePaint` | Paint for the axis name label |\n| `DataLabelsPaint` | Paint for data labels on the series |\n| `CrosshairPaint` | Paint for crosshair lines |\n| `IsVisible` | Show/hide the axis |\n| `Position` | `AxisPosition.Start` or `AxisPosition.End` |\n\n### Zooming and Panning\n\n```csharp\n// Enable X-axis zoom and pan:\nmyChart.ZoomMode = ZoomAndPanMode.X;\n\n// Enable both axes:\nmyChart.ZoomMode = ZoomAndPanMode.Both;\n\n// Disable:\nmyChart.ZoomMode = ZoomAndPanMode.None;\n```\n\nEach gesture also has its own flag (`PanX`, `ZoomX`, `PanY`, `ZoomY`) so zoom and pan can be enabled independently. The composites `X = PanX | ZoomX`, `Y = PanY | ZoomY` and `Both = X | Y` keep their original pan+zoom semantics.\n\n```csharp\n// Allow zooming on the X axis but disable panning (e.g. so pan gestures don't hide tooltips on mobile):\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX;\n\n// Zoom on X, pan on Y:\nmyChart.ZoomMode = ZoomAndPanMode.ZoomX | ZoomAndPanMode.PanY;\n```\n\n`ZoomAndPanMode` is a flags enum — combine values:\n```csharp\nmyChart.ZoomMode = ZoomAndPanMode.X | ZoomAndPanMode.NoFit | ZoomAndPanMode.NoZoomBySection;\n```\n\n### DateTime / TimeSpan Axes\n\nUse `DateTimePoint` or `TimeSpanPoint` for time-based X axes and format with a `Labeler`:\n\n```csharp\nXAxes = new[]\n{\n    new Axis\n    {\n        Labeler = value => new DateTime((long)value).ToString(\"HH:mm:ss\"),\n        UnitWidth = TimeSpan.FromSeconds(1).Ticks,\n        MinStep  = TimeSpan.FromSeconds(1).Ticks,\n    }\n};\n```\n\n---\n\n## Tooltips & Legends\n\n```csharp\n// Tooltip position options: Top (default), Bottom, Left, Right, Center, Hidden\nmyChart.TooltipPosition = TooltipPosition.Bottom;\n\n// Legend position: Hidden (default), Top, Bottom, Left, Right\nmyChart.LegendPosition = LegendPosition.Right;\n```\n\nCustom tooltips: implement `IChartTooltip<TDrawingContext>` and assign to `Chart.Tooltip`.  \nCustom legends: implement `IChartLegend<TDrawingContext>` and assign to `Chart.Legend`.\n\n---\n\n## Sections (Reference Lines / Bands)\n\n```csharp\nusing LiveChartsCore;\n\nmyChart.Sections = new[]\n{\n    new RectangularSection\n    {\n        Yi = 4,\n        Yj = 8,\n        Fill = new SolidColorPaint(new SKColor(255, 205, 210, 100))\n    }\n};\n```\n\n---\n\n## Drawing on Canvas\n\nUse `Chart.VisualElements` to overlay custom SkiaSharp drawing:\n\n```csharp\nmyChart.VisualElements = new[]\n{\n    new DrawnVisual\n    {\n        OnDraw = (canvas, chart) =>\n        {\n            canvas.DrawText(\"Hello!\", new SKPoint(100, 100), new SKPaint { Color = SKColors.Black });\n        }\n    }\n};\n```\n\n---\n\n## Server-Side / Console Chart Generation\n\nInstall only the core packages (no UI framework required):\n\n```\ndotnet add package LiveChartsCore.SkiaSharpView\n```\n\nUse `SKCartesianChart`, `SKPieChart`, `SKPolarChart`, `SKGeoMap` — they all inherit from `InMemorySkiaSharpChart`\nand expose a `GetImage()` method that returns an `SKImage`:\n\n```csharp\nvar chart = new SKCartesianChart\n{\n    Width = 900, Height = 600,\n    Series = new ISeries[] { new LineSeries<int> { Values = new[] { 1, 2, 3 } } }\n};\n\n// Save to file:\nchart.SaveImage(\"output.png\");\n\n// Or get bytes for HTTP response:\nusing var image  = chart.GetImage();\nusing var data   = image.Encode(SKEncodedImageFormat.Png, 100);\nusing var stream = data.AsStream();\n```\n\n---\n\n## Multi-threading\n\nWhen modifying chart data from a background thread, always use a `lock`:\n\n```csharp\n// 1. Define a sync object in your ViewModel:\npublic object Sync { get; } = new object();\n\n// 2. Assign it to the chart control (XAML or code-behind):\n//    myChart.SyncContext = viewModel.Sync;\n\n// 3. Wrap all data mutations in the lock:\nlock (Sync)\n{\n    Values.Add(new ObservableValue(random.Next(0, 10)));\n    if (Values.Count > 200) Values.RemoveAt(0);\n}\n```\n\n---\n\n## Themes and Color Palettes\n\n```csharp\nLiveCharts.Configure(settings =>\n    settings\n        .AddDefaultTheme(theme =>\n            theme.OnInitialized(() =>\n            {\n                theme.AnimationsSpeed  = TimeSpan.FromMilliseconds(300);\n                theme.EasingFunction   = EasingFunctions.QuadraticOut;\n                theme.Colors           = ColorPalletes.MaterialDesign500;\n            })));\n```\n\nBuilt-in palettes: `MaterialDesign200`, `MaterialDesign500`, `MaterialDesign800`, `FluentDesign`, etc.\n\n---\n\n## Common Namespaces\n\n```csharp\nusing LiveChartsCore;                            // ISeries, IAxis, LiveCharts.Configure, etc.\nusing LiveChartsCore.Defaults;                   // ObservableValue, ObservablePoint, DateTimePoint, etc.\nusing LiveChartsCore.Kernel;                     // Coordinate, ChartEntityMetaData, IChartEntity\nusing LiveChartsCore.Measure;                    // ZoomAndPanMode, TooltipPosition, LegendPosition, etc.\nusing LiveChartsCore.SkiaSharpView;              // LineSeries, ColumnSeries, Axis, etc. (non-XAML)\nusing LiveChartsCore.SkiaSharpView.Painting;     // SolidColorPaint, LinearGradientPaint, etc.\nusing LiveChartsCore.SkiaSharpView.WPF;          // CartesianChart, PieChart (WPF controls)\nusing LiveChartsCore.SkiaSharpView.Avalonia;     // CartesianChart, PieChart (Avalonia controls)\nusing LiveChartsCore.SkiaSharpView.Maui;         // CartesianChart, PieChart (MAUI controls)\nusing LiveChartsCore.SkiaSharpView.SKCharts;     // SKCartesianChart, SKPieChart (server-side)\nusing SkiaSharp;                                 // SKColor, SKPoint, SKPaint, etc.\n```\n\n---\n\n## API Reference URL Pattern\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\nUse `latest` as the version for the most recent docs, or a specific version string.\n`{objectFullName}` uses CLI metadata naming (e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`).\n\nFull docs: `https://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}`\n\nWhere `{UIFramework}` ∈ `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`.\n\n---\n\n## Frequently Asked Questions\n\n**Q: My chart is blank / not showing.**  \nA: The chart control has no default size constraint. Set an explicit `Width` and `Height`, or ensure the\nparent layout does not collapse the control to zero size.\n\n**Q: Changes to my data don't update the chart.**  \nA: Use `ObservableCollection<T>` for the `Series` collection and the `Values` collection.\nFor property-level updates, implement `INotifyPropertyChanged` on your data class (or use `ObservableValue`).\n\n**Q: How do I use LiveCharts without SkiaSharp?**  \nA: Implement the Core drawing interfaces (`IDrawingContext`, etc.) and register your custom renderer.\nThe `VorticeSample` in the repository demonstrates this using DirectX11 via Vortice.Windows.\n\n**Q: Can I use LiveCharts in a Blazor Server app?**  \nA: The official package targets Blazor WASM. For server-side use, use `SKCartesianChart` to generate\nPNG/JPEG images on the server and serve them as `<img>` tags.\n\n**Q: How do I disable animations?**  \nA: Set `myChart.EasingFunction = null;` or `myChart.AnimationsSpeed = TimeSpan.Zero;`.\n\n<!-- File: llms.txt (Tokens: ~1775 | Category: root-instruction) -->\n# LiveCharts2\n\nLiveCharts2 (v2) is a flexible, cross-platform charting library for .NET built on top of SkiaSharp for rendering; it supports Cartesian, Pie, Polar, and GeoMap chart types with smooth, automatic animations. The library uses a layered architecture separating a platform-agnostic Core from a SkiaSharp-based Renderer and platform-specific Views (WPF, Avalonia, MAUI, Blazor, etc.), so adding a new platform requires minimal effort. LiveCharts2 targets .NET Framework 4.6.2, .NET Standard 2.0, and modern .NET, and uses `INotifyPropertyChanged`/`INotifyCollectionChanged` for zero-boilerplate automatic chart updates.\n\n> **⚠️ Important: This is LiveCharts v2. Do NOT use v0 syntax.**\n> The legacy v0 (`LiveCharts` / `LiveCharts.Wpf` NuGet packages) is obsolete and has a completely different API.\n> v0 source and samples: https://github.com/Live-Charts/Live-Charts\n> Always use the v2 packages listed below and the v2 documentation at https://livecharts.dev.\n\n## Supported UI Frameworks\n\n- **MAUI** — `LiveChartsCore.SkiaSharpView.Maui` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.maui\n- **Uno Platform (WinUI)** — `LiveChartsCore.SkiaSharpView.Uno.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.Uno.WinUI\n- **Avalonia** — `LiveChartsCore.SkiaSharpView.Avalonia` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.avalonia\n- **WPF** — `LiveChartsCore.SkiaSharpView.WPF` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.wpf\n- **WinForms** — `LiveChartsCore.SkiaSharpView.WinForms` — https://www.nuget.org/packages/LiveChartsCore.skiasharpview.winforms\n- **WinUI** — `LiveChartsCore.SkiaSharpView.WinUI` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.winui\n- **Blazor (WASM)** — `LiveChartsCore.SkiaSharpView.Blazor` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.blazor\n- **Eto.Forms** — `LiveChartsCore.SkiaSharpView.Eto` — https://www.nuget.org/packages/LiveChartsCore.SkiaSharpView.eto\n\n## URL Templates\n\n### API Reference\n\n```\nhttps://livecharts.dev/api/{LiveChartsVersion}/{objectFullName}\n```\n\n- `{objectFullName}` follows CLI (Common Language Infrastructure) metadata naming conventions, e.g. `LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `{LiveChartsVersion}`: use `latest` for the latest version, or a specific version string (e.g. `2.0.0-rc6.1`)\n- Full list of available versions: `https://livecharts.dev/docs/{UIFramework}/list`\n  - `{UIFramework}` is one of: `maui`, `unowinui`, `avalonia`, `eto`, `blazor`, `wpf`, `winforms`, `winui`\n\n**Examples:**\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.WPF.CartesianChart`\n- `https://livecharts.dev/api/latest/LiveChartsCore.SkiaSharpView.Avalonia.PieChart`\n\n### Documentation & Examples\n\n```\nhttps://livecharts.dev/docs/{UIFramework}/{LiveChartsVersion}/{ArticleName}\n```\n\n`{UIFramework}` and `{LiveChartsVersion}` are as described above.\n\nAvailable `{ArticleName}` values:\n\n**Overview**\n- `Overview.Installation`\n- `Overview.How%20it%20works`\n- `Overview.Automatic%20updates`\n- `Overview.Mappers`\n- `Overview.Paints`\n- `Overview.Animations`\n\n**Cartesian Chart**\n- `CartesianChart.Cartesian%20chart%20control`\n- `CartesianChart.Axes%20properties`\n- `CartesianChart.Tooltips`\n- `CartesianChart.Legends`\n- `CartesianChart.Line%20series%20properties`\n- `CartesianChart.Column%20series%20properties`\n- `CartesianChart.Scatter%20series%20properties`\n- `CartesianChart.Step%20line%20series%20properties`\n- `CartesianChart.Heat%20series%20properties`\n- `CartesianChart.Candle%20sticks%20series%20properties`\n- `CartesianChart.Stacked%20line%20series%20properties`\n- `CartesianChart.Stacked%20column%20series%20properties`\n- `CartesianChart.Stacked%20step%20line%20series%20properties`\n- `CartesianChart.Box%20series%20properties`\n\n**Pie Chart**\n- `PieChart.Pie%20chart%20control`\n- `PieChart.Pie%20series`\n- `PieChart.Gauges`\n\n**Polar Chart**\n- `PolarChart.Polar%20chart%20control`\n- `PolarChart.Polar%20line%20series`\n\n**GeoMap**\n- `GeoMap.GeoMap%20control`\n- `GeoMap.Heat%20land%20series`\n\n**About**\n- `About.About%20this%20samples`\n\n**Samples**\n- `samples.lines.basic`\n- `samples.lines.straight`\n- `samples.lines.area`\n- `samples.lines.custom`\n- `samples.lines.custompoints`\n- `samples.lines.autoupdate`\n- `samples.lines.xy`\n- `samples.lines.zoom`\n- `samples.steplines.basic`\n- `samples.stackedArea.basic`\n- `samples.stackedArea.stepArea`\n- `samples.bars.basic`\n- `samples.bars.withBackground`\n- `samples.bars.custom`\n- `samples.bars.spacing`\n- `samples.bars.layered`\n- `samples.bars.rowsWithLabels`\n- `samples.bars.delayedAnimation`\n- `samples.bars.race`\n- `samples.stackedBars.basic`\n- `samples.stackedBars.groups`\n- `samples.pies.basic`\n- `samples.pies.pushout`\n- `samples.pies.doughnut`\n- `samples.pies.outlabels`\n- `samples.pies.custom`\n- `samples.pies.icons`\n- `samples.pies.nightingaleRose`\n- `samples.pies.nested`\n- `samples.pies.gauge1`\n- `samples.pies.gauge2`\n- `samples.pies.gauge3`\n- `samples.pies.gauge4`\n- `samples.pies.gauge5`\n- `samples.pies.angularGauge`\n- `samples.error.basic`\n- `samples.box.basic`\n- `samples.scatter.basic`\n- `samples.scatter.bubbles`\n- `samples.scatter.custom`\n- `samples.financial.basicCandlesticks`\n- `samples.heat.basic`\n- `samples.polar.basic`\n- `samples.polar.radialArea`\n- `samples.polar.coordinates`\n- `samples.maps.world`\n- `samples.events.tutorial`\n- `samples.events.addPointOnClick`\n- `samples.axes.labelsFormat`\n- `samples.axes.labelsFormat2`\n- `samples.axes.multiple`\n- `samples.axes.shared`\n- `samples.axes.style`\n- `samples.axes.crosshairs`\n- `samples.axes.dateTimeScaled`\n- `samples.axes.timeSpanScaled`\n- `samples.axes.matchScale`\n- `samples.axes.logarithmic`\n- `samples.axes.customSeparatorsInterval`\n- `samples.axes.paging`\n- `samples.general.multiThreading`\n- `samples.general.realTime`\n- `samples.general.sections`\n- `samples.general.chartToImage`\n- `samples.general.visualElements`\n- `samples.general.visibility`\n- `samples.general.nullPoints`\n- `samples.general.customTooltips`\n- `samples.general.customLegends`\n- `samples.general.mapPoints`\n- `samples.general.drawOnCanvas`\n- `samples.general.conditionalDraw`\n- `samples.general.scrollable`\n- `samples.design.linearGradients`\n- `samples.design.radialGradients`\n- `samples.design.strokeDashArray`\n\n<!-- File: .claude/skills/render-chart/SKILL.md (Tokens: ~1966 | Category: anthropic-skill) -->\n---\nname: render-chart\ndescription: Use when the user asks to render, visualize, plot, or \"show me a chart of\" any kind of series data (line, column, row, scatter, stacked, candlestick, box, pie, polar, heat). Renders via the `lvc` CLI from a JSON spec — inline in your reply for simple charts you need to read, or in a new terminal window for interactive / color-dependent ones (heat maps, pies with many slices, anything with > 3 series the user wants to explore).\n---\n\n# render-chart\n\nThe user wants to *see* data as a chart. You have access to a renderer (`lvc`)\nthat writes LiveCharts to a terminal. Pick the right mode for the situation,\ninstall the tool if it's missing, and either inline the result in your reply\nor hand the user a live window.\n\n## Decision: inline vs live window\n\n| Situation | Mode | Why |\n| --- | --- | --- |\n| ≤ 3 series, line / column / row / stacked-bar / scatter, you need to *verify* the shape | `--no-color` inline | Plain Braille glyphs render in a fenced code block. You can read it; the user sees it. |\n| User said \"open this in a new window\" / \"let me play with it\" / \"zoom into this\" | `--live` in a new terminal | Interactive Sixel + mouse hover + wheel zoom + click-drag pan. The user explores; you can't read the result, so don't pretend to. |\n| Heat map | `--live` in a new terminal | Heat reads the gradient by color. Strip color and it's an undifferentiated blob. |\n| Pie with > 4 slices | `--live` in a new terminal | Outer labels collide and Pushout gaps stop reading at small canvas sizes. |\n| Anything where the *meaning* depends on color (gradient encodes magnitude, similar curves only separable by hue) | `--live` in a new terminal | Plain mode can't carry color information — see [[reference_claude_code_cli_ansi_passthrough]]. |\n| User asks to \"compare these two/three series\" with simple shapes | `--no-color` inline | Single bar series stays Braille; multi-bar uses textures; line series get end-of-line labels. Distinguishable without color. |\n\n**Default to `--no-color` inline** when you can read the chart — it keeps the\nconversation flowing and you can describe what's in it. Reserve `--live` for\nwhen there's genuinely no way to convey the information in monochrome glyphs.\n\n## Step 1 — make sure dotnet is installed\n\n```sh\ndotnet --version\n```\n\nIf that errors, the user needs the .NET 8 SDK or runtime. Point them at\n<https://dotnet.microsoft.com/download> and stop — don't try to install it\nfor them (admin install, varies per OS).\n\n## Step 2 — install `lvc` as a global tool (once)\n\n```sh\ndotnet tool install -g LiveChartsCore.Console.Cli\n```\n\nIf they already have it, this errors with \"already installed\" — that's fine.\nUpdate with `dotnet tool update -g LiveChartsCore.Console.Cli`.\n\nAfter install, `lvc` is on the user's PATH. Verify with:\n\n```sh\nlvc --json '{\"kind\":\"line\",\"series\":[{\"values\":[1,2,3,2,1]}]}' --no-color\n```\n\nYou should see a small Braille line chart in stdout.\n\n## Step 3 — write the JSON spec\n\nPass via `--json '<spec>'`, `--file path.json`, or pipe stdin.\n\n```json\n{\n  \"kind\": \"line\",\n  \"title\": \"optional\",\n  \"width\": 70,\n  \"height\": 20,\n  \"series\": [\n    {\n      \"name\": \"Signal\",\n      \"values\": [1, 2, 3, 4],\n      \"strokeThickness\": 2\n    }\n  ],\n  \"xAxis\": { \"name\": \"X\", \"labels\": [\"a\", \"b\", \"c\", \"d\"] },\n  \"yAxis\": { \"name\": \"Y\" }\n}\n```\n\n`kind` accepts: `line`, `column`, `row`, `step`, `scatter`, `stackedcolumn`,\n`stackedrow`, `stackedarea`, `candlestick`, `box`, `pie`, `polar`.\n\nSeries shape:\n- `values: number[]` — line / column / row / step / stacked / pie / polar\n- `points: number[][]` — scatter (`[x, y]`) / candlestick (`[open, high, close, low]`) / box (`[max, q3, q1, median, min]`)\n- `strokeThickness: number` — line / step (optional, default 1)\n\nFor pie: needs `--width ≥ 80 --height ≥ 30` (outer labels collide otherwise).\nFor stacked column / row with 2+ series: per-series textures auto-applied in\nplain mode; legend shows the texture next to each series name.\n\n## Step 4a — inline rendering (the common path)\n\n```sh\nlvc --json '<spec>' --no-color --width 70 --height 20\n```\n\nCapture the output and paste it back inside a fenced code block in your reply.\nCommonMark renders it monospace, the user sees the same glyphs you see.\n\nSizing: ~70×20 is a sweet spot. Smaller charts get cramped; larger ones might\nwrap weirdly in the user's terminal. Default to 70×20 unless the user asked\notherwise.\n\nRead what you rendered. Describe what's in it — \"the blue series climbs from\n~5 to ~12, the red oscillates around 8\" — so the user can sanity-check it\nmatches what they wanted. Don't claim \"the chart looks correct\" without\nnaming the actual shapes you see.\n\n## Step 4b — live window (interactive / color path)\n\nSpawn a new terminal so it doesn't block your conversation:\n\n**Windows (Windows Terminal):**\n```pwsh\nStart-Process wt.exe -ArgumentList '-d', $pwd.Path, 'pwsh', '-NoExit', '-NoLogo', '-Command', 'lvc --live --file demo.json'\n```\n\n**macOS (Terminal.app):**\n```sh\nosascript -e \"tell app \\\"Terminal\\\" to do script \\\"lvc --live --file $PWD/demo.json\\\"\"\n```\n\n**Linux (GNOME Terminal):**\n```sh\ngnome-terminal --working-directory=\"$PWD\" -- lvc --live --file demo.json\n```\n\nFor multi-line JSON, write a `demo.json` file first via the Write tool and\npass `--file` — avoids cross-shell quoting hell.\n\n**Critical:** you can't read the live window's contents. After launching,\ntell the user \"I opened a chart in a new window — what do you see?\" and\niterate from their feedback. Don't fabricate a description of what's\n\"probably there.\"\n\nIn the live window the user gets: mouse hover (tooltips), click-and-drag (pan),\nmouse wheel (zoom), `q` (quit), `r` (reset zoom), `+` / `-` (zoom at center).\n\n## Common pitfalls\n\n- **`--live --no-color`** is an error: live mode redraws frames in place via\n  ANSI escapes, which is exactly what `--no-color` strips. Pick one.\n- **`--live` with stdout redirected** errors out — it needs a real TTY. Always\n  spawn a new terminal window, never pipe `--live` output.\n- **`--mode sixel --no-color`** errors out — Sixel is a binary escape sequence\n  with no plain form. Drop `--mode sixel` or drop `--no-color`.\n- **Pie charts in plain mode at small canvases** collapse the disc to a sliver\n  because outer labels reserve margin space. Use `--width 80 --height 30`\n  minimum, or accept a smaller render in `--live` mode where the disc has\n  full canvas.\n- **Stacked bar plain mode with 1 series** keeps Braille `⣿` fills (no\n  textures kick in until 2+ bar series exist). This is intentional.\n- **You cannot see colors in the user's terminal from your own output.** Inline\n  ANSI escapes you write get collapsed to one inline-code style by the\n  CommonMark renderer — see [[reference_claude_code_cli_ansi_passthrough]].\n  This is why `--no-color` is the inline path: plain glyphs don't pretend to\n  carry color information.\n\n## When NOT to use this skill\n\n- The user asks to *edit chart configuration* in a LiveCharts app (XAML /\n  source-code view) — that's a code-edit task, not a rendering task.\n- The user wants to *understand* a chart they already have a screenshot of —\n  use vision on the image, not lvc.\n- The data is structural / hierarchical (trees, graphs, org charts) — lvc\n  only handles statistical chart kinds.\n\n<!-- File: .claude/skills/repro-and-fix/SKILL.md (Tokens: ~4751 | Category: anthropic-skill) -->\n---\nname: repro-and-fix\ndescription: Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. \"let's work on issue #1234\", a github.com/Live-Charts/LiveCharts2/issues/N URL, or \"reproduce and propose a fix\"). Implements the LiveCharts workflow end-to-end — worktree, in-sample repro view, auto-launched sample, screenshot/log verification, diagnosis, fix, separate regression-test commit, and PR — with minimal user interaction.\n---\n\n# repro-and-fix\n\nA user pointed you at a GitHub issue and asked you to reproduce + fix it. Run\nthe workflow below. The whole point is that the dev loop is *self-contained*:\nyou build the repro, launch the sample at that repro automatically, verify the\nbug yourself (screenshot or logs), fix it, verify the fix, and commit. Don't\nask the user for visual confirmations you can get yourself.\n\n> **Shared with Copilot Coding Agent.** `.github/copilot-instructions.md` links\n> here as the canonical issue → reproduce → fix → PR workflow. Edit this file\n> when changing the workflow; keep the Copilot doc as a thin pointer to avoid\n> drift.\n\n## When this skill applies\n\n- \"Let's work on https://github.com/Live-Charts/LiveCharts2/issues/N\"\n- \"Reproduce issue #N and propose a fix\"\n- \"Investigate this bug report: <URL>\"\n- A user paste of an issue URL with no other instruction\n\nIf the user is asking about *theory* (\"why does the gauge use a doughnut\ngeometry?\") or a *non-issue* task (refactor, doc update, perf), this skill is\nnot the right tool — fall back to general workflow.\n\n## Pick the platform that matches the issue\n\nRead the issue's **labels** and **repro snippet** to choose. The workflow is\nthe same on every XAML platform — only paths and launch commands change.\n\n| Platform | Sample dir                    | Launch project (Debug build)                                                | In-app screenshot |\n| -------- | ----------------------------- | --------------------------------------------------------------------------- | ----------------- |\n| Avalonia | `samples/AvaloniaSample/`     | `samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/.../*.Desktop.exe` | ✅ supported       |\n| WPF      | `samples/WPFSample/`          | `samples/WPFSample/.../WPFSample.exe`                                       | ✅ supported       |\n| WinUI    | `samples/WinUISample/WinUISample/` | `samples/WinUISample/WinUISample/.../WinUISample.exe`                  | ✅ supported       |\n| MAUI     | `samples/MauiSample/`         | per-platform; `dotnet build -t:Run -f net10.0-windows10.0.19041.0`          | ❌ use OS tool     |\n| Uno      | `samples/UnoPlatformSample/UnoPlatformSample/` | per-platform                                              | ❌ use OS tool     |\n\nIf the issue is platform-agnostic (a core engine bug), prefer Avalonia for the\nfastest dev loop on Windows (no WindowsAppSDK / packaged-build overhead).\n\n## Project conventions you must follow\n\nThese are durable rules from `~/.claude/projects/.../memory/MEMORY.md`. Re-read\nthe relevant memory file if uncertain — these are not optional:\n\n- **Worktree per issue.** Create `../LiveCharts2-fix-<issue>-<slug>` first\n  (`feedback_worktree_per_issue`). Don't work in the primary tree.\n- **One concept per commit.** Fix and regression test go in *separate* commits.\n  The regression-test commit must fail when the fix is reverted — verify this\n  before pushing (`feedback_commit_separation`).\n- **Snapshot tests for render-path changes.** If your fix touches paint, layout,\n  z-index, or draw order, run `tests/SnapshotTests/` before claiming done — unit\n  tests have missed catastrophic regressions\n  (`feedback_run_snapshots_for_render_changes`).\n- **Update docs when public API changes** in the same change set as a separate\n  commit (`feedback_update_docs_for_api`).\n- Check `Directory.Build.props` for `<LiveChartsVersion>` and use that value in\n  user-facing text (`project_current_version`).\n\n## Workflow\n\n### 1. Read the issue and decide if it still reproduces\n\n```bash\ngh issue view <N> --repo Live-Charts/LiveCharts2 --json title,body,labels,state,comments\n```\n\nPay attention to **comments**, not just the body. Issues commonly evolve:\n\n- The original symptom may already be fixed in main (commenter says \"newer\n  releases fixed this\") and the *current* bug is a downstream observation.\n  This is exactly what happened with #2008 — the `GaugeValue` TemplateBinding\n  bug in the title was already resolved; the live bug was a `CornerRadius=0`\n  override in the comments.\n- Multiple users may report different things in the same thread. Identify the\n  most recent reporter's actual symptom.\n\nIf you suspect the title bug is already fixed: build the original repro\nverbatim and verify *first*, before doing diagnosis. Cite the commenter who\nsaid it's fixed in your PR description.\n\n### 2. Set up the worktree\n\n```bash\ngit worktree add ../LiveCharts2-fix-<issue>-<short-slug> -b fix/issue-<N>-<short-slug>\n```\n\nAll edits, builds, and runs happen in the worktree. The primary tree stays\nclean for other work.\n\n### 3. Build the repro view (XAML platforms)\n\nThe repro convention is a **sample view inside the platform sample app**:\n\n```\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>\nsamples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>.cs\n```\n\nMatch the issue's repro setup as closely as you can — same `ControlTemplate`\nshape, same property values, same paints. *Don't simplify* until you've\nconfirmed the bug fires; over-minimization can accidentally avoid the trigger.\n\nExisting repros to mirror:\n\n- `samples/AvaloniaSample/VisualTest/Issue1986Repro/` — TabControl + ScrollViewer\n- `samples/AvaloniaSample/VisualTest/Issue1417Repro/` — GeoMap reattach\n\nThe View's code-behind should expose helpers that a Factos test can call\n(e.g. `FindTemplatedGaugeSeries()`). This is how the regression test hooks in\nwithout going through the visual tree.\n\n**Do not commit changes to `samples/ViewModelsSamples/Index.cs` for repro\nviews.** Factos navigates to a sample by path via `LVC_SAMPLE` regardless of\nwhether the path is listed in the index, and the index is shared across every\nplatform sample. If you add `VisualTest/Issue<N>Repro` there and the view only\nexists in `samples/AvaloniaSample/`, every other platform sample (WPF, MAUI,\nWinUI, Uno) will throw when it loads the index. Leave the file untouched on\nyour branch.\n\nIf it's genuinely easier for your *local* dev loop to pick the repro from the\nsample selector dropdown rather than via `LVC_SAMPLE`, edit `Index.cs`\ntemporarily — but revert it before committing. `git restore\nsamples/ViewModelsSamples/Index.cs` before each commit, or just don't stage\nthe file.\n\n### 4. Auto-launch the sample at your repro\n\nAll XAML platform samples read `LVC_SAMPLE` at startup and load that sample\ninstead of the default landing screen. Set it before launching:\n\n```bash\n# bash / WSL\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nBuild first if needed: `dotnet build samples/<Platform>Sample/... -c Debug`.\n\n### 5. Verify the bug yourself\n\nTwo paths — pick based on the bug type:\n\n**A. In-app screenshot for visual bugs** (color, shape, position, rendering\nartifacts). Avalonia/WPF/WinUI samples support `LVC_SCREENSHOT`: when set,\nthe sample renders its main window via the framework's native\n`RenderTargetBitmap` after a short delay (default 3 s, override with\n`LVC_SCREENSHOT_DELAY_MS`) and exits. No external tooling, no race against\na screenshot tool launching too early. The capture is scaled to the\nwindow's physical pixels (`RenderScaling` on Avalonia,\n`VisualTreeHelper.GetDpi` on WPF) so HiDPI displays produce a sharp PNG\nthat matches what's on screen:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-before.png \\\n  ./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe\n```\n\n```powershell\n# PowerShell\n$env:LVC_SAMPLE = \"VisualTest/Issue<N>Repro\"\n$env:LVC_SCREENSHOT = \"$pwd\\.claude\\screenshots\\<N>-before.png\"\n.\\samples\\WPFSample\\bin\\Debug\\net10.0-windows\\WPFSample.exe\n```\n\nAfter it exits, `Read` the PNG. You're multimodal — describe what you see,\ncompare to a control sample (often `Pies/Gauge1` or `General/FirstChart` for\n\"what should this look like\"). If the bug is subtle (a few pixels), make the\nrepro larger (`Width=380`, `Height=380`) so it's clearly visible.\n\n**Fallback for MAUI/Uno or other-OS edge cases:** use the OS-appropriate\nhelper script. They all take `<ProcessName> <OutPath> [WaitSeconds]` and\npoll for the target window before capturing:\n\n| OS      | Script                                       | Underlying tool                            |\n| ------- | -------------------------------------------- | ------------------------------------------ |\n| Windows | `.claude/scripts/capture-window.ps1`         | `PrintWindow` via Win32 (works occluded)   |\n| macOS   | `.claude/scripts/capture-window-macos.sh`    | `osascript` + `screencapture -l <id>`      |\n| Linux   | `.claude/scripts/capture-window-linux.sh`    | `xdotool`+`import` / `swaymsg`+`grim` / `gnome-screenshot` |\n\nThe Linux script tries X11 → sway → GNOME in priority order; install the\nmatching package if none are present (the script prints the apt/dnf hint).\nUse these only when `LVC_SCREENSHOT` isn't supported on the target platform\n(MAUI, Uno) — for Avalonia/WPF/WinUI prefer in-app capture.\n\n**B. Console logs for state/dataflow bugs** (binding doesn't fire, value\ndoesn't propagate, event order is wrong):\n\nAdd temporary `Console.WriteLine` calls along the suspected path:\n\n```csharp\nConsole.WriteLine($\"[issue<N>] OnPropertyChanged: {change.Property.Name} old={change.OldValue} new={change.NewValue}\");\n```\n\nThe platform sample writes to stdout when launched from the terminal. Run via\nthe bash tool with `run_in_background=true` (no `LVC_SCREENSHOT` so the app\nstays open), wait a few seconds, kill the app, then `grep` the captured output\nfile. **Remove the diagnostics before committing.**\n\nIf neither approach decisively confirms the bug, escalate to the user with\n**one** well-framed question, not a chain of polling questions. Example:\n\n> \"The before-fix capture shows the gauge endcaps as flat, contrary to the\n> issue's screenshot. Did you toggle CornerRadius after the screenshot was\n> taken in the original report?\"\n\n### 6. Diagnose the root cause\n\nTrace from symptom backward through the rendering/data pipeline. Cross-check\nagainst `MEMORY.md` — many bugs in this repo have related ancestors\n(z-index issues, theme overrides, motion-property defaults, source-gen\nbehavior). If you find a matching memory note, use its diagnosis as a starting\npoint but verify against current code; memories go stale.\n\nCommon gotchas in this codebase:\n\n- **Theme overrides user-set values** when the user's value equals the DP\n  default — Avalonia skips `OnPropertyChanged` and `_userSets` never gets\n  populated. `XamlGaugeSeries.EndInit` syncs IsSet DPs as a remediation; if\n  you see this pattern in another wrapper, the same fix shape applies.\n- **Series controls aren't in the visual tree.** `OnInitialized` and\n  `TemplatedParent` may not fire/be set the way you'd expect. Use `EndInit`\n  instead.\n- **Theme rules run from the chart engine measure pass**, not at construction.\n  `_isInternalSet` + `_userSets` is the existing precedence mechanism — don't\n  reinvent it.\n- **Motion properties animate from a stale \"from\" value.** A value flip from\n  N→0 may render N for one frame.\n\n### 7. Write the regression test first\n\nTest-first: by the end of step 6 you understand the root cause and the\nobservable that would catch a regression. Write the test now, *before*\napplying the fix, and run it — it must fail for the right reason. A test\nwritten after the fix risks passing against both versions of the code; a\ntest that fails first proves it's gated on the broken behavior, and you\nskip the awkward \"comment out the fix, rebuild, re-run\" verification dance.\n\nTest choice depends on the bug nature:\n\n- **Programmatic state assertion** (the bug is in state propagation, not\n  pixels): Factos test in `tests/SharedUITests/`. Navigate to the repro,\n  query a helper method on the View that exposes the state under test,\n  assert. Gate by `#if <PLATFORM>_UI_TESTING` if platform-specific (most\n  XAML-platform-quirk bugs are).\n- **Pixel-perfect rendering**: snapshot test in `tests/SnapshotTests/`.\n- **Animation trajectory** (the bug is in per-frame interpolation, not the\n  final value — a bar pops to target instead of growing, a slice doesn't\n  sweep, a transition runs at the wrong speed, a refactor risks changing the\n  motion shape of an existing series): JSON animation baseline under\n  `tests/CoreTests/AnimationBaselines/` driven by\n  `tests/CoreTests/Helpers/SeriesAnimationCapture.cs`. The helper steps\n  `CoreMotionCanvas.DebugElapsedMilliseconds`, captures the visual's geometry\n  at each sample timestamp, and `AssertTrajectoryMatches` compares the\n  trajectory to a committed `.json`. First run writes the new trajectory to\n  `AnimationBaselinesNew/` and fails with a \"review and commit\" message —\n  inspect the file, then move it into `AnimationBaselines/`. Re-baseline the\n  same way: delete the JSON, re-run, move from `New/` back. On mismatch the\n  helper also drops `[EXPECTED]`/`[RESULT]` files into\n  `AnimationBaselinesDiff/` so you can diff them directly. Caller must use\n  `EasingFunctions.Lineal` + fixed `MinLimit`/`MaxLimit` so interpolation is\n  deterministic; the existing `tests/CoreTests/SeriesTests/*AnimationTests.cs`\n  files are the templates. Prefer this over a plain MSTest whenever the\n  observable is \"how the value changes between two states\" — a single\n  before/after assertion can't catch a regression that only mis-paints the\n  intermediate frames.\n- **Pure C# logic** (chart engine, motion, math): MSTest in\n  `tests/CoreTests/`.\n\nRun the test and confirm the failure message matches the symptom you saw in\nstep 5 — not, for example, a setup error or NullRef from missing test\ninfrastructure. If it fails for an unrelated reason, the test isn't yet\ncatching the bug; fix the test before moving on.\n\nTo run a single Factos UI test:\n\n```bash\n# In tests/UITests/Program.cs, set: var appToRun = \"<platform>-desktop\"\n# (avalonia-desktop / wpf-net10 / winui / maui / uno).\ndotnet build tests/UITests/UITests.csproj -c Debug\ncd tests/UITests/bin/Debug/net10.0 && dotnet UITests.dll\n# Revert the appToRun change before committing — it's a local dev-loop tweak.\n```\n\n### 8. Apply the fix\n\nSmallest possible change. Don't refactor surrounding code. Don't add\ncomments unless the WHY is non-obvious — but if the bug is a subtle\ninteraction (Avalonia behavior, theme precedence, source-gen quirk), a comment\nexplaining *why this fix is necessary* is warranted because future readers\nwon't reconstruct it from memory.\n\n### 9. Verify the fix\n\nRe-run the failing test from step 7 — it must now pass. Then re-run step 5\nwith the fix in place to capture an \"after\" screenshot at a sibling path and\ncompare visually:\n\n```bash\nLVC_SAMPLE=VisualTest/Issue<N>Repro \\\nLVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-after.png \\\n  ./samples/<Platform>Sample/.../<Platform>Sample.exe\n```\n\n`Read` both images. Don't claim the fix works without comparing. The test\npassing is necessary but not sufficient for visual bugs — pixel-equivalent\noutput can still look subtly wrong if the assertion was too narrow.\n\n### 10. Commit and PR\n\nYou developed test-first, but commit fix-first. Two commits, in this order:\n\n1. `fix(<scope>): <one-line summary> (#<N>)` — only the fix.\n2. `test(<scope>): regression for <symptom> (#<N>)` — only the test +\n   repro view. Do not stage `samples/ViewModelsSamples/Index.cs`; see step 3\n   for why.\n\nWhy fix-first commit order despite test-first development: every commit on\nthe branch should be individually green so `git bisect` lands on a usable\nstate. If the test commit landed first it would be a failing-test commit\nthat bisect would (correctly) flag as broken. Fix-then-test keeps both\ncommits green while still satisfying the project rule that reverting the\nfix must surface the regression — revert commit 1 alone and the test from\ncommit 2 fails.\n\nCommit message style follows recent history (`git log --oneline -10`).\nBody: imperative, mention the root-cause mechanism, why the test catches it.\nEnd with the standard `Co-Authored-By` line.\n\nPush and open the PR with `gh pr create`. The PR body should include:\n\n- **Summary** bullet list (what changed, what it closes)\n- **Why** section (root cause walkthrough — the most valuable part)\n- **Test plan** checklist with what you actually verified locally\n\n### 11. Update memory\n\nAfter the PR is open, write a `project_issue_<N>.md` memory and add a one-line\nentry to `MEMORY.md`. Capture: **what was non-obvious** about the bug, what\ndiagnosis steps led to the fix, and what conventions/files the next person\nneeds. Don't re-document the code — just the insights.\n\n## Anti-patterns to avoid\n\n- **Asking the user \"is the bug visible now?\" repeatedly.** Capture a\n  screenshot or read logs. If you can't decide from one capture + one\n  question, you haven't framed the question precisely enough.\n- **Simplifying the repro before confirming.** A \"minimal\" repro that doesn't\n  trigger the bug is worse than a verbose one that does.\n- **Writing the test after the fix.** Develop test-first (step 7 before\n  step 8) so the failure is real and you don't have to comment out the fix\n  to verify the test catches anything. A test authored against\n  already-fixed code can pass for the wrong reason.\n- **Mixing fix + test + cleanup in one commit.** Project policy is strict\n  here — every fix needs a separately revertible test commit.\n- **Force-pushing for \"cleanliness\".** Never. Stack new commits.\n- **Trusting memory over code.** Memory files name specific functions and\n  files; verify they still exist before recommending — projects refactor.\n\n## Tooling reference\n\n- Issue triage: `gh issue view <N> --repo Live-Charts/LiveCharts2`\n- **Auto-launch sample**: `LVC_SAMPLE=<path>` env var (Avalonia, WPF, WinUI,\n  MAUI, Uno).\n- **In-app screenshot**: `LVC_SCREENSHOT=<path>` env var (Avalonia, WPF,\n  WinUI). Sample renders to PNG after `LVC_SCREENSHOT_DELAY_MS` (default\n  3000) and exits.\n- **External screenshot fallback** — one script per OS, all take the same\n  `<ProcessName> <OutPath> [WaitSeconds]` shape:\n  - Windows: `.claude/scripts/capture-window.ps1` (also accepts\n    `-WindowTitle <substring>` instead of `-ProcessName`)\n  - macOS:   `.claude/scripts/capture-window-macos.sh`\n  - Linux:   `.claude/scripts/capture-window-linux.sh` (X11 / sway / GNOME)\n- Factos UI tests: `tests/UITests/`, set `appToRun` in `Program.cs` for\n  local runs.\n- Build per-platform: `LiveCharts.<Platform>.slnx` solutions.\n\n<!-- File: CLAUDE.md (Tokens: ~1283 | Category: claude-rule) -->\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nLiveCharts2 is a cross-platform .NET charting library with a layered architecture:\n- **`src/LiveChartsCore/`** — Platform-agnostic core (math, series, axes, animation). No UI dependencies. Targets `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp/`** — SkiaSharp rendering backend implementing the core drawing abstractions.\n- **`src/skiasharp/LiveChartsCore.SkiaSharp.{Platform}/`** — Platform-specific view controls (WPF, Avalonia, MAUI, Blazor, WinForms, WinUI, Eto, UNO).\n- **`generators/LiveChartsGenerators/`** — Roslyn source generator for boilerplate reduction.\n\n## Build Commands\n\n```bash\n# Core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Platform-specific (examples)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n\n# Target a specific framework when multi-targeting causes issues\ndotnet build -f net8.0\n```\n\nMAUI/WASM projects require workloads: `dotnet workload install maui --skip-sign-check` / `dotnet workload install wasm-tools --skip-sign-check`. Core and desktop projects (WPF, Avalonia, WinForms) do not.\n\n## Testing\n\n```bash\n# Unit tests (MSTest) — primary test suite\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Snapshot tests (image comparison, net10.0 only)\ndotnet test tests/SnapshotTests/\n\n# UI tests via Factos (requires sample apps built)\ndotnet run --project tests/UITests/\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n```\n\nTests use `CoreMotionCanvas.IsTesting = true` to disable animations. UI tests are defined in `tests/SharedUITests/` (shared project) and run against each platform via the Factos orchestrator in `tests/UITests/`.\n\n## Running Samples\n\n```bash\ndotnet run --project samples/WPFSample/WPFSample.csproj\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\nSample ViewModels live in `samples/ViewModelsSamples/` and are shared across all platform samples. Each platform sample creates its own views. `samples/ViewModelsSamples/Index.cs` lists all available sample paths.\n\n## Architecture Details\n\n**Rendering pipeline**: Data → Core series engine (measurement, layout) → SkiaSharp drawables → Platform-native surface. The core is rendering-agnostic — `samples/VorticeSample/` demonstrates using DirectX instead of SkiaSharp.\n\n**Shared projects**: `src/skiasharp/_Shared/`, `_Shared.Xaml/`, `_Shared.WinUI/` contain code shared across platform views via MSBuild linked files (configured in `build/*.Build.props`).\n\n**Code generation**: `LiveChartsGenerators` is a Roslyn analyzer/generator. Controlled by `UseNuGetForGenerator` in `Directory.Build.props` (default: `true` = NuGet package).\n\n**Key build properties** (`Directory.Build.props`):\n- `UseNuGetForSamples`: `false` during development (project references), `true` for CI/release\n- `UITesting`: set to `true` to include shared UI tests in sample projects\n- `GPU`, `VSYNC`, `Diagnose`: rendering mode overrides for testing\n\n## Code Style\n\nBased on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with these exceptions (enforced via `.editorconfig`):\n- `var` is freely used everywhere (not restricted to explicit right-hand types)\n- Single-line `if` without braces is preferred when the line is short; break long lines rather than adding braces\n- Private fields: `_camelCase`, static private: `s_camelCase`, constants: `PascalCase`\n- 4-space indentation, Allman braces, LF line endings\n\n**File naming is critical**: file names must match the class name exactly (`Hello<T>` → `Hello.cs`). Generic and non-generic with the same name go in the same file (only when related by inheritance). This is required for automatic documentation generation.\n\n## Key Constraints\n\n- **Never add platform-specific code to `LiveChartsCore`** — it must remain platform-agnostic\n- **.NET Framework 4.6.2 compatibility must be maintained** (strong-named assemblies, `LiveCharts.snk`)\n- **SkiaSharp version range**: min 2.88.9, latest 3.119.0 — changes must respect both\n- **C# 14.0** language version\n- Animation system (`Motion/`) is core infrastructure — changes require extensive testing\n- Chart updates can arrive from any thread; synchronization is essential\n\n## Additional Documentation\n\nSee `.github/copilot-instructions.md` for extended guidance including: sample platform view patterns (XAML/code-only/Blazor), adding new series types, CI/CD workflow details, and documented build errors with workarounds.\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~7727 | Category: copilot-instructions) -->\n# LiveCharts2 Copilot Instructions\n\nThis document helps coding agents work efficiently with the LiveCharts2 repository.\n\n## Repository Overview\n\nLiveCharts2 is a flexible, cross-platform charting library for .NET. It follows a layered architecture where:\n- **Core library** (`LiveChartsCore`) is platform-agnostic and handles all chart mathematics\n- **SkiaSharp backend** renders the charts using SkiaSharp\n- **Platform-specific views** provide UI controls for various frameworks (WPF, Avalonia, MAUI, Blazor, etc.)\n\n## Repository Structure\n\n```\nLiveCharts2/\n├── src/\n│   ├── LiveChartsCore/                    # Platform-agnostic core library\n│   │   ├── Kernel/                        # Core charting engine\n│   │   ├── Drawing/                       # Drawing abstractions\n│   │   ├── Motion/                        # Animation system\n│   │   ├── Measure/                       # Chart measurement logic\n│   │   └── [Series types]/                # Line, Bar, Pie, Scatter, etc.\n│   ├── skiasharp/                         # SkiaSharp rendering implementations\n│   │   ├── LiveChartsCore.SkiaSharp/      # Core SkiaSharp provider\n│   │   ├── LiveChartsCore.SkiaSharp.WPF/\n│   │   ├── LiveChartsCore.SkiaSharp.Avalonia/\n│   │   ├── LiveChartsCore.SkiaSharpView.Maui/\n│   │   ├── LiveChartsCore.SkiaSharpView.Blazor/\n│   │   └── [other platforms]/\n│   └── _Shared.Native/                    # Native platform interop\n├── samples/                               # Sample applications\n│   ├── ViewModelsSamples/                 # Shared ViewModels for all samples\n│   │   └── Index.cs                       # List of all sample paths\n│   ├── WPFSample/\n│   ├── AvaloniaSample/\n│   ├── MauiSample/\n│   ├── VorticeSample/                     # DirectX sample (core without SkiaSharp)\n│   └── [other platforms]/\n├── tests/\n│   ├── CoreTests/                         # Core unit tests using MSTest\n│   │   ├── ChartTests/                    # High-level chart tests\n│   │   ├── SeriesTests/                   # Series-specific tests\n│   │   ├── LayoutTests/                   # Layout tests\n│   │   ├── CoreObjectsTests/              # Core objects tests\n│   │   └── OtherTests/                    # Axes, events, etc.\n│   ├── SnapshotTests/                     # Snapshot/image comparison tests (net10.0)\n│   ├── UITests/                           # UI testing orchestrator\n│   │   └── Program.cs                     # Factos-based multi-platform test runner\n│   └── SharedUITests/                     # Shared UI tests (referenced by sample apps)\n│       ├── CartesianChartTests.cs\n│       ├── PieChartTests.cs\n│       ├── PolarChartTests.cs\n│       └── MapChartTests.cs\n├── docs/                                  # Documentation (Scriban templates)\n│   ├── samples/                           # Sample documentation templates\n│   ├── shared/                            # Reusable template fragments\n│   ├── cartesianChart/                    # Cartesian chart docs\n│   ├── piechart/                          # Pie chart docs\n│   └── polarchart/                        # Polar chart docs\n└── generators/                            # Code generators\n```\n\n## Key Architecture Concepts\n\n### 1. Layered Design\n- **LiveChartsCore**: Pure .NET, no UI dependencies, handles all calculations\n- **SkiaSharp Provider**: Implements `IDrawingProvider` to render using SkiaSharp\n- **Platform Views**: WPF/Avalonia/MAUI/etc. specific controls that host the renderer\n\n### 2. Multi-Platform Targeting\n\nCore projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) target:\n- `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows`\n- **No mobile workloads required** to build the core library\n\n**Platform-specific view projects** (WPF, Avalonia, MAUI, etc.) have their own target framework requirements based on the platform.\n\n### 3. Sample Structure\n- **ViewModelsSamples**: Contains shared ViewModels used across all UI frameworks\n- **Index.cs**: Defines available samples as string paths (e.g., \"Lines/Basic\", \"Pies/Doughnut\")\n- Each platform sample project (WPF, Avalonia, etc.) references ViewModelsSamples and creates platform-specific views\n\n### 4. VorticeSample\nA special sample demonstrating how to use LiveChartsCore without SkiaSharp, using DirectX instead. This shows the core library is truly rendering-agnostic.\n\n## Building the Repository\n\n### Prerequisites\n- .NET SDK (see `global.json` for minimum version)\n- No workloads required for core projects\n- Platform-specific projects (MAUI, UNO, Avalonia Browser) require relevant workloads:\n  ```bash\n  dotnet workload install maui\n  dotnet workload install wasm-tools\n  ```\n\n### Build Methods\n\n#### Quick Build - Core Projects\n```bash\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n```\n\n#### Quick Build - Platform Views\n```bash\n# Build specific platform views (recommended for development)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n```\n\n#### Full Build (Windows)\n```bash\n# Build platform-specific projects individually\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WinForms/LiveChartsCore.SkiaSharpView.WinForms.csproj\n# Or use platform-specific solution files (see below)\n```\n\n#### Build with Solution Files\n```bash\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\ndotnet build LiveCharts.Avalonia.slnx\ndotnet build LiveCharts.Maui.slnx\n```\n\n### Common Build Issues and Workarounds\n\n#### Issue: Missing workload errors (NETSDK1147)\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\n```\n\n**Context**: This error occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require workloads.\n\n**Workaround Options:**\n1. Install the required workload: `dotnet workload install maui`\n2. Build only the platform you need (e.g., WPF or Avalonia desktop on Windows)\n3. Use platform-specific solution files that don't include all targets\n\n#### Issue: SkiaSharp version conflicts\nThe project supports multiple SkiaSharp versions:\n- `MinSkiaSharpVersion`: 2.88.9 (minimum supported)\n- `LatestSkiaSharpVersion`: 3.119.0 (default for GPU support)\n\nDefined in `Directory.Build.props`.\n\n#### Issue: Multi-targeting complexity\nWhen building fails for specific targets, you can:\n1. Use `-f` to target specific framework: `dotnet build -f net8.0`\n2. Edit `TargetFrameworks` in .csproj to focus on needed platforms\n\n## Testing\n\n### Unit Tests (Core Library)\n\n**Location**: `tests/CoreTests/`\n\n**Framework**: MSTest with coverlet for code coverage\n\n**Run Tests:**\n```bash\ndotnet test tests/CoreTests/\n\n# Run for specific framework\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run with coverage\ndotnet test tests/CoreTests/ --collect:\"XPlat Code Coverage\"\n```\n\n**Test Structure:**\n- `ChartTests/`: High-level chart functionality\n- `SeriesTests/`: Tests for Line, Bar, Pie, Scatter, Heat, etc.\n- `LayoutTests/`: Stack and table layouts\n- `CoreObjectsTests/`: Transitions, colors, labels\n- `OtherTests/`: Axes, events, data providers, visual elements\n- `MockedObjects/`: Test helpers and mocks\n- `TestsInitializer.cs`: MSTest assembly initialization\n\n**Important**: Tests use `CoreMotionCanvas.IsTesting = true` to disable animations during testing.\n\n### Snapshot Tests\n\n**Location**: `tests/SnapshotTests/`\n\n**Framework**: MSTest, targets `net10.0`\n\nSnapshot tests render charts to images and compare them against stored reference snapshots. They are run in CI on Windows.\n\n**Run Tests:**\n```bash\ndotnet test tests/SnapshotTests/\n```\n\n### UI Testing\n\n**Location**: `tests/UITests/` (orchestrator) and `tests/SharedUITests/` (shared tests)\n\n**Framework**: [Factos](https://github.com/beto-rodriguez/Factos) - A multi-platform UI testing framework\n\n**How it works:**\n1. Shared UI tests are defined in `tests/SharedUITests/` (shared project)\n2. Each sample application references `SharedUITests` \n3. The `tests/UITests/Program.cs` orchestrator:\n   - Starts various sample applications (Avalonia, WPF, MAUI, Blazor, etc.)\n   - Connects to them via Factos\n   - Runs the shared UI tests against each platform\n4. Tests ensure charts render correctly across all supported UI frameworks\n\n**Test Coverage:**\n- `CartesianChartTests.cs`: Cartesian chart rendering and behavior\n- `PieChartTests.cs`: Pie/Doughnut chart tests\n- `PolarChartTests.cs`: Polar chart tests  \n- `MapChartTests.cs`: Map chart tests\n- `AvaloniaTests.cs`: Avalonia-specific tests\n\n**Running UI Tests:**\n```bash\n# Run UI tests (requires sample apps to be built)\ndotnet run --project tests/UITests/\n\n# Run against specific platform (see Program.cs for options)\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\ndotnet run --project tests/UITests/ -- --select maui --test-env \"tf=net10.0-windows10.0.19041.0\"\n```\n\n**Important Notes:**\n- UI testing requires the Factos package\n- Each platform may need specific prerequisites (emulators for mobile, browsers for web)\n- In Debug mode, tests use project references; in Release mode, they use NuGet packages\n- The orchestrator supports testing against multiple target frameworks\n- Mobile platforms (Android, iOS) require running emulators\n\n**Build Configuration for UI Tests:**\nUI test configuration is managed through MSBuild properties. When `UITesting=true` is set, samples include the shared UI test project.\n\n## Running Samples\n\n### Sample Applications\nEach platform has its own sample application that references `ViewModelsSamples`:\n\n```bash\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n```\n\n### Adding New Samples\n1. Add ViewModel class in `samples/ViewModelsSamples/[Category]/[Name].cs`\n2. Add path to `samples/ViewModelsSamples/Index.cs`\n3. Create platform-specific view files in each sample project (WPF, Avalonia, etc.)\n\n### Sample Platforms Reference\n\nThe following platforms each need a view for every sample. **ConsoleSample** and **VorticeSample** are excluded — they don't follow this pattern.\n\n| Platform | Root path | View file(s) | Base class | LVC namespace (xmlns:lvc) |\n|---|---|---|---|---|\n| **Avalonia** | `samples/AvaloniaSample/[Category]/[Name]/` | `View.axaml` + `View.axaml.cs` | `UserControl` | `using:LiveChartsCore.SkiaSharpView.Avalonia` |\n| **WPF** | `samples/WPFSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` | `clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF` |\n| **MAUI** | `samples/MauiSample/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `ContentPage` | `clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui` |\n| **WinUI** | `samples/WinUISample/WinUISample/Samples/[Category]/[Name]/` | `View.xaml` + `View.xaml.cs` | `UserControl` (`sealed partial`) | `using:LiveChartsCore.SkiaSharpView.WinUI` |\n| **WinForms** | `samples/WinFormsSample/[Category]/[Name]/` | `View.cs` + `View.Designer.cs` + `View.resx` | `UserControl` (`partial`) | N/A — code-only |\n| **Blazor** | `samples/BlazorSample/Pages/[Category]/[Name]/` | `View.razor` | N/A — Razor component | `@using LiveChartsCore.SkiaSharpView.Blazor` |\n| **EtoForms** | `samples/EtoFormsSample/[Category]/[Name]/` | `View.cs` | `Panel` (non-partial) | N/A — code-only |\n| **UnoPlatform** | *(no separate files)* | Reuses `WinUISample` views via reflection | — | — |\n\n**Key facts for each platform:**\n\n- **All XAML platforms (Avalonia, WPF, MAUI, WinUI)** use `Activator.CreateInstance` with the pattern `{Platform}.{Category}.{Name}.View` to load views — so the **C# namespace must exactly match** `{PlatformPrefix}.{Category}.{Name}` and the class must be named `View`.\n- **WinForms** and **EtoForms** use the same reflection pattern. The view class must be `partial class View : UserControl` (WinForms) or `class View : Panel` (EtoForms).\n- **Blazor** uses Razor's `@page \"/{Category}/{Name}\"` directive for routing. The nav menu reads `ViewModelsSamples.Index.Samples` automatically.\n- **UnoPlatform** (`samples/UnoPlatformSample/`) loads views from the `WinUISample` assembly — no separate files are needed.\n\n**XAML DataContext / BindingContext patterns:**\n\n```xml\n<!-- Avalonia (View.axaml) -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.Avalonia\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\"\n             x:DataType=\"vms:ViewModel\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- WPF (View.xaml) -->\n<UserControl xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n\n<!-- MAUI (View.xaml) — ContentPage + XamlCompilation attribute on code-behind -->\n<ContentPage xmlns:lvc=\"clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui\"\n             xmlns:vms=\"clr-namespace:ViewModelsSamples.[Category].[Name];assembly=ViewModelsSamples\"\n             x:DataType=\"vms:ViewModel\">\n    <ContentPage.BindingContext><vms:ViewModel/></ContentPage.BindingContext>\n</ContentPage>\n\n<!-- WinUI (View.xaml) — sealed partial class -->\n<UserControl xmlns:lvc=\"using:LiveChartsCore.SkiaSharpView.WinUI\"\n             xmlns:vms=\"using:ViewModelsSamples.[Category].[Name]\">\n    <UserControl.DataContext><vms:ViewModel/></UserControl.DataContext>\n</UserControl>\n```\n\n**Code-only platforms (WinForms / EtoForms)** typically instantiate the ViewModel directly or inline the data:\n\n```csharp\n// WinForms — partial class View : UserControl\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nchart.Location = new System.Drawing.Point(0, 0);\nchart.Size = new System.Drawing.Size(50, 50);\nchart.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;\nControls.Add(chart);\n\n// EtoForms — class View : Panel (non-partial, no Designer file)\nvar vm = new ViewModel();\nvar chart = new GeoMap { Series = vm.Series, ... };\nContent = new DynamicLayout(chart);\n```\n\n**WinForms `View.Designer.cs`** is always a minimal boilerplate — copy from any existing sample, just update the namespace.\n\n**UI-testing accessor** — most XAML views expose a `Chart` property under `#if UI_TESTING` for the Factos test runner:\n\n```csharp\n// XAML platforms (WPF, Avalonia, MAUI, WinUI)\n#if UI_TESTING\n    public SomeChartType Chart => chartNamedInXaml;\n#endif\n\n// EtoForms / WinForms\npublic SomeChartType Chart;  // public field, always present\n```\n\n**Blazor** exposes the chart via `@ref`:\n```razor\n<CartesianChart @ref=\"Chart\" .../>\n@code { public CartesianChart Chart; }\n```\n\n## Code Style and Conventions\n\n### Editor Config\nThe repository uses `.editorconfig` based on [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md) with exceptions.\n\n**Key Style Rules:**\n- **Indentation**: 4 spaces\n- **Line endings**: LF, insert final newline\n- **Braces**: New line before open brace (Allman style)\n- **var usage**: Use `var` freely (explicitly allowed)\n- **Single-line if**: Allowed and preferred when line is short\n- **Naming**:\n  - Private/internal fields: `_camelCase`\n  - Static private fields: `s_camelCase`\n  - Constants: `PascalCase`\n- **Using directives**: Outside namespace\n\n### File Naming\n**Critical for auto-generated documentation:**\n- File names MUST match the class name exactly\n- `public class Hello` → `Hello.cs`\n- `public class Hello<T>` → `Hello.cs` (ignore generics)\n- Generic and non-generic with same name → same file (only if inheritance relationship)\n\n### Important Constants\nDefined in `Directory.Build.props`:\n- `LiveChartsVersion`: Current version (2.0.0-rc6.1)\n- `MinSkiaSharpVersion`: 2.88.9\n- `LatestSkiaSharpVersion`: 3.119.0\n- `LangVersion`: 14.0 (C# 14)\n\n## Build Configuration Properties\n\n### Rendering Settings\nRendering settings are configured via MSBuild properties:\n- `GPU`: Enable/disable GPU acceleration\n- `VSYNC`: Enable/disable vertical sync\n- `FPS`: Frame rate (10, 20, 30, 45, 60, 75, 90, 120)\n- `Diagnose`: Enable diagnostic mode\n\nThese create conditional compilation symbols for testing different rendering modes.\n\n### Development Flags\nIn `Directory.Build.props`:\n- `UseNuGetForSamples`: Use NuGet packages vs project references (default: false)\n- `UseNuGetForGenerator`: Use NuGet generator package (default: true)\n\n## CI/CD\n\n### GitHub Actions Workflows\n\n#### 1. Main CI (`livecharts.yml`)\n- Triggers: Pull requests\n- Runs on: `windows-2025` (pack/test), `ubuntu-24.04` (Linux/browser), `macos-26` (Mac/iOS)\n- Steps:\n  1. **Pack**: Builds NuGet packages for all platform libraries (core, skiasharp, WPF, Avalonia, MAUI, Blazor, WinUI, UNO, WinForms, Eto)\n  2. **test-core**: Runs `CoreTests` on `net8.0` and `net462`\n  3. **test-snapshot**: Runs `SnapshotTests`\n  4. **test-windows/linux/mac/browser/android/ios**: Runs Factos UI tests for each platform\n- On tag pushes (after tests pass): publishes packages to NuGet.org\n\n#### 2. Publish (`publish.yml`)\n- Handles NuGet package publishing\n\n**Note**: The CI uses NuGet packages (not project references) when running UI tests in Release mode.\n\n## Common Development Workflows\n\n### Adding a New Series Type\n1. Create series class in `src/LiveChartsCore/[SeriesType]/`\n2. Implement series interfaces (`ISeries`, etc.)\n3. Create SkiaSharp drawable in `src/skiasharp/LiveChartsCore.SkiaSharp/Drawing/Geometries/`\n4. Add tests in `tests/CoreTests/SeriesTests/`\n5. Create sample ViewModel in `samples/ViewModelsSamples/`\n6. Update `samples/ViewModelsSamples/Index.cs`\n\n### Adding Platform Support\n1. Create new project in `src/skiasharp/LiveChartsCore.SkiaSharpView.[Platform]/`\n2. Reference `LiveChartsCore.SkiaSharp` project\n3. Create platform-specific control classes\n4. Add shared code to `_Shared/` if applicable\n5. Create sample application in `samples/[Platform]Sample/`\n6. Add platform-specific solution file\n\n### Updating Documentation\n\n**Important**: Documentation files in the `docs/` folder are **Scriban templates**, not final markdown files.\n\n**How it works:**\n1. Template files are compiled by an external (non-open-source) repository\n2. Templates use [Scriban](https://github.com/scriban/scriban) - a fast, powerful, and lightweight text templating language\n3. Scriban supports custom functions and expressions embedded in the markdown\n\n**Common Scriban expressions you'll find:**\n\n**File inclusion** - Renders content from source files:\n```\n{{~ render \"~/../samples/ViewModelsSamples/Events/Cartesian/ViewModel.cs\" ~}}\n{{~ render \"~/../samples/MauiSample/MauiProgram.cs\" ~}}\n{{~ render \"~/../samples/{samples_folder}/Events/Cartesian{view_extension}\" ~}}\n```\n\n**Conditionals** - Platform-specific content:\n```\n{{~ if xaml ~}}\n  Content for XAML platforms (WPF, Avalonia, UNO, WinUI, MAUI)\n{{~ end ~}}\n\n{{~ if winforms ~}}\n  Content specific to WinForms\n{{~ end ~}}\n```\n\n**Variables** - Dynamic content:\n```\n{{ website_url }}/docs/{{ platform }}/{{ version }}/About\n{{ assets_url }}/docs/{{ unique_name }}/result.gif\n{{ name | to_title_case }}\n{{ edit_source | replace_local_to_server }}\n```\n\n**Loops** - Iterate over collections:\n```\n{{~ for r in related_to ~}}\n  <a href=\"{{ compile this r.url }}\">{{ r.name }}</a>\n{{~ end ~}}\n```\n\n**Template structure:**\n- `docs/samples/[category]/[name]/template.md` - Sample documentation templates\n- `docs/shared/*.md` - Reusable template fragments included via `{{ render \"~/shared/...\" }}`\n- `docs/piechart/`, `docs/cartesianChart/`, etc. - Feature documentation with templates\n\n**When editing docs:**\n- Always edit the `.md` files as Scriban templates\n- Test template syntax (though final compilation happens externally)\n- Use `{{~ ~}}` syntax to strip whitespace around expressions\n- File paths in `render` are relative to the template location (use `~/../` for repo root)\n\n## Important Notes for Coding Agents\n\n### Do's\n- ✅ Use project references during development (not NuGet packages)\n- ✅ Follow the exact file naming convention (critical for docs)\n- ✅ Run tests after changes to core or series logic\n- ✅ Use platform-specific solution files for focused development\n- ✅ Consult `CONTRIBUTING.md` for detailed style guide\n- ✅ Use shared code in `_Shared/` folders when adding cross-platform features\n\n### Don'ts\n- ❌ Don't break multi-platform support when modifying core projects\n- ❌ Don't add platform-specific code to `LiveChartsCore` (keep it agnostic)\n- ❌ Don't ignore `.editorconfig` warnings\n- ❌ Don't remove or modify working tests without good reason\n- ❌ Don't add new dependencies without checking compatibility across all target frameworks\n\n### Special Considerations\n- The library supports .NET Framework 4.6.2 - maintain compatibility\n- SkiaSharp is abstracted - core library should work with other rendering engines\n- Animation system (`Motion/`) is critical - changes require extensive testing\n- Multi-threading: Chart updates can come from any thread; proper synchronization is essential\n\n## Quick Reference Commands\n\n```bash\n# === Building ===\n# Build core library (no workloads needed)\ndotnet build src/LiveChartsCore/LiveChartsCore.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp/LiveChartsCore.SkiaSharpView.csproj\n\n# Build platform-specific projects\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# === Install Workloads (for platform-specific projects) ===\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n\n# Check installed workloads\ndotnet workload list\n\n# === Testing ===\n# Run core unit tests\ndotnet test tests/CoreTests/ --framework net8.0\n\n# Run snapshot tests\ndotnet test tests/SnapshotTests/\n\n# Run UI tests (requires sample apps to build)\ndotnet run --project tests/UITests/\n\n# Run UI tests for specific platform\ndotnet run --project tests/UITests/ -- --select wpf\ndotnet run --project tests/UITests/ -- --select avalonia-desktop\n\n# === Running Samples ===\n# Run WPF sample\ndotnet run --project samples/WPFSample/WPFSample.csproj\n\n# Run Avalonia sample\ndotnet run --project samples/AvaloniaSample/AvaloniaSample.csproj\n\n# Run Console sample (no UI)\ndotnet run --project samples/ConsoleSample/ConsoleSample.csproj\n\n# === Troubleshooting ===\n# Clean build artifacts\ndotnet clean\nfind . -type d -name \"bin\" -o -name \"obj\" | xargs rm -rf\n\n# Restore packages\ndotnet restore\n\n# Check for workload issues\ndotnet workload restore --skip-sign-check\n```\n\n## Documented Errors and Workarounds\n\nThis section documents actual errors encountered when working with this repository and their solutions.\n\n### Error 1: NETSDK1147 - Missing Workloads\n\n**Error Message:**\n```\nerror NETSDK1147: To build this project, the following workloads must be installed: maui\nTo install these workloads, run the following command: dotnet workload restore\n```\n\n**Context**: This occurs when building platform-specific view projects (MAUI, UNO, Avalonia Browser) that require specific workloads. Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) do NOT require any workloads.\n\n**Workarounds:**\n\n**Option 1: Install Required Workloads**\n```bash\ndotnet workload install maui --skip-sign-check\ndotnet workload install wasm-tools --skip-sign-check\n```\n\n**Option 2: Build Platform-Specific Projects that don't need workloads**\n```bash\n# Build only WPF (Windows only)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.WPF/LiveChartsCore.SkiaSharpView.Wpf.csproj\n\n# Build only Avalonia desktop (cross-platform)\ndotnet build src/skiasharp/LiveChartsCore.SkiaSharp.Avalonia/LiveChartsCore.SkiaSharpView.Avalonia.csproj\n\n# Use platform-specific solution files\ndotnet build LiveCharts.WPF.slnx\n```\n\n### Error 2: Visual Studio Component Required\n\n**Error Message:**\n```\nUnhandled exception: The imported file \"$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v$(VisualStudioVersion)/CodeSharing/Microsoft.CodeSharing.Common.Default.props\" does not exist and appears to be part of a Visual Studio component.\n```\n\n**Context**: Appears when running `dotnet workload restore` on non-Windows systems or when Visual Studio is not installed.\n\n**Why it happens**: The `src/skiasharp/_Shared.WinUI/_Shared.WinUI.shproj` shared project requires Visual Studio components that are Windows-specific.\n\n**Workaround**: This error can be ignored if you're not building WinUI projects. The workload installation succeeds despite this error. If you need to build WinUI:\n- Use Windows with Visual Studio 2022 installed\n- Use `msbuild` instead of `dotnet build` for WinUI projects\n\n### Error 3: Ambiguous Argument with Git\n\n**Error Message:**\n```\nfatal: ambiguous argument 'origin/branch-name': unknown revision or path not in the working tree.\n```\n\n**Context**: After fetching a branch with `git fetch origin branch-name`, trying to reference it as `origin/branch-name`.\n\n**Why it happens**: Git fetch stores the ref as `FETCH_HEAD`, not as a trackable remote branch.\n\n**Solution**: Use `FETCH_HEAD` or create a local tracking branch:\n```bash\n# Option 1: Use FETCH_HEAD directly\ngit log FETCH_HEAD\n\n# Option 2: Create tracking branch\ngit fetch origin main\ngit checkout -b main --track origin/main\n\n# Option 3: Fetch with branch creation\ngit fetch origin main:main\n```\n\n### Error 4: Package Not Found During Build\n\n**Context**: Sample applications may fail to build if NuGet packages are not found.\n\n**Why it happens**: `UseNuGetForSamples` flag in `Directory.Build.props` controls whether samples use project references or NuGet packages.\n\n**Solution**: Ensure you're using project references during development:\n```xml\n<!-- In Directory.Build.props -->\n<UseNuGetForSamples>false</UseNuGetForSamples>\n```\n\nOr restore NuGet packages if building from packages:\n```bash\ndotnet restore\n```\n\n### Error 5: Strong Name Assembly Conflicts\n\n**Context**: When building for .NET Framework 4.6.2, you may encounter assembly version conflicts.\n\n**Why it happens**: .NET Framework uses strong-named assemblies, and SkiaSharp has different versioning.\n\n**Referenced Issue**: https://github.com/mono/SkiaSharp/issues/3153\n\n**Solution**: The project is configured to handle this, but if you encounter issues:\n1. Clean the solution: `dotnet clean`\n2. Delete `bin` and `obj` folders\n3. Restore and rebuild: `dotnet restore && dotnet build`\n\n### Error 6: Test Build Failures on CI\n\n**Context**: UI tests may fail with target framework mismatches in CI.\n\n**Solution**: The UI test infrastructure uses special MSBuild properties:\n- `TestBuildTargetFramework`: Override target framework for test builds\n- `IsTestBuild`: Flag to indicate test build\n- `UITesting`: Flag to include shared UI tests\n\nExample from `tests/UITests/Program.cs`:\n```csharp\nMSBuildArg tf_n10w = new(\"TestBuildTargetFramework\", \"net10.0-windows\");\nMSBuildArg isTest = new(\"IsTestBuild\", \"true\");\n```\n\n## Troubleshooting\n\n### Problem: Can't build platform-specific projects - workload errors\n**Solution**: Install the required workload for the platform you're targeting (e.g., `dotnet workload install maui`). Core projects (`LiveChartsCore`, `LiveChartsCore.SkiaSharp`) build without any workloads.\n\n### Problem: SkiaSharp errors\n**Solution**: Check SkiaSharp version in `Directory.Build.props`, ensure NuGet restore succeeded\n\n### Problem: Tests fail with animation issues\n**Solution**: Verify `CoreMotionCanvas.IsTesting = true` in test initialization\n\n### Problem: Sample won't run\n**Solution**: Ensure platform-specific dependencies are installed (e.g., .NET Desktop Runtime for WPF)\n\n### Problem: Generator errors\n**Solution**: Check `UseNuGetForGenerator` setting and ensure LiveChartsGenerators package/project is available\n\n## Issue Reproduction & Fix Workflow\n\nWhen picking up a GitHub issue (reproduce → diagnose → fix → regression test → PR),\nfollow the canonical workflow at [`.claude/skills/repro-and-fix/SKILL.md`](../.claude/skills/repro-and-fix/SKILL.md).\nThat doc is the single source of truth for both Claude Code and Copilot Coding Agent —\nkeep edits there, not duplicated here.\n\nQuick reference for the dev-loop hooks the workflow relies on:\n\n- **`LVC_SAMPLE=<sample-path>`** — XAML samples (Avalonia / WPF / WinUI / MAUI / Uno) auto-navigate to the named sample on launch, e.g. `LVC_SAMPLE=VisualTest/Issue1986Repro`. Skips manual UI navigation for repros.\n- **`LVC_SCREENSHOT=<png-path>`** — Avalonia / WPF / WinUI samples render the main window to PNG via `RenderTargetBitmap` shortly after activation and exit. Captures scale to physical pixels on HiDPI.\n- **`LVC_SCREENSHOT_DELAY_MS=<ms>`** — overrides the 3 s default settle delay before the in-app screenshot is taken (use on slower CI hosts).\n- **`.claude/scripts/capture-window.{ps1,-macos.sh,-linux.sh}`** — per-OS PrintWindow / `screencapture` / `grim` fallbacks for platforms without an in-app capture path (MAUI, Uno).\n\nRepro views live under `samples/AvaloniaSample/VisualTest/Issue<N>Repro/` (or\nthe equivalent under whichever platform sample fits the bug). Their code-behind\nexposes helpers (e.g. `FindTemplatedGaugeSeries()`) that Factos UI tests call\ndirectly. Factos and `LVC_SAMPLE` navigate by path and don't need the repro\nregistered in `samples/ViewModelsSamples/Index.cs` — **do not commit changes\nto that file for a repro view.** It's shared across every platform sample,\nso a single-platform repro entry will crash the load on the other platforms.\n\n## Resources\n\n- **Main Documentation**: https://livecharts.dev\n- **Contributing Guide**: `CONTRIBUTING.md`\n- **Repository**: https://github.com/Live-Charts/LiveCharts2\n- **Code of Conduct**: `CODE_OF_CONDUCT.md`\n- **License**: MIT (see `LICENSE`)\n\n## Version Information\n\n- **Current Version**: 2.0.0-rc6.1 (Release Candidate)\n- **C# Language Version**: 14.0\n- **SkiaSharp**: 2.88.9 (min) to 3.119.0 (latest)\n- **Target Frameworks**: `net462`, `netstandard2.0`, `net8.0`, `net8.0-windows` (core); plus platform-specific targets for view projects\n</yakaai_skills>"}