Myra UI - Draggable Window and Services
Myra, an external UI library, hosted inside Stride: a draggable window, two health bars - one declared in the view, one added while it runs - and service lookup through GetService to keep the UI from depending directly on the game. Hosting a foreign UI toolkit means giving it a scene renderer of its own and a place in the compositor, which is what MyraSceneRenderer does.
The Program.cs file shows how to:
- Hosting an external UI library inside Stride
- Rendering a foreign UI through a custom scene renderer
- Building a draggable window from Myra widgets
- Adding widgets statically and at runtime
- Decoupling UI from the game with GetService()

View on GitHub.
using E04_Myra_DraggableWindow;
using Stride.CommunityToolkit.Bepu;
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Rendering.Compositing;
using Stride.CommunityToolkit.Skyboxes;
using Stride.Engine;
using Stride.Games;
// Whether the second health bar has been added yet
var healthBarAdded = false;
using var game = new Game();
game.Run(new SceneSetup3D().UseBepu().UseSkybox(), start: Start, update: Update);
void Start(Scene rootScene) => game.AddSceneRenderer(new MyraSceneRenderer());
// The second health bar is added while the game runs, once the renderer has put the view in the services
void Update(Scene rootScene, GameTime time)
{
if (healthBarAdded || game.Services.GetService<MainView>() is not { } mainView) return;
mainView.Widgets.Add(UIUtils.CreateHealthBar(-50, "#FFD961FF"));
healthBarAdded = true;
}
MyraSceneRenderer.cs
The scene renderer that draws the Myra desktop over the scene.
using Myra;
using Myra.Graphics2D.UI;
using Stride.Engine;
using Stride.Games;
using Stride.Graphics;
using Stride.Rendering;
using Stride.Rendering.Compositing;
namespace E04_Myra_DraggableWindow;
/// <summary>
/// Draws a Myra user interface as a scene renderer in Stride's rendering pipeline.
/// </summary>
public class MyraSceneRenderer : SceneRendererBase
{
/// <summary>Myra's root container, which every element hangs off.</summary>
private Desktop? _desktop;
/// <summary>Sets up Myra, the main view and the desktop that holds it.</summary>
protected override void InitializeCore()
{
base.InitializeCore();
// Myra needs the concrete Game by now: a null here would surface much later as a
// NullReferenceException inside Myra.
MyraEnvironment.Game = Services.GetService<IGame>() as Game
?? throw new InvalidOperationException("Myra needs the running Stride Game to be registered in Services.");
// The view goes into the services, which is how Program.cs finds it to add a widget later
var mainView = new MainView();
Services.AddService(mainView);
_desktop = new Desktop { Root = mainView };
}
protected override void DrawCore(RenderContext context, RenderDrawContext drawContext)
{
drawContext.CommandList.Clear(GraphicsDevice.Presenter.DepthStencilBuffer, DepthStencilClearOptions.DepthBuffer);
_desktop?.Render();
}
}
MainView.cs
The main view: a health bar, a HorizontalProgressBar, and the draggable window.
using Myra.Graphics2D.UI;
namespace E04_Myra_DraggableWindow;
/// <summary>
/// The main view: a health bar and a draggable test window.
/// </summary>
public sealed class MainView : Panel
{
/// <summary>The draggable test window, with a sample label.</summary>
public Window ExampleWindow { get; }
public MainView()
{
Widgets.Add(UIUtils.CreateHealthBar(-20, "#4BD961FF"));
ExampleWindow = new Window
{
Title = "Hello From Myra",
Left = 590,
Top = 200,
Content = new Label
{
VerticalSpacing = 10,
Text = "This is a Test! Hello from Myra! This is a draggable window and below two progress bars."
}
};
Widgets.Add(ExampleWindow);
}
}
UIUtils.cs
CreateHealthBar, which builds both health bars: the one in MainView and the one Program.cs adds at run time.
using Myra.Graphics2D.Brushes;
using Myra.Graphics2D.UI;
namespace E04_Myra_DraggableWindow;
/// <summary>
/// Creates custom UI widgets.
/// </summary>
public static class UIUtils
{
/// <summary>
/// Creates a <see cref="HorizontalProgressBar"/> with the given top position and filler colour.
/// </summary>
/// <param name="top">The top position of the progress bar.</param>
/// <param name="filler">The filler colour of the progress bar.</param>
/// <returns>A new <see cref="HorizontalProgressBar"/> instance.</returns>
public static HorizontalProgressBar CreateHealthBar(int top, string filler) => new()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Bottom,
Value = 100,
Filler = new SolidBrush(filler),
Left = 20,
Top = top,
Width = 300,
Height = 20,
Background = new SolidBrush("#202020FF")
};
}