Home Theme System
Post
Cancel

Theme System

HunterPie’s theme system provides powerful customization capabilities, allowing users to completely override the application’s appearance and create personalized designs. You can customize everything from basic colors to complete widget redesigns.

Overview

The theme system operates through XAML resource overrides, that means you can:

  1. Override default colors and styles: Change the core visual elements of HunterPie
  2. Fully customize widget designs: Create entirely new layouts and appearances for overlay widgets

Default Resources

HunterPie’s default theme consists of two main resource files:

How to Create a Theme

A HunterPie theme consists of two essential components:

  1. Theme Manifest (theme.manifest.json) - Contains metadata about your theme
  2. XAML Files (.xaml) - Contains the actual styling and resource overrides

Theme Manifest Structure

The theme.manifest.json file stores your theme’s metadata and is required for HunterPie to recognize your theme:

1
2
3
4
5
6
7
8
9
10
11
{
  "id": "<THIS MUST BE UNIQUE>",
  "name": "My cool theme",
  "description": "A very cool theme with very cool designs",
  "version": "1.0.0",
  "author": "Haato",
  "tags": [
    "overlay",
    "monster-widget"
  ]
}

Manifest Properties

PropertyDescription
idA unique identifier for your theme (MUST BE UNIQUE). Generate a new UUID for each theme here.
nameThe display name of your theme
descriptionA brief description of what your theme offers
versionYour theme’s version number (use semantic versioning)
authorYour name or username
tagsArray of descriptive tags (currently not used by HunterPie but recommended to fill)

Important: The id property must be unique across all themes. Use a GUID generator to create a unique identifier.

XAML File Loading Order

  • XAML files are loaded in alphabetical order
  • If multiple files override the same resource, the last loaded file takes priority
  • Use filenames to control loading order (e.g., 01-colors.xaml, 02-widgets.xaml)

Basic Theme Structure

1
2
3
4
5
6
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <!-- Your custom resources go here -->
    
</ResourceDictionary>

Importing namespaces

Sometimes you might need to import namespaces into your ResourceDictionary so you can use HunterPie’s built-in converters and markups. Let’s say you need to import the converter that multiplies two numbers MultiplyNumberConverter.

To do that, you will need to add the following line to your ResourceDictionary header:

1
2
3
4
5
6
7
8
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:arithmetics="clr-namespace:HunterPie.UI.Architecture.Converters.Arithmetics;assembly=HunterPie.UI"> 
                    <!-- ^ This is what should be added to your ResourceDictionary -->

<!-- Once you added the namespace to your file, you can now use the resources from that namespace -->
<arithmetics:MultiplyNumberConverter x:Key="MultiplyByTwo"
                                     Factor="2" />

For a list of all converters, take a look at HunterPie’s source code: Converters

Overriding Colors

To override colors, create a resource with the exact same name as the default resource. Here are some commonly customized colors:

Core UI Colors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Background colors -->
<SolidColorBrush x:Key="Brushes.HunterPie.Background.Primary">#1a1a1a</SolidColorBrush>
<SolidColorBrush x:Key="Brushes.HunterPie.Background.Secondary">#2a2a2a</SolidColorBrush>
<SolidColorBrush x:Key="Brushes.HunterPie.Background.Tertiary">#3a3a3a</SolidColorBrush>

<!-- Text colors -->
<SolidColorBrush x:Key="Brushes.HunterPie.Foreground.Primary">#ffffff</SolidColorBrush>
<SolidColorBrush x:Key="Brushes.HunterPie.Foreground.Secondary">#cccccc</SolidColorBrush>

<!-- Accent colors -->
<SolidColorBrush x:Key="Brushes.HunterPie.Accent.Solid">#ff6b35</SolidColorBrush>
<LinearGradientBrush x:Key="Brushes.HunterPie.Accent" StartPoint="0,1" EndPoint="1,1">
    <GradientStop Offset="0.863" Color="#ff6b35" />
    <GradientStop Offset="1" Color="#f7931e" />
</LinearGradientBrush>

Gray Scale Palette

