Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4ddef74
Initial plan
Copilot Feb 26, 2026
2dd0031
Extract SKSkottiePlayer for cross-platform sharing between MAUI and B…
Copilot Feb 26, 2026
a963a8b
Rename SKSkottiePlayer→SKLottiePlayer, move shared Lottie types to co…
Copilot Feb 26, 2026
9d3c657
Replace global using aliases with [assembly: TypeForwardedTo] for mov…
Copilot Feb 26, 2026
7f2fc91
Keep SKLottieAnimation and SKLottieAnimationFailedEventArgs in MAUI, …
Copilot Feb 26, 2026
5143cca
Replace SKLottieRepeatMode enum with SKLottieRepeat readonly struct; …
Copilot Feb 26, 2026
184c54d
Redesign SKLottieView/Player sync: event-driven, remove isSyncingFrom…
Copilot Feb 26, 2026
739836d
Make SKLottiePlayer.Progress getter-only; add public Seek(TimeSpan) m…
Copilot Feb 26, 2026
a16bf72
Remove isResetting guard field; fix AnimationCompleted transition; ad…
Copilot Feb 26, 2026
8f56013
Simplify Progress: auto-property with private set, no backing field
Copilot Feb 26, 2026
cf45b35
feat: XML docs, core playback tests, Blazor animated canvas, slim MAU…
Copilot Mar 1, 2026
778be5b
Fix Blazor Lottie loading: use Animation.Parse(json) to avoid WASM st…
Copilot Mar 2, 2026
1b9eaba
fix: resolve SKLottiePlayer and Blazor animation lifecycle issues
mattleibow Mar 2, 2026
1c2cec4
fix: dispose loadedAnimation native resource in Blazor Lottie sample
mattleibow Mar 2, 2026
ad7ee4f
fix: address 6 review findings in SKLottiePlayer and Blazor controls
mattleibow Mar 3, 2026
941590d
fix: reset isInForwardPhase when Repeat mode changes
mattleibow Mar 3, 2026
1b5883a
feat: add SKLottieView Blazor component and .razor.css isolation
mattleibow Mar 3, 2026
5f67979
fix: preserve playback direction when changing Reverse repeat count
mattleibow Mar 3, 2026
4d0c062
fix: WASM canvas rendering and direction flip on repeat switch
mattleibow Mar 3, 2026
68ed421
docs: add Lottie Player, Blazor Lottie, and rework MAUI Lottie docs
mattleibow Mar 3, 2026
7d78bf6
docs: rename lottie docs to lottie-maui and lottie-blazor
mattleibow Mar 3, 2026
fb814ed
docs: group controls under Controls section in sidebar
mattleibow Mar 3, 2026
ea622f3
samples: add Controls group to Blazor sample nav and homepage
mattleibow Mar 3, 2026
d596481
docs: fix broken links and Razor code highlighting
mattleibow Mar 3, 2026
a47c61d
fix: add detach:true requirement to pr-monitor skill
mattleibow Mar 3, 2026
6a07238
Fix Blazor SKLottieView: add load cancellation and safe disposal
mattleibow Mar 3, 2026
ad63082
Update pr-monitor skill from gist: add poll_loop.sh, agent architecture
mattleibow Mar 3, 2026
83ac834
Update pr-monitor skill: remove poll_loop.sh, use cheap background agent
mattleibow Mar 3, 2026
b811abc
Fix API consistency, disposal safety, event ordering, and doc link
mattleibow Mar 3, 2026
2caa4d5
Better skill
mattleibow Mar 4, 2026
6c7ba12
Address PR review: fix nav duplicate CONTROLS, CSS brace, add core pr…
Copilot Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions docs/docs/lottie-blazor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
# Blazor Lottie Animations

