Skip to content

Stardew UI

Logo

A convenient, fast and scalable UI framework for Stardew Valley mods, dedicated to making UI development a breeze rather than a chore. Inspired in part by Angular and XAML.

  • 🌱 StardewUI Core is an includable code library in the form of a .NET Shared Project, containing the layout and rendering services, fundamental widgets, and integrations with the Stardew Valley base game, in particular its Menu system.

  • 🌳 StardewUI Framework is a standalone mod that hosts its own version of the Core library and provides a Model-View-Whatever (MVW) binding system using StarML as well as many other quality-of-life features not found in the Core.

Features

  • Dynamic layout


    Don't fuss with pixel positions; design with flows, grids and other layouts that adapt to your content.

    Built-in layouts

  • High performance


    Retained-mode UI only updates the things that change, when they change. Your UI will never stutter, even on potatoes.

    Details and benchmarks

  • 🎮 Controller ready


    No fussy neighbor lists, clunky clickable components or other boilerplate. Mouse or gamepad, it just works.

    Focus and interaction

  • Model-View-Whatever


    Keep your views and data separate, using an enhanced HTML-like markup with data binding and hot reload.

    StarML guide

  • Don't reinvent the wheel


    Pre-made widgets cover everything from simple text and images to drop-down lists, sliders, input boxes and scrollbars.

    Standard views

  • Made for modding


    Designed for SMAPI. StarML documents are normal game assets, and can be edited or replaced without Harmony patching.

    All about assets

Quick Start

In this introductory example, we'll be using the Framework, which is recommended if you're new to StardewUI. You'll need to be familiar with basic C# modding.

Try it out

Want to see the complete working example in game? The full source can be found in the test mod. Install it along with StardewUI and press F9 after loading a save.

internal sealed class ModEntry : Mod
{
    private IViewEngine viewEngine;

    public override void Entry(IModHelper helper)
    {
        helper.Events.GameLoop.GameLaunched += GameLoop_GameLaunched;
        helper.Events.Input.ButtonPressed += Input_ButtonPressed;
    }

    private void GameLoop_GameLaunched(object? sender, GameLaunchedEventArgs e)
    {
        viewEngine = Helper.ModRegistry.GetApi<IViewEngine>("focustense.StardewUI");
        viewEngine.RegisterViews("Mods/TestMod/Views", "assets/views");
        viewEngine.EnableHotReloading();
    }

    private void Input_ButtonPressed(object? sender, ButtonPressedEventArgs e)
    {
        if (Context.IsPlayerFree && e.Button == SButton.F8)
        {
            var context = MenuData.Edibles();
            Game1.activeClickableMenu = viewEngine.CreateMenuFromAsset(
                "Mods/TestMod/Views/ScrollingItemGrid",
                context);
        }
    }
}
public class MenuData
{
    public string HeaderText { get; set; } = "";
    public List<ParsedItemData> Items { get; set; } = [];

    public static MenuData Edibles()
    {
        int[] edibleCategories = [
            StardewValley.Object.CookingCategory,
            StardewValley.Object.EggCategory,
            StardewValley.Object.FishCategory,
            StardewValley.Object.FruitsCategory,
            StardewValley.Object.meatCategory,
            StardewValley.Object.MilkCategory,
            StardewValley.Object.VegetableCategory,
        ];
        var items = ItemRegistry.ItemTypes
            .Single(type => type.Identifier == ItemRegistry.type_object)
            .GetAllIds()
            .Select(id => ItemRegistry.GetDataOrErrorItem(id))
            .Where(data => edibleCategories.Contains(data.Category))
            .ToList();
        return new()
        {
            HeaderText = "All Edibles",
            Items = items,
        };
    }
}
<lane orientation="vertical"
      horizontal-content-alignment="middle">
    <banner background={@Mods/StardewUI/Sprites/BannerBackground}
            background-border-thickness="48,0"
            padding="12"
            text={HeaderText} />
    <frame layout="880px 640px"
           background={@Mods/StardewUI/Sprites/ControlBorder}
           margin="0,16,0,0"
           padding="32,24">
        <scrollable>
            <grid layout="stretch content"
                  item-layout="length: 64"
                  item-spacing="16,16"
                  horizontal-item-alignment="middle">
                <image layout="stretch content"
                       *repeat={Items}
                       sprite={this}
                       focusable="true" />
            </grid>
        </scrollable>
    </frame>
</lane>

The result:

Video of scrolling item grid

Next Steps

To get started on your own UI, you can either browse the Examples or follow through the recommended reading order below:

  1. StarML: Features, rules, and a handy syntax reference.
  2. Concepts: Semi-technical shallow dive into the framework's underlying concepts and design. Learn what "views" and "bindings" are, and get the necessary background for troubleshooting bugs or performance problems.
  3. Binding Context: How to design a good data model for powering StarML views and menus, and make your UI responsive to changes in game/user state.
  4. Events: Eventually you'll probably want to make your UI do something, like interact with the game world or update some of your mod's state or setting. Event bindings are powerful enough to deserve their own page.
  5. Includes: As UIs grow in complexity, you'll often find yourself wanting to create reusable components to be used in many different menus, HUDs, etc. This tutorial goes over the process and potential pitfalls.
  6. The Core Library: How and when to use it; both the "safe" and "unsafe" ways.
  7. Custom Views: If the Framework doesn't have what you need, you can create your own, whether it's something simple like the Banner to an entirely new kind of layout.
  8. Framework Extensibility: Adding custom tags, conversions, attributes and more; most useful to those who have created one or more custom widgets and want to make them available in StarML.

Happy Modding!