AppoMobi.Maui.DrawnUi
1.0.1.5-pre
See the version list below for details.
dotnet add package AppoMobi.Maui.DrawnUi --version 1.0.1.5-pre
NuGet\Install-Package AppoMobi.Maui.DrawnUi -Version 1.0.1.5-pre
<PackageReference Include="AppoMobi.Maui.DrawnUi" Version="1.0.1.5-pre" />
paket add AppoMobi.Maui.DrawnUi --version 1.0.1.5-pre
#r "nuget: AppoMobi.Maui.DrawnUi, 1.0.1.5-pre"
// Install AppoMobi.Maui.DrawnUi as a Cake Addin #addin nuget:?package=AppoMobi.Maui.DrawnUi&version=1.0.1.5-pre&prerelease // Install AppoMobi.Maui.DrawnUi as a Cake Tool #tool nuget:?package=AppoMobi.Maui.DrawnUi&version=1.0.1.5-pre&prerelease
AppoMobi.Maui.DrawnUi
Rendering engine for .Net MAUI to draw your UI on a skia canvas, with gestures and animations, from games to business apps.
Supports iOS, MacCatalyst, Android, Windows.
The current development state is PRE-ALPHA, many features remain to be implemented, the project is active.
This readme is heavily under construction, a lot of properties and use cases are not documented.
What's new
- SkiaCarousel
- SkiaDrawer
- Scrolling and other bug fixes
Development Notes
To notice:
- Expect this repo to be updated very often and breaking changes to occure
- Expect fps in minimum to double in Release builds (on Windows the lib fps in manually flex-capped at 200).
- In the demo app you can return to root view inside same tab on reselecting its icon (the Fun screen has no GoBack button)
Maui limitations:
- Xaml Hot-Reload revealed itsself not working for views added dynamically at runtime, despite using
VisualDiagnostics.OnChildAdded
, need to investigate. - Code-behind HotReload not working when changing code for controls and demo running.
Known Bugs:
- Padding not working inside label
- Aligned to End layout wrong calculation of width for type Column
- SkiaMauiElement is living his own life, maui elements are not working in a stable way.
- Margins and Padding are overall working okay but in same rare cases they contract the size of the element event when there is plenty of space around.
ToDo:
- SkiaEditor is just started, need to add a scroll inside, handle more stuff, add attachable text filters etc.
- Re-enable zoom gesture for SkiaScroll and add a demo, was ok (except for windows) but was disabled while working on templated cells.
- Restore the case dynamic templates for a skia scroll (was disabled at some time) and provide a demo in a form of chat messages recycled scroll
- SkiaSlider, basically have everything ready for it from other projects
- Rewrite the WheelPicker scroll calculations to so when scroll starts it already targets the perfect end cell position without snapping being needed after.
- Bind Rive Android+iOS, it's working fine on Windows, could be awesome for creating games.
- After reworking Snap from scrollTo to Bounce create SkiaCarousel.
- Add support for Minimim and Maximum size requests options for layout.
- Create drawer animator for many cases, add demos after that.
- SkiaGrid requires definitions to be set by dev to work, need to generate defaults if not set, corresponding to added views.
- Need to rework WheelPicker to add 3d transforms props for an intuitive use.
- FastShell used in Demo was coded to be used for Maui views, so need rework it to make compatible with drawn ui.
- Add header and footer for templated SkiaLayout
- Add options for fullscreen, have them ready for maui need just need to inject to drawn ui.
- Add diagnostic helper to dump visual trees especially animators.
- Add retry mechanics to image loader
- Recenter repeating code in some helper that would read app resources and web urls.
- Will add separate example for using drawn ui in a normal maui app as canvases here and there.
- Will add more animated tabs controls to with visual the looks of best flutter tabs plugins
- Etc etc..
Features
Draw your UI using SkiaSharp with hardware acceleration
Easily create your controls and animations
Design in Xaml or code-behind
2D and 3D Transforms
Animations targeting max fps
Gestures support for panning, scrolling and zooming (rotation incoming)
Caching system for elements and images
Optimized for performance, rendering only visible elements, recycling templates etc
Prebuilt Basic Ui Elements
- SkiaShape (Rounded rectangle, Circle, Gauge, more to come) can wrap other elements
- SkiaLabel, multiline with many options
- SkiaImage with options and filters
- SkiaSvg with many options
- SkiaLottie with tint customization
- SkiaRive (todo ios and android)
- SkiaLayout (Absolute, Grid, Vertical stack, Horizontal stack, todo Masonry) with templates support
- SkiaScroll (Horizonal, Vertical, Both) with zoom support and adjustable inertia, bounce, snap and much more (todo header, footer)
- SkiaScroll + SkiaLayout = CollectionView-like control with refresh, custom refresh indicator, load more etc
- SkiaHotspot to handle gestures in a easy way
- SkiaMauiElement for when skia is not enough
Derived custom controls
- SkiaButton include anything inside, text, images etc
- SkiaScrollLooped for neverending scrolls
- SkiaDrawer to swipe in and out your controls
- SkiaCarousel swipe and slide controls inside a carousel
- SkiaEditor we can type over canvas too
- SkiaCursor to blink where you type
- SkiaHoverMask to overlay a clipping shape
- SkiaLabelFps for developement
- SkiaDecoratedGrid to draw shapes between rows and columns
- ScrollPickerWheel for creating wheel pickers
- RefreshIndicator can use lottie and anything for your scroll refresh view
- SkiaTabsSelector create top and bottom tabs
- SkiaViewSwitcher switch your views, pop, push and slide
- Create your own!
Animated Effects
- Ripple
- Shimmer
- BlinkColors
- (todo Pulse)
- Commit yours!
Animators
- _todo add info
Transforms
- TranslationX
- TranslationY
- ScaleX
- ScaleY
- Rotation
- CameraAngleX
- CameraAngleY
- CameraAngleZ
- SkewX
- SkewY
- Perspective1
- Perspective2
Demo App
todo add more tabs animations, chat example, complex scroll example (aliexpress, auchan), 2d game example (checkers, arkanoid)
Installation
Install the package AppoMobi.Maui.DrawnUi from NuGet.
After that initialize the library inside your MauiProgram.cs file:
builder.UseDrawnUi<App>();
Quick Start
You will be mainly using Maui view Canvas
that will wrap your SkiaControls.
Anywhere in your existing Maui app you can include a Canvas
and start drawing your UI.
The Canvas
control is aware of its children size and will resize accordingly.
At the same time you could set a fixed size for the Canvas
and its children will adapt to it.
Xaml
Import the namespace:
xmlns:draw="http://schemas.appomobi.com/drawnUi/2023/draw"
Consume:
<draw:Canvas>
<draw:SkiaSvg
Source="Svg/dotnet_bot.svg"
LockRatio="1"
HorizontalOptions="Center"
TintColor="White"
WidthRequest="44" />
</draw:Canvas>
As you can see in this example the Maui view Canvas
will adapt it's size to drawn content and should take 44x44 pts.
Code behind
_todo_
Please check the demo app, it contains many examples of usage.
todo put important explanation about caching again
Gestures
To make your root Canvas
catch gestures you need to attach a TouchEffect
to it.
After that skia controls can process gestures in multiple ways:
- Implementing an
ISkiaGestureListener
interface and overridingOnGestureReceived
. - Attaching a
HandleGestures
effect that has properties similarSkiaHotspot
. - Including a
SkiaHotspot
as a child. - Using a
SkiaButton
.
todo give examples
Caching System
Controls Rendering Result
todo
Caching is set using a property UseCache
of the following type:
/// <summary>
/// Usage of cache requires IsClippedToBounds to be true
/// </summary>
public enum SkiaCacheType
{
None,
/// <summary>
/// Create and reuse SKPicture,
/// </summary>
Operations,
/// <summary>
/// The cached surface will use the same graphic context as your canvas
/// </summary>
Bitmap
}
You should tweak your design caching to avoid unnecessary re-drawing of elements.
The basic approach here is to cache small elements at some level.
For example you would cache small children like cells inside a SkiaScroll as Bitmap
.
At the same time avoid using bitmaps where just Operations
type is enough, for example for SkiaSvg results.
When you start using any kind of animations you should start using caching to max your FPS. You can check the DemoApp for such examples.
Loaded Images
We are using the EasyCaching.InMemory library for caching loaded bitmaps. It's impact can much be seen when using recycled cells inside a scroll. todo add options and link to ImageLoader and SkiaImage docs
Transforms
todo
- TranslationX
- TranslationY
- ScaleX
- ScaleY
- Rotation
- CameraAngleX
- CameraAngleY
- CameraAngleZ
- SkewX
- SkewY
- Perspective1
- Perspective2
Animations
todo
One would create animations and effects using animators. Animators are attached to controls, but technically register themselves at the root canvas level and their code is executed on every rendering frame. If the canvas is not redrawing then animators will not be executed. When the canvas has a registered animator running it would constantly force re-drawing itsself until all animators are stopped.
There are two types of animators:
- Animators are executed before the drawing, so you can move and transform elements before the are rendered on the canvas.
- PostAnimators are executed after their parent element was drawn, so you can paint an effect over the existing result, or execute any other post-drawing logic.
Hint: If you need to create a game loop you could put its code inside an animator and attach the animator with the root element as parent.
todo restore from deleted another way of running a game loop that was not redrawing canvas on every tick
Layout
For initial items positionning you would be using SkiaLayout
.
Its Absolute
layout type is already buil-it in every skia control..
You can position your children using familiar properties like
HorizonalOptions
, VerticalOptions
, Margin
, parent Padding
,
WidthRequest
, HeightRequest
,MinimumWidthRequest
, MinimumHeightRequest
and additional MaximumWidthRequest
, MaximumHeightRequest
and LockRatio
properties.
For dynamic positionning or other precise cases use TranslationX
and TranslationY
.
Whn you need to layout children in a more arranged way you will want to wrap them with a SkiaLayout
of different LayoutType
: Grid, Colum, Row and others.
Layout supports ItemTemplate
for most of layout types.
Enhanced usage
When dealing with subviews in code behind you could typically use two ways.
Example for adding a subview:
- set subview property
Parent
to the new parent. In this case parent layout will not be invalidated, use this for optimized logic when you know what you are doing. You can mainly use this way when just constructing parent, knowing it will be measured at start anyway. - call parent's method
AddSubView
passing subview.Parent's layout will be invalidated, and OnChildAdded will be called on parent. For removing a subview the usual options would be: - set subview property
Paren t
to null, for soft removal. - call parent's method
RemoveSubView
passing subview. Parent's layout will be invalidated, and OnChildRemoved will be called on parent.
In Deep
When XAML would be constructed it would fill SubViews
property with views, this property is for high-level access. Views
Will be then filled internally. When you add or remove items in SubViews
methods AddSubView
and RemoveSubView
will be called for managing Views
.
Enhanced Usage
Styles
When you want to dynamically change properties in Xaml you might want to use conditional styles. They look like regular Maui styles, but with some nuances:
- When defining style is resources you must set a unique
Class
attibute - They are selected at runtime upon
Condition
orState
bindable properties.State
is like MauiVisualState
but you can have several of them applied at same time.
Define a style inside ResourceDictionary
:
<Style
x:Key="SkiaLabelDefaultStyle"
Class="SkiaLabelDefaultStyle"
TargetType="draw:SkiaLabel">
<Setter Property="TextColor" Value="#E8E3D7" />
<Setter Property="FontFamily" Value="FontText" />
<Setter Property="FontSize" Value="15" />
</Style>
Apply a style:
<draw:SkiaLabel
Style="{StaticResource SkiaLabelStyle}"
Text="Simple Styled Label" />
Apply styles upon conditions:
<views:SkiaShape
LockRatio="1"
Type="Circle"
WidthRequest="16">
<views:SkiaControl.Styles>
<views:ConditionalStyle
State="Normal"
Style="{x:StaticResource StyleCameraDot}" />
<views:ConditionalStyle
Condition="{Binding .}"
Style="{x:StaticResource StyleCameraDotOn}" />
</views:SkiaControl.Styles>
</views:SkiaShape>
Same as:
<views:SkiaShape
Style="{StaticResource StyleCameraDot}"
LockRatio="1"
Type="Circle"
WidthRequest="16">
<views:SkiaControl.Styles>
<views:ConditionalStyle
Condition="{Binding .}"
Style="{x:StaticResource StyleCameraDotOn}" />
</views:SkiaControl.Styles>
</views:SkiaShape>
When the BindingContext (x:Boolean) is True the style StyleCameraDotOn
will be applied, otherwise StyleCameraDot
will be applied.
To apply styles upon states you will be using standart Maui VisualStates mechanism, or you can even have serveral states at the same time, every SkiaControl
has a string[] States
bindable property to server this purpose:
<views:SkiaShape
States="{Binding VisualStates}"
LockRatio="1"
Type="Circle"
WidthRequest="16">
<views:SkiaControl.Styles>
<views:ConditionalStyle
State="Normal"
Style="{x:StaticResource StyleCameraDot}" />
<views:ConditionalStyle
State="IsOn"
Style="{x:StaticResource StyleCameraDotOn}" />
</views:SkiaControl.Styles>
Hints
todo
For SkiaStack of type Row or Column avoid using Fill for children ?? that would require a second measurement pass.
Models
SkiaControl
Base element.
Properties:
LockRatio
a numeric value that will be used to calculate the width when the height is set or vice versa. If it's above 0 the max value will be applied, if it's below 0 the min value will be applied. If it's 0 then the ratio will be ignored.
Example 1:
<draw:SkiaShape
LockRatio="1"
WidthRequest="40" />
HeightRequest wasn't specified but this control will request 40 by 40 pts.
Example 2:
<draw:SkiaShape
LockRatio="-1"
HeightRequest="30"
WidthRequest="40" />
This control will request 30 by 30 pts.
SkiaScroll
SkiaScroll
is a scrollable container that supports virtualization and recycling of its children.
If you include a SkiaLayout
inside a SkiaScroll
only visible on screen items will be rendered.
If the include a SkiaLayout
that uses ItemTemplate
this combination will automatically become virtualized and you will get sort of a CollectionView with recycled cells at your disposal. It is a good practice to use it for long lists of items.
SkiaLayout
SkiaLayout
is a container that supports various layout types: Absolute
, Grid
, Row
, Column
and others.
It also supports virtualization and recycling of its children with ItemTemplate
property.
SkiaShape
SkiaShape
is a base class for all shapes. You could fill it, stroke, drop shadows, apply gradients and even clip other controls with it.
SkiaImage
SkiaImage
is a control that renders images. It cant apply filters and transformations.
SkiaSvg
SkiaSvg
is a control that renders svg files. It cant tint the svg with a color or gradient, and apply some transforms to it.
SkiaLabel
A multi-line label fighting for his place under the sun.
Properties:
FontWeight
a numeric value used in case you have properly registered your fonts to support weights.
You can use your font the usual Maui way but in case of custom font files used from resources you might want to register them, using the following example:
.ConfigureFonts(fonts =>
{
fonts.AddFont("Gilroy-Regular.ttf", "FontText", FontWeight.Regular);
fonts.AddFont("Gilroy-Medium.ttf", "FontText", FontWeight.Medium);
});
Now if you set the FontWeight
to 500
the control will use the Gilroy-Medium.ttf
file.
This might come very handy when your Figma design shows you to use this weight and you want just to pass it over to SkiaLabel.
HorizontalTextAlignment
:
public enum DrawTextAlignment
{
Start,
Center,
End,
FillWords,
FillWordsFull,
FillCharacters,
FillCharactersFull,
}
SkiaLottie
SkiaLottie
is a control that renders lottie files. It can even tint some colors inside your animation!
SkiaRive
Actually for Windows only, this plays and controls Rive animation files. Other platforms will be added soon, poke if you would like to help biding some c++;
SkiaDrawer
A drawer is a container that can be opened and closed. It is a subclassed SnappingLayout:SkiaLayout
.
It you want to host a ScrollView inside, this one must have Bounces
set to false
to pass scrolling gestures to drawer at scrolling edges.
Events:
IsOpenChanged
Event that will be fired when the open state changes.
Scrolling
For when it's scrolling..
Scrolled
Scrolling finished.
Properties:
IsOpen
Two-way bindable boolean property that controls the drawer state.
InTransition
Read-only boolean, to know if transition animation is in progress.
HeaderSize
Size in pts (double) of the area the will be visible on screen when drawer is closed.
Direction
Type is DrawerDirection
:
public enum DrawerDirection
{
FromBottom,
FromTop,
FromLeft,
FromRight
}
You will still be responsible to set appropriate layout options for every case, like VerticalOptions="End"
for FromBottom
direction.
Bounces
Boolean, rubber effect on bounds
SkiaCarousel
To use as slider or carousel.
Subclassed SnappingLayout : SkiaLayout
.
Needs self dimensions to be set or to use Fill, will not adapt to content size.
Can use ItemTemplate or directly included children controls, in this last case will auto-set children size to self size. If you use ItemTemplate
please set it to Fill the container.
Using direct controls instead of ItemTemplate
is useful for small number of items when you need to have totally different designs for each cell.
Events:
SelectedIndexChanged
: Event fired when the selected index changes.
OnLayoutReady
: Event fired when the layout is ready.
OnTransitionChanged
: Event fired when a transition state changes.
ItemAppearing
: Event fired when an item is appearing.
ItemDisappearing
: Event fired when an item is disappearing.
Scrolled
: Event fired when scrolling is finished.
Scrolling
: Event fired when scrolling is in progress.
Properties:
SelectedIndex
Two-way bindable integer property that speaks for itsself.
SidesOffset
As title, for when you want to see neighboor items at sides, default is 0.
InTransition
: A Boolean property indicating whether the layout is in a transition state.
IsVertical
: A Boolean property that defines whether the carousel scrolls vertically; false by default.
IsRightToLeft
: A Boolean property that indicates whether the carousel direction is right-to-left; false by default.
LayoutReady
: A Boolean property indicating whether the layout is ready.
Bounces
: A Boolean property indicating whether the layout has a bounce effect at its edges.
RubberEffect
: A double property representing the strength of the rubber band effect at sides when Bounces
is True.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-android33.0 is compatible. net7.0-ios was computed. net7.0-ios16.1 is compatible. net7.0-maccatalyst was computed. net7.0-maccatalyst16.1 is compatible. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net7.0-windows10.0.19041 is compatible. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net7.0
- AppoMobi.Maui.Gestures (>= 1.0.1.2-pre)
- EasyCaching.InMemory (>= 1.9.0)
- SkiaSharp.Skottie (>= 2.88.3)
- SkiaSharp.Views.Maui.Controls.Compatibility (>= 2.88.3)
- Svg.Skia (>= 0.5.18)
-
net7.0-android33.0
- AppoMobi.Maui.Gestures (>= 1.0.1.2-pre)
- AppoMobi.Maui.Native (>= 1.0.0.5-pre)
- EasyCaching.InMemory (>= 1.9.0)
- SkiaSharp.Skottie (>= 2.88.3)
- SkiaSharp.Views.Maui.Controls.Compatibility (>= 2.88.3)
- Svg.Skia (>= 0.5.18)
-
net7.0-ios16.1
- AppoMobi.Maui.Gestures (>= 1.0.1.2-pre)
- EasyCaching.InMemory (>= 1.9.0)
- SkiaSharp.Skottie (>= 2.88.3)
- SkiaSharp.Views.Maui.Controls.Compatibility (>= 2.88.3)
- Svg.Skia (>= 0.5.18)
-
net7.0-maccatalyst16.1
- AppoMobi.Maui.Gestures (>= 1.0.1.2-pre)
- EasyCaching.InMemory (>= 1.9.0)
- SkiaSharp.Skottie (>= 2.88.3)
- SkiaSharp.Views.Maui.Controls.Compatibility (>= 2.88.3)
- Svg.Skia (>= 0.5.18)
-
net7.0-windows10.0.19041
- AppoMobi.Maui.Gestures (>= 1.0.1.2-pre)
- AppoMobi.Maui.Rive (>= 1.0.1.2-pre)
- EasyCaching.InMemory (>= 1.9.0)
- SkiaSharp.Skottie (>= 2.88.3)
- SkiaSharp.Views.Maui.Controls.Compatibility (>= 2.88.3)
- Svg.Skia (>= 0.5.18)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on AppoMobi.Maui.DrawnUi:
Package | Downloads |
---|---|
AppoMobi.Maui.Infrastructure
AppoMobi In-house Framework For .NET MAUI |
|
DrawnUi.Maui.Rive
SkiaRive DrawnUi control for .NET MAUI (temporarily Windows only is supported) |
|
DrawnUi.MauiGraphics
SkiaMauiGraphics DrawnUi control for .NET MAUI |
|
DrawnUi.Maui.Camera
Camera implementation (temporarily Android only) and preview rendering with SkiaSharp in .NET MAUI |
|
DrawnUi.Maui.Game
Base class for implementing a game with SkiaSharp in .NET MAUI |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on AppoMobi.Maui.DrawnUi:
Repository | Stars |
---|---|
taublast/DrawnUi.Maui
UI Rendering Engine for .NET MAUI powered by SkiaSharp
|
Version | Downloads | Last updated | |
---|---|---|---|
1.3.54.5-pre | 86 | 11/12/2024 | |
1.3.54.4-pre | 38 | 11/12/2024 | |
1.3.54.2-pre | 43 | 11/9/2024 | |
1.3.54.1-pre | 94 | 11/9/2024 | |
1.3.0.2113-pre | 167 | 4/6/2024 | |
1.3.0.2112-pre | 81 | 4/6/2024 | |
1.3.0.219-pre | 80 | 4/3/2024 | |
1.3.0.218-pre | 71 | 4/3/2024 | |
1.3.0.23-pre | 75 | 3/26/2024 | |
1.3.0.22-pre | 70 | 3/26/2024 | |
1.3.0.21-pre | 70 | 3/26/2024 | |
1.3.0.2-pre | 74 | 3/26/2024 | |
1.3.0.1-pre | 77 | 3/26/2024 | |
1.2.9.4 | 4 | 11/24/2024 | |
1.2.9.2 | 46 | 11/21/2024 | |
1.2.9.1 | 69 | 11/19/2024 | |
1.2.5.2 | 103 | 11/12/2024 | |
1.2.5.1 | 110 | 11/5/2024 | |
1.2.4.8 | 85 | 11/4/2024 | |
1.2.4.7 | 98 | 11/2/2024 | |
1.2.4.4 | 114 | 10/30/2024 | |
1.2.4.1 | 99 | 10/26/2024 | |
1.2.3.8 | 404 | 8/21/2024 | |
1.2.3.6 | 258 | 7/14/2024 | |
1.2.3.4 | 214 | 7/4/2024 | |
1.2.3.3 | 187 | 6/27/2024 | |
1.2.3.2 | 153 | 6/26/2024 | |
1.2.2.617 | 154 | 6/17/2024 | |
1.2.2.67 | 134 | 6/7/2024 | |
1.2.2.7 | 137 | 6/3/2024 | |
1.2.2.5 | 173 | 5/24/2024 | |
1.2.2.4 | 99 | 5/24/2024 | |
1.2.2.3 | 156 | 5/20/2024 | |
1.2.2.2 | 107 | 5/20/2024 | |
1.2.2.1 | 122 | 5/20/2024 | |
1.2.0.95 | 158 | 4/14/2024 | |
1.2.0.94 | 136 | 4/12/2024 | |
1.2.0.89 | 246 | 4/6/2024 | |
1.2.0.88 | 178 | 4/6/2024 | |
1.2.0.86 | 122 | 4/5/2024 | |
1.2.0.84 | 130 | 4/3/2024 | |
1.2.0.83 | 138 | 4/3/2024 | |
1.2.0.8 | 133 | 4/3/2024 | |
1.2.0.7 | 159 | 3/26/2024 | |
1.2.0.6 | 133 | 3/26/2024 | |
1.2.0.5 | 185 | 3/26/2024 | |
1.2.0.4-pre | 135 | 3/25/2024 | |
1.2.0.3-pre | 130 | 3/25/2024 | |
1.2.0.2-pre | 143 | 3/25/2024 | |
1.0.8.7 | 213 | 3/6/2024 | |
1.0.8.6 | 263 | 2/27/2024 | |
1.0.8.5 | 252 | 2/21/2024 | |
1.0.8.4 | 248 | 2/21/2024 | |
1.0.8.3 | 287 | 2/16/2024 | |
1.0.8.2 | 302 | 2/16/2024 | |
1.0.8.1 | 321 | 2/5/2024 | |
1.0.8 | 304 | 2/4/2024 | |
1.0.7.6-pre | 263 | 2/1/2024 | |
1.0.7.4-pre | 250 | 2/1/2024 | |
1.0.7.3-pre | 270 | 1/31/2024 | |
1.0.7.2-pre | 270 | 1/31/2024 | |
1.0.7.1-pre | 270 | 1/30/2024 | |
1.0.6.6-pre | 266 | 1/26/2024 | |
1.0.6.5-pre | 235 | 1/26/2024 | |
1.0.6.4-pre | 273 | 1/25/2024 | |
1.0.6.1-pre | 259 | 1/24/2024 | |
1.0.5.8-pre | 257 | 1/22/2024 | |
1.0.5.7-pre | 286 | 1/21/2024 | |
1.0.5.6-pre | 275 | 1/21/2024 | |
1.0.5.5-pre | 279 | 1/21/2024 | |
1.0.5.4-pre | 271 | 1/21/2024 | |
1.0.5.3-pre | 273 | 1/21/2024 | |
1.0.4.6-pre | 279 | 1/20/2024 | |
1.0.3.7-pre | 289 | 1/11/2024 | |
1.0.3.6-pre | 229 | 1/11/2024 | |
1.0.3.5-pre | 282 | 1/11/2024 | |
1.0.3.4-pre | 287 | 1/10/2024 | |
1.0.3.3-pre | 299 | 1/10/2024 | |
1.0.3.2-pre | 269 | 1/10/2024 | |
1.0.3-pre | 274 | 1/8/2024 | |
1.0.2.9-pre | 283 | 1/7/2024 | |
1.0.2.8-pre | 284 | 1/4/2024 | |
1.0.1.32-pre | 314 | 12/15/2023 | |
1.0.1.31-pre | 297 | 12/15/2023 | |
1.0.1.30-pre | 301 | 12/10/2023 | |
1.0.1.29-pre | 279 | 12/10/2023 | |
1.0.1.28-pre | 304 | 12/8/2023 | |
1.0.1.27-pre | 324 | 11/22/2023 | |
1.0.1.26-pre | 289 | 11/22/2023 | |
1.0.1.25-pre | 277 | 11/21/2023 | |
1.0.1.24-pre | 294 | 11/21/2023 | |
1.0.1.23-pre | 266 | 11/21/2023 | |
1.0.1.22-pre | 298 | 11/21/2023 | |
1.0.1.21-pre | 282 | 11/21/2023 | |
1.0.1.20-pre | 288 | 11/20/2023 | |
1.0.1.17-pre | 282 | 11/14/2023 | |
1.0.1.15-pre | 293 | 11/9/2023 | |
1.0.1.14-pre | 266 | 11/9/2023 | |
1.0.1.12-pre | 295 | 11/7/2023 | |
1.0.1.11-pre | 279 | 11/2/2023 | |
1.0.1.10-pre | 304 | 11/2/2023 | |
1.0.1.9-pre | 312 | 10/23/2023 | |
1.0.1.8-pre | 289 | 10/23/2023 | |
1.0.1.6-pre | 322 | 8/3/2023 | |
1.0.1.5-pre | 309 | 8/3/2023 |
Under construction