1
2
3
4
5
6
7
8
9
10
<!-- Customize the gray scale used throughout the app -->
<SolidColorBrush x:Key="Gray">#404040</SolidColorBrush>
<SolidColorBrush x:Key="Gray@50">#303030</SolidColorBrush>
<SolidColorBrush x:Key="Gray@100">#252525</SolidColorBrush>
<SolidColorBrush x:Key="Gray@200">#202020</SolidColorBrush>
<SolidColorBrush x:Key="Gray@300">#1a1a1a</SolidColorBrush>
<SolidColorBrush x:Key="Gray@400">#151515</SolidColorBrush>
<SolidColorBrush x:Key="Gray@500">#101010</SolidColorBrush>
<SolidColorBrush x:Key="Gray@600">#0a0a0a</SolidColorBrush>
<SolidColorBrush x:Key="Gray@700">#050505</SolidColorBrush>

Widget-Specific Colors

Monster Widget

1
2
3
4
5
6
7
8
9
10
<!-- Monster health bars -->
<SolidColorBrush x:Key="Brushes.Widgets.Monster.Health.Default">#4a90e2</SolidColorBrush>
<SolidColorBrush x:Key="Brushes.Widgets.Monster.Health.Default.Background">#1a3a5c</SolidColorBrush>

<!-- Enraged state -->
<LinearGradientBrush x:Key="Brushes.Widgets.Monster.Health.Enraged" 
                     EndPoint="1,1" StartPoint="0,1">
    <GradientStop Color="#e74c3c"/>
    <GradientStop Color="#c0392b" Offset="1"/>
</LinearGradientBrush>

Player HUD Widget

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- Player health -->
<LinearGradientBrush x:Key="Brushes.Widgets.Player.Health.Default"
                     EndPoint="1,1" StartPoint="0,1">
    <GradientStop Color="#27ae60"/>
    <GradientStop Color="#2ecc71" Offset="1"/>
</LinearGradientBrush>

<!-- Player stamina -->
<LinearGradientBrush x:Key="Brushes.Widgets.Player.Stamina.Default"
                     EndPoint="1,1" StartPoint="0,1">
    <GradientStop Color="#f39c12" Offset="1"/>
    <GradientStop Color="#e67e22" Offset="0"/>
</LinearGradientBrush>

Weapon-Specific Colors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- Longsword spirit gauge levels -->
<LinearGradientBrush x:Key="Brushes.Widgets.Longsword.LevelOne"
                     EndPoint="1,1" StartPoint="0,1">
    <GradientStop Color="#ecf0f1" Offset="1"/>
    <GradientStop Color="#bdc3c7" Offset="0"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="Brushes.Widgets.Longsword.LevelTwo"
                     EndPoint="1,1" StartPoint="0,1">
    <GradientStop Color="#f1c40f" Offset="1"/>
    <GradientStop Color="#f39c12" Offset="0"/>
</LinearGradientBrush>

<LinearGradientBrush x:Key="Brushes.Widgets.Longsword.LevelMax"
                     EndPoint="1,1" StartPoint="0,1">
    <GradientStop Color="#e74c3c" Offset="1"/>
    <GradientStop Color="#c0392b" Offset="0"/>
</LinearGradientBrush>

Custom Widget Styles

To fully customize a widget’s appearance, override its style and set a custom Template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<Style x:Key="Widgets.Monster" TargetType="{x:Type UserControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type UserControl}">
                <!-- Your custom widget layout -->
                <Border Background="{StaticResource Brushes.HunterPie.Background.Primary}"
                        BorderBrush="{StaticResource Brushes.HunterPie.Border}"
                        BorderThickness="2"
                        CornerRadius="5">
                    
                    <!-- Bind to the Monsters collection -->
                    <ItemsControl ItemsSource="{Binding Monsters, Mode=OneWay}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Vertical" />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        
                        <!-- Template for each monster -->
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name, Mode=OneWay}"
                                          Foreground="{StaticResource Brushes.HunterPie.Foreground.Primary}"
                                          FontSize="14"
                                          Margin="10,5"
                                          HorizontalAlignment="Left"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Understanding Widget Data Binding

