[WIP] UNIStyle: A CSS inspired GUI styling system

Hi folks,

I am developing UNIStyle, a style sheet driven system for UI design.

You describe your UI style in a CSS-like language. In addition to normal css syntax you can use math functions and placeholder variables. These can be set from the inspector which allows for super fast prototyping, even while running the game in the editor. Tweens are also easy to include, custom tween curves are possible, too.

This is not a UI replacement!

UNIStyle sits on top of Unity’s “new” GUI system and controls its design aspect. However, the system is not bound to uGUI in particular and can be adapted to any UI system with a bit of effort.

The whole system is easily extendable, new properties and support for new types and MonoBehaviours can be added with a few lines of code, and be packaged in a shareable theme extension module.

This is the current roadmap:

  • Allow Custom properties

  • Allow Custom types

  • Allow Custom functions

  • Allow Custom theme extension packages

  • Allow Custom variable storage in theme extensions

  • Direct setting of properties (inline styles)

  • Support media queries

  • Loading of external style sheets (non-assets)

  • Adding multiple style sheets to one theme

  • Support all uGUI classes in default extension

  • Parser and selector engine optimization

I would love to read your feedback and any suggestions you might have!

P.S.

For demo purposes I made a simple minesweeper-like game in 160 lines of C# and 100 lines of CSS. Everything graphical, including fonts, coloring and tweens is handled by UNIStyle. The game code is only concerned with the game logic and switching a few css classes on the elements.

The theme is editable via the editor with instant feedback. This makes tweaking very simple.

The demo game:

The editor:

Higher resolution video: Imgur: The magic of the Internet

1 Like

Implemented descendant and sibling selectors and did a bit of refactoring and optimization.

Here is the “loot” demo:

This initializes 250 styled widgets at once and is kind of my performance testbed for now.

The different rarity types are set via a single css class at the root of each item.
Child selectors do the rest of the work.

The popup animation is a custom tween curve:

Very cool! I’ll keep an close eye on this :slight_smile:
Will we be able to create our own “css” attributes or integrate other plugins like Text Mesh Pro? Also is it possible to modify/swap the style file at runtime?

Thanks!
Can you read my mind? :slight_smile:

That’s exactly what I have on the roadmap.

The attributes are currently hardcoded but I am in the process of modularizing the whole system. You will be able to write your own extensions that declare: New attributes, new types, new behaviours.

Hotswapping will definitely be possible. It’s already working “out of the box” but could be optimized.
I am also thinking of runtime parsing of non-asset css files, so you could download new styles from your server to do A/B UI testing, for example.

Wow that sounds really awesome!
Can child selectors override their parent’s attributes like in css?
And is something like media-queries on your roadmap?
What about layout attributes (like flexbox)? :smile:

Absolutely.

You can bet.

Not so sure about that one. I am only manipulating component properties (Transform, UI.Graphic, UI.Text, …) from my system, so I have to work with what Unity provides. Maybe I will add some Layout components for that later, but that is not on top of my list.

Great!! Can’t wait to throw money at this :wink:

Short update, unfortunately no eye candy today:

I just finished reworking the parsing and themeing system which is now fully customizable.
That means: Authors offering UI extensions or developers who are using their own extensions or anyone who wants to extend UNIStyle can now easily do so.

I am using this system myself for developing the core functionality.

This is geared towards programmers who want to customize the system for their own needs. A regular user does not need to touch this code, of course.

As an example here is the current initialization section of the default theme extension and the code required to make the parser understand the lerp function.

/// <summary>
/// The default extension for uGUI functionality and basic types
/// </summary>
public class DefaultExtension : ThemeExtension {

    public override void AddTypeHandlers(Theme t) {
        t.AddTypeHandler(new FloatTypeHandler());
    }

    public override void AddFunctionHandlers(Theme t) {
        t.AddFunctionHandler("lerp", new ColorLerpFunctionHandler());
        t.AddFunctionHandler("lerp", new FloatLerpFunctionHandler());
        t.AddFunctionHandler("lerp", new Vector2LerpFunctionHandler());
        t.AddFunctionHandler("lerp", new Vector3LerpFunctionHandler());
        t.AddFunctionHandler("vec2", new Vec2FunctionHandler());
        t.AddFunctionHandler("vec3", new Vec3FunctionHandler());
        t.AddFunctionHandler("rgba", new RGBAFunctionHandler());
    }

    public override void AddPropertyHandlers(Theme t) {
        t.AddTweenablePropertyHandler("font-size", new FontSizePropertyHandler());
        t.AddTweenablePropertyHandler("color", new ColorPropertyHandler());
        t.AddTweenablePropertyHandler("scale", new ScalePropertyHandler());
        t.AddPropertyHandler("font", new FontPropertyHandler());
        t.AddPropertyHandler("sprite", new SpritePropertyHandler());
    }
}
public class ColorLerpFunctionHandler : GenericParserFunction<Color, Color, float, Color> {
    protected override Color CalculateResult() {
        return arg1 + (arg2 - arg1) * arg3;
    }
}

public class Vector2LerpFunctionHandler : GenericParserFunction<Vector2,Vector2,float,Vector2> {
    protected override Vector2 CalculateResult() {
        return arg1 + (arg2 - arg1) * arg3;
    }
}

public class Vector3LerpFunctionHandler : GenericParserFunction<Vector3,Vector3,float,Vector3> {
    protected override Vector3 CalculateResult() {
        return arg1 + (arg2 - arg1) * arg3;
    }
}

public class FloatLerpFunctionHandler : GenericParserFunction<float,float,float,float> {
    protected override float CalculateResult() {
        return arg1 + (arg2 - arg1) * arg3;
    }
}
1 Like

@stephanu
Any update on your extension? I could use it in an app im currently working on.

+1

To anyone still interested. Unfortunately life got in the way and progress has been less than slow… and with Unity’s new UI on the horizon I don’t know whether it’s worthwile to develop this asset any further.

I would still like to finish this project. So if anyone could give me a thumbs up that would be great. :smile:

1 Like

new Unity uGUI is not going away any sooner, and the reason is UIElement is still in alpha quality, and they will only target runtime when editor mode is finalized. we all know how much time that’d take.

So you can keep working on it and im also super interested in it

1 Like

That’s my thinking as well. I’ll keep this thread up to date.