Play Lottie animations in Blazor WebAssembly apps with [`SKLottieView`](xref:SkiaSharp.Extended.UI.Blazor.Controls.SKLottieView). This component wraps the shared [`SKLottiePlayer`](lottie-player.md) engine with a Blazor-friendly API — just point it at a JSON URL and it handles loading, frame updates, and rendering.

For building custom animated canvases beyond Lottie, see [`SKAnimatedCanvasView`](#custom-animations-with-skanimatedcanvasview) below.

## Quick Start

### 1. Add the NuGet package

```bash
dotnet add package SkiaSharp.Extended.UI.Blazor
```

### 2. Add the namespace

In your `_Imports.razor`:

```cshtml-razor
@using SkiaSharp.Extended.UI.Blazor.Controls
```

### 3. Add the component

```cshtml-razor
<SKLottieView Source="animations/trophy.json"
RepeatCount="-1"
style="width: 300px; height: 300px;" />
```

That's it — the animation loads from the URL and starts playing automatically.

## Playback Controls

### Repeat modes

```cshtml-razor
@* Loop forever, restarting each time *@
<SKLottieView Source="animation.json"
RepeatMode="SKLottieRepeatMode.Restart"
RepeatCount="-1" />

@* Ping-pong 3 times *@
<SKLottieView Source="animation.json"
RepeatMode="SKLottieRepeatMode.Reverse"
RepeatCount="3" />

@* Play once *@
<SKLottieView Source="animation.json"
RepeatCount="0" />
```

### Speed and direction

```cshtml-razor
<SKLottieView Source="animation.json"
AnimationSpeed="2.0"
RepeatCount="-1" />

@* Negative speed plays in reverse *@
<SKLottieView Source="animation.json"
AnimationSpeed="-1.0"
RepeatCount="-1" />
```

### Pause and resume

```cshtml-razor
<SKLottieView Source="animation.json"
IsAnimationEnabled="@isPlaying"
RepeatCount="-1" />

<button @onclick="() => isPlaying = !isPlaying">
@(isPlaying ? "Pause" : "Play")
</button>

@code {
private bool isPlaying = true;
}
```

### Restart programmatically

Use an `@ref` to call `Restart()`:

```cshtml-razor
<SKLottieView @ref="lottieView"
Source="animation.json"
RepeatCount="-1" />

<button @onclick="() => lottieView?.Restart()">Restart</button>

@code {
private SKLottieView? lottieView;
}
```

## Reading Playback State

Access read-only state through the component reference:

```cshtml-razor
<SKLottieView @ref="lottieView"
Source="animation.json"
RepeatCount="-1"
AnimationUpdated="StateHasChanged" />

@if (lottieView?.HasAnimation == true)
{
<p>
Duration: @lottieView.Duration.TotalSeconds.ToString("0.00")s |
Progress: @lottieView.Progress.TotalSeconds.ToString("0.00")s |
@(lottieView.IsComplete ? "Complete ✓" : "Playing")
</p>
}

@code {
private SKLottieView? lottieView;
}
```

> **Tip:** Bind `AnimationUpdated` to `StateHasChanged` so the UI refreshes with each frame. Without this, the displayed progress won't update live.

## Events

| Event | Type | Description |
| :---- | :--- | :---------- |
| `AnimationLoaded` | `EventCallback` | The animation JSON was loaded and parsed successfully |
| `AnimationCompleted` | `EventCallback` | All repeats finished (never fires for infinite loops) |
| `AnimationFailed` | `EventCallback<Exception?>` | Loading or parsing failed |
| `AnimationUpdated` | `EventCallback` | Fires after each frame update |

```cshtml-razor
<SKLottieView Source="animation.json"
AnimationLoaded="OnLoaded"
AnimationFailed="OnFailed"
AnimationCompleted="OnCompleted" />

@code {
private void OnLoaded() => Console.WriteLine("Loaded!");
private void OnFailed(Exception? ex) => Console.WriteLine($"Failed: {ex?.Message}");
private void OnCompleted() => Console.WriteLine("Done!");
}
```

## Parameters Reference

| Parameter | Type | Default | Description |
| :-------- | :--- | :------ | :---------- |
| `Source` | `string?` | `null` | URL of the Lottie JSON file to load |
| `RepeatMode` | `SKLottieRepeatMode` | `Restart` | `Restart` or `Reverse` (ping-pong) |
| `RepeatCount` | `int` | `-1` | Additional plays after the first (`0` = once, `-1` = infinite) |
| `AnimationSpeed` | `double` | `1.0` | Speed multiplier (negative = reverse) |
| `IsAnimationEnabled` | `bool` | `true` | Play/pause the animation loop |

Additional HTML attributes (like `style` and `class`) are forwarded to the underlying canvas element.

## Read-Only State (via `@ref`)

| Property | Type | Description |
| :------- | :--- | :---------- |
| `IsLoading` | `bool` | Whether the animation is currently being fetched |
| `HasAnimation` | `bool` | Whether an animation is loaded and ready |
| `Duration` | `TimeSpan` | Total animation duration |
| `Progress` | `TimeSpan` | Current playback position |
| `IsComplete` | `bool` | Whether all repeats have finished |

## Sizing

The component renders an HTML `<canvas>` element. Set the size using standard CSS:

```cshtml-razor
@* Fixed size *@
<SKLottieView Source="animation.json" style="width: 300px; height: 300px;" />

@* Fill parent container *@
<div style="width: 100%; height: 400px;">
<SKLottieView Source="animation.json" style="width: 100%; height: 100%;" />
</div>
```

## Custom Animations with SKAnimatedCanvasView

For animations beyond Lottie, [`SKAnimatedCanvasView`](xref:SkiaSharp.Extended.UI.Blazor.Controls.SKAnimatedCanvasView) provides a frame loop with a SkiaSharp canvas. It runs at ~60 fps and calls your update and paint callbacks each frame.

```cshtml-razor
@using SkiaSharp
@using SkiaSharp.Extended.UI.Blazor.Controls

<SKAnimatedCanvasView OnUpdate="HandleUpdate"
OnPaintSurface="HandlePaint"
style="width: 400px; height: 400px;" />

@code {
private float angle = 0;

private void HandleUpdate(TimeSpan delta)
{
angle += (float)(delta.TotalSeconds * 90); // 90° per second
}

private void HandlePaint(SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
canvas.RotateDegrees(angle, e.Info.Width / 2f, e.Info.Height / 2f);

using var paint = new SKPaint { Color = SKColors.CornflowerBlue };
canvas.DrawRect(
e.Info.Width / 2f - 50, e.Info.Height / 2f - 50,
100, 100, paint);
}
}
```

### SKAnimatedCanvasView Parameters

| Parameter | Type | Default | Description |
| :-------- | :--- | :------ | :---------- |
| `IsAnimationEnabled` | `bool` | `true` | Start/stop the frame loop |
| `OnUpdate` | `EventCallback<TimeSpan>` | — | Called each frame with delta time |
| `OnPaintSurface` | `EventCallback<SKPaintSurfaceEventArgs>` | — | Called to render each frame |

> **Important:** `OnPaintSurface` handlers must be synchronous. The canvas is only valid during the paint callback.

## Learn More

- [Lottie Player](lottie-player.md) — The shared playback engine behind both MAUI and Blazor views
- [MAUI Lottie Animations](lottie-maui.md) — Use Lottie in .NET MAUI apps
- [Lottie by Airbnb](https://airbnb.design/lottie/) — Official project page
- [LottieFiles](https://lottiefiles.com/) — Free and premium animations
- [API Reference](xref:SkiaSharp.Extended.UI.Blazor.Controls.SKLottieView) — Full method documentation
25 changes: 21 additions & 4 deletions docs/docs/lottie.md → docs/docs/lottie-maui.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Lottie brings designer-created animations to your .NET MAUI apps. Instead of man

![Lottie animation preview][lottie-preview]

> **Other platforms:** This page covers .NET MAUI. For Blazor WebAssembly, see [Blazor Lottie Animations](lottie-blazor.md). For the shared playback engine, see [Lottie Player](lottie-player.md).

## What is Lottie?

[Lottie](https://airbnb.design/lottie/) is an animation format created by Airbnb. Animations are designed in Adobe After Effects, exported as JSON using the [Bodymovin](https://github.com/airbnb/lottie-web) plugin, and rendered natively on mobile and web. The name honors Lotte Reiniger, a pioneer of silhouette animation.
Expand Down Expand Up @@ -61,6 +63,18 @@ lottieView.Source = new SKStreamLottieImageSource { Stream = myStream };
<skia:SKLottieView Source="animation.json" RepeatCount="-1" RepeatMode="Reverse" />
```

> **Under the hood:** The MAUI `SKLottieView` translates `RepeatCount` and `RepeatMode` into [`SKLottieRepeat`](xref:SkiaSharp.Extended.SKLottieRepeat) values on the shared [`SKLottiePlayer`](lottie-player.md). See the [Lottie Player](lottie-player.md) docs for details on repeat semantics.

### Speed and direction

```xml
<!-- Double speed -->
<skia:SKLottieView Source="animation.json" AnimationSpeed="2.0" RepeatCount="-1" />

<!-- Play in reverse -->
<skia:SKLottieView Source="animation.json" AnimationSpeed="-1.0" RepeatCount="-1" />
```

### Control playback programmatically

```csharp
Expand All @@ -70,7 +84,7 @@ lottieView.IsAnimationEnabled = false;
// Resume
lottieView.IsAnimationEnabled = true;

// Jump to specific progress
// Jump to specific progress (also works while paused for scrubbing)
lottieView.Progress = TimeSpan.FromSeconds(1.5);

// Check if complete
Expand Down Expand Up @@ -109,11 +123,12 @@ lottieView.AnimationCompleted += (s, e) =>
| :------- | :--- | :---------- |
| `Source` | [`SKLottieImageSource`](xref:SkiaSharp.Extended.UI.Controls.SKLottieImageSource) | The Lottie JSON file to play |
| `Duration` | `TimeSpan` | Total duration of the animation (read-only) |
| `Progress` | `TimeSpan` | Current playback position |
| `Progress` | `TimeSpan` | Current playback position (two-way bindable) |
| `RepeatCount` | `int` | Times to repeat (0 = once, -1 = forever) |
| `RepeatMode` | [`SKLottieRepeatMode`](xref:SkiaSharp.Extended.UI.Controls.SKLottieRepeatMode) | `Restart` or `Reverse` (ping-pong) |
| `AnimationSpeed` | `double` | Speed multiplier (negative = reverse). Default: `1.0` |
| `IsAnimationEnabled` | `bool` | Play/pause the animation |
| `IsComplete` | `bool` | Whether playback has finished |
| `IsComplete` | `bool` | Whether playback has finished (read-only) |

## Where to Find Animations

Expand All @@ -138,10 +153,12 @@ You can customize the rendering surface by overriding the control template:
</skia:SKLottieView>
```

The `PART_DrawingSurface` name is requiredit can be either `SKCanvasView` (software) or `SKGLView` (GPU).
The `PART_DrawingSurface` name is requiredit can be either `SKCanvasView` (software) or `SKGLView` (GPU).

## Learn More

- [Lottie Player](lottie-player.md) — The shared playback engine behind MAUI and Blazor views
- [Blazor Lottie Animations](lottie-blazor.md) — Use Lottie in Blazor WebAssembly
- [Lottie by Airbnb](https://airbnb.design/lottie/) — Official project page
- [Lottie Documentation](https://airbnb.io/lottie/) — Format specification and guides
- [LottieFiles](https://lottiefiles.com/) — Animation marketplace
Expand Down
Loading