Each widget in HunterPie has its own view model that exposes different properties and data collections. When creating custom widget themes, it’s your responsibility to:

  1. Bind to the correct properties - Each widget’s view model has specific properties you need to bind to for data display
  2. Respect configuration settings - Bind to configuration properties when possible so user settings apply to your custom theme
  3. Use proper binding modes - Most data should use Mode=OneWay for performance reasons

Common Widget Properties

Most widgets follow similar patterns for their view models:

  • Data Collections - ObservableCollection<T> properties (e.g., Monsters, Players, Ailments)
  • Configuration - Config property containing user settings for that specific Widget
  • Display Values - Formatted strings and numeric values for UI display

Binding to Configuration

Always check if the widget exposes configuration properties and bind to them when appropriate:

1
2
3
4
5
6
7
8
9
10
<!-- Example: Bind to user's width settings -->
<Border Width="{Binding Config.Width.Current, Mode=OneWay}">
    <!-- Your content -->
</Border>

<!-- Example: Respect visibility settings -->
<StackPanel Visibility="{Binding Config.IsVisible.Value, 
                                 Converter={StaticResource BooleanToVisibilityConverter}}">
    <!-- Your content -->
</StackPanel>

This ensures your custom theme respects the user’s preferences and behaves consistently with the default theme.

To find out what properties are available for each widget and their respective View Model, refer to the source code.

Available Widget Styles

You can customize the following widget styles:

  • Widgets.SpecializedToolV2 - Specialized Tools widget
  • Widgets.Monster - Monster information widget
  • Widgets.DamageMeter - Damage meter widget
  • Widgets.DamageMeterV2 - Updated damage meter widget
  • Widgets.AbnormalityTray - Buff/debuff display widget
  • Widgets.Activities - Activities widget
  • Widgets.Chat - Chat widget
  • Widgets.Wirebug - Wirebug widget

Testing Your Theme

HunterPie supports hot-reloading for themes, which means you can see your changes instantly without restarting the application.

The easiest way to test your theme is by enabling mocked widgets in HunterPie’s development settings:

  1. Enable Development Mode - Read Development Tools to learn to enable development tools
  2. Enable Mocked Widgets - Turn on the “Mock Widgets” option in the development settings
  3. Apply Your Theme - Select your custom theme from the theme settings
  4. View Results - All widgets will display with sample data

Method 2: Testing with Real Game Data

For more realistic testing, you can test your theme while actually playing:

  1. Launch Monster Hunter - Start the game and join a hunt
  2. Apply Your Theme - Ensure your custom theme is selected in HunterPie
  3. Test Widget Behavior - Interact with the game to see how your widgets respond to real data
  4. Modify and Reload - Make changes to your XAML files and they’ll update automatically

Hot-Reload

Saving any file within your loaded theme folder will cause HunterPie to re-load that theme and apply the new styles immediately. In case of any errors, check your HunterPie’s console for more information.

Advanced Customization

Using Markup Extensions

HunterPie provides custom markup extensions to make your life easier:

1
2
<SolidColorBrush x:Key="CustomBrush" 
                 Color="{markup:BrushColor Brush={StaticResource Gray}, Opacity=0.5}"/>

Gradient Brushes

Create sophisticated visual effects with gradient brushes:

1
2
3
4
5
6
7
8
9
10
11
<!-- Linear gradient -->
<LinearGradientBrush x:Key="CustomGradient" StartPoint="0,1" EndPoint="1,1">
    <GradientStop Color="#3498db" Offset="0"/>
    <GradientStop Color="#2980b9" Offset="1"/>
</LinearGradientBrush>

<!-- Radial gradient -->
<RadialGradientBrush x:Key="CustomRadial" RadiusX="1" RadiusY="1">
    <GradientStop Color="#e74c3c" Offset="0"/>
    <GradientStop Color="#c0392b" Offset="1"/>
</RadialGradientBrush>

Color Variations

Create color variations using opacity and system resources:

1
2
3
4
5
<!-- Semi-transparent variant -->
<SolidColorBrush x:Key="CustomColor.Transparent" Color="#80e74c3c"/>

<!-- Using system types -->
<system:Double x:Key="CustomOpacity">0.8</system:Double>
This post is licensed under CC BY 4.0 by the author.