---
title: Getting started
tags: uikit
---
# Project setup
To use UIKit, you first have to reference its DLL in your mod's `.csproj`. This document assumes you are using Visual Studio (not VS Code) and that you already know how to add a reference, but if not, see [Microsoft's documentation on doing this in Visual Studio](https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2022#browse).
Due to how loading DLLs works on the .NET platform, it is not possible to load multiple versions of the same library, so additional steps are needed so that multiple mods that use UIKit can coexist without conflicting.
Depending on your use case and needs, choose one of the below options.
## a) Depend on `UIKitTools` (recommended)
Follow the instructions below if you want to support UIKit's author on NexusMods and/or if you do not mind adding a strong (`true`) mod dependency to your project.
The best way to make sure users do not have multiple copies of UIKit is to just depend on the `UIKitTools` mod included with it.
### Add a strong (`true`) mod dependency
Open your mod's `manifest.json`, and add a dependency:
```json
{
// ...
"Dependencies": [
{
"UniqueID": "Shockah.UIKit.Tools",
"IsRequired": true
}
]
}
```
### Stop packaging `UIKit.dll`
Open your mod's `.csproj`, and make the following change:
From:
```xml
<!-- ... -->
<ItemGroup>
<Reference Include="UIKit">
<HintPath>References\UIKit.dll <!-- this may differ --></HintPath>
</Reference>
</ItemGroup>
<!-- ... -->
```
To:
```xml
<!-- ... -->
<ItemGroup>
<Reference Include="UIKit">
<HintPath>References\UIKit.dll <!-- this may differ --></HintPath>
<Private>true</Private>
</Reference>
</ItemGroup>
<!-- ... -->
```
### Summary
After following those steps, your project should be ready to start using UIKit. Remember to remind your users to also install `UIKitTools`.
<a href="https://hackmd.io/@Shockah/Skkq-TZMq#Creating-and-displaying-your-first-UI" target="_self">Continue to the next section.</a>
## b) Package UIKit and weakly depend on `UIKitTools` (not recommended)
If you are not willing to add a strong dependency (because it may discourage your users from using your mod), follow the instructions below.
This method will package `UIKit.dll` with your mod, but it will not be used unless the user does not have `UIKitTools` installed.
:::warning
In theory, if a new version of UIKit included with `UIKitTools` has some breaking changes to its ABI, this approach could lead to your mod failing to load.
However, the UIKit's author will give it their best to avoid such situations, and if it is impossible to avoid, will try to communicate them much earlier.
:::
### Add a weak (`false`) mod dependency
Open your mod's `manifest.json`, and add a dependency:
```json
{
// ...
"Dependencies": [
{
"UniqueID": "Shockah.UIKit.Tools",
"IsRequired": false
}
]
}
```
This ensures that `UIKitTools` will load before your mod, along with its included `UIKit.dll`. As long as the user updates their mods regularly, this will be the latest version of the framework.
### Setup packaging of third party libraries
This step assumes you are using the `Pathoschild.Stardew.ModBuildConfig` NuGet package.
Open your mod's `.csproj`, and make the following addition:
```xml
<!-- ... -->
<PropertyGroup>
<!-- ... -->
<BundleExtraAssemblies>ThirdParty</BundleExtraAssemblies>
</PropertyGroup>
<!-- ... -->
```
See [SMAPI's documentation](https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#available-properties) for more details.
### Summary
After following those steps, your project should be ready to start using UIKit. You should still recommend your users to install `UIKitTools`, as this allows your mod to automatically accept any improvements or bugfixes of the newer versions, even without updating your own mod.
<a href="https://hackmd.io/@Shockah/Skkq-TZMq#Creating-and-displaying-your-first-UI" target="_self">Continue to the next section.</a>
## c) Package separated copy of UIKit (discouraged)
If you are not willing to add a dependency to `UIKitTools` and you are afraid of any potential breaking changes, follow the instructions below. These instructions assume you know what you are doing, which is why they are kept super short.
:::warning
Following these instructions will make it impossible to use any tools provided by `UIKitTools`. You will not be able to debug your constraints nor view hierarchy, unless you reimplement the debugging features yourself.
:::
:::warning
These instructions are untested, but in theory they should work.
:::
1. Prepare for building `UIKit` yourself. Clone / download the repository.
2. Change the `UIKit` assembly name to a custom name, making sure it will not clash with other mods doing the same.
3. Build `UIKit`.
4. Reference the built `.dll` in your mod.
5. [Make sure you have `BundleExtraAssemblies` set up properly.](#Setup-packaging-of-third-party-libraries)
After following those steps, your project should be ready to start using UIKit. Your copy of UIKit should be separated out from any other mods using UIKit, and `UIKitTools` will not be able to interact with it. Updates to `UIKitTools` will not affect your version of UIKit.
# Creating and displaying your first UI
UIKit by itself does not hook into the game -- it requires you, the developer, to do it. This has its advantages:
* It is more flexible -- you can use it as a screen overlay, as a part of your `IClickableMenu`, in the main game menu, etc.
* You can update the UI just once, then just render it, if all you do is display static information.
* You can update the UI just once, then render the UI to a `RenderTarget2D`, if you really want to save on performance and all you do is display static information.
But it also has the drawback of having to hook it up manually.
## Hello World
In the below example, we will create an in-game screen overlay.
First, create a root view. This can be done anywhere and anytime, as long as UIKit is already loaded. We will do it in the `GameLaunched` event provided by SMAPI.
We will be using the `StardewRootView` class provided by UIKit. This class handles resizing to the screen bounds, updating the layout, handling (mouse) input and rendering the screen.
```csharp
private StardewRootView Root;
public override void Entry(IModHelper helper)
{
helper.Events.GameLoop.GameLaunched += OnGameLaunched;
}
private void OnGameLaunched(object sender, GameLaunchedEventArgs e)
{
Root = new StardewRootView(Helper.Input);
}
```
### Hooking up
We need to hook up updating and rendering of our UI. In our example, we do this by using the `UpdateTicking` and `RenderedHud` events provided by SMAPI, but it does not necessarily have to be done this way.
```csharp
public override void Entry(IModHelper helper)
{
// ...
helper.Events.GameLoop.UpdateTicking += OnUpdateTicking;
helper.Events.Display.RenderedHud += OnRenderedHud;
}
private void OnUpdateTicking(object sender, UpdateTickingEventArgs e)
{
if (!Context.IsWorldReady)
return;
Root.Update();
}
private void OnRenderedHud(object sender, RenderedHudEventArgs e)
{
Root.Draw(e.SpriteBatch);
}
```
### Creating the layout
Our UI is hooked up, but it is currently empty. It is now time to add some views we can actually see. We will do this in the `GameLaunched` event handler.
```csharp
private void OnGameLaunched(object sender, GameLaunchedEventArgs e)
{
// ...
new UIStackView(Orientation.Vertical).With(Root, (self, parent) =>
{
new UIScalableColorableLabel(
new UISpriteFont(Game1.dialogueFont),
"Hello world!"
).With(self, (self, parent) =>
{
parent.AddArrangedSubview(self);
});
new UIQuad().With(self, (self, parent) =>
{
self.Texture = new UITextureRect(
Game1.emoteSpriteSheet,
new Rectangle(0, 80, 16, 16)
);
parent.AddArrangedSubview(self);
self.MakeAspectRatioConstraint().Activate();
});
parent.AddSubview(self);
self.LeftAnchor.MakeConstraintToSuperview(16f).Activate();
self.TopAnchor.MakeConstraintToSuperview(16f).Activate();
});
}
```
The above code is the preferred way of building UIs in a structured way. It leverages the `With` extension method provided by UIKit (or, well, technically its referenced shared project). Writing layout code in this way allows you to quickly see the view hierarchy, just from reading the code.
The below code has the exact same effect:
```csharp
private void OnGameLaunched(object sender, GameLaunchedEventArgs e)
{
// ...
UIStackView stackView = new UIStackView(Orientation.Vertical);
Root.AddSubview(stackView);
stackView.LeftAnchor.MakeConstraintToSuperview(16f).Activate();
stackView.TopAnchor.MakeConstraintToSuperview(16f).Activate();
UIScalableColorableLabel label = new UIScalableColorableLabel(
new UISpriteFont(Game1.dialogueFont),
"Hello world!"
);
stackView.AddArrangedSubview(label);
UIQuad quad = new UIQuad();
quad.Texture = new UITextureRect(
Game1.emoteSpriteSheet,
new Rectangle(0, 80, 16, 16)
);
stackView.AddArrangedSubview(quad);
quad.MakeAspectRatioConstraint().Activate();
}
```
### Testing
Our first UI is complete. You can now run the game with your mod. After loading into any save, you should be able to see this result:

### Final full code
You can find the full code for this example here:
:::spoiler Code
```csharp=
using Microsoft.Xna.Framework;
using Shockah.CommonModCode;
using Shockah.CommonModCode.UI;
using Shockah.UIKit;
using Shockah.UIKit.Geometry;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
namespace YourName.ModName
{
public class ModNameEntry: Mod
{
private StardewRootView Root;
public override void Entry(IModHelper helper)
{
helper.Events.GameLoop.GameLaunched += OnGameLaunched;
helper.Events.GameLoop.UpdateTicking += OnUpdateTicking;
helper.Events.Display.RenderedHud += OnRenderedHud;
}
private void OnGameLaunched(object sender, GameLaunchedEventArgs e)
{
Root = new StardewRootView(Helper.Input);
new UIStackView(Orientation.Vertical).With(Root, (self, parent) =>
{
new UIScalableColorableLabel(
new UISpriteFont(Game1.dialogueFont),
"Hello world!"
).With(self, (self, parent) =>
{
parent.AddArrangedSubview(self);
});
new UIQuad().With(self, (self, parent) =>
{
self.Texture = new UITextureRect(
Game1.emoteSpriteSheet,
new Rectangle(0, 80, 16, 16)
);
parent.AddArrangedSubview(self);
self.MakeAspectRatioConstraint().Activate();
});
parent.AddSubview(self);
self.LeftAnchor.MakeConstraintToSuperview(16f).Activate();
self.TopAnchor.MakeConstraintToSuperview(16f).Activate();
});
}
private void OnUpdateTicking(object sender, UpdateTickingEventArgs e)
{
if (!Context.IsWorldReady)
return;
Root.Update();
}
private void OnRenderedHud(object sender, RenderedHudEventArgs e)
{
Root.Draw(e.SpriteBatch);
}
}
}
```
:::
---
<div style="float: left;">
<a href="https://hackmd.io/@Shockah/rJBdk7Gfq"><i class="fa fa-chevron-left"></i> UIKit</a>
</div>
<div style="float: right;">
<a href="https://hackmd.io/@Shockah/S1YmQuJfq">View hierarchy and constraints <i class="fa fa-chevron-right"></i></a>
</div>