Welcome to Toned, an extension module to Elttob’s Fusion that will completely change the way you design your UI. No longer is there a need to mix your functionality with design and have components filled with fluff. Toned offers a custom style language used to design your UIs far more rapidly than any other existing solution.
Style Sheets
With Toned you can create style sheets that get directly applied to your Fusion instances. Here’s an example of an in-line style sheet being applied to a ScreenGui created with Fusion.
-- All TextLabels receive a white background color
.TextLabel {
BackgroundColor3: #FFFFFF;
}
-- Instances named "Hello" receive a green text color
@Hello {
TextColor3: [0, 255, 0];
}
-- Instances named "Goodbye" receive a red text color
@Goodbye {
TextColor3: [255, 0, 0];
}
We style all TextLabels by setting their backgrounds to white and then independently set text colors based on instance names. This is just a taste of how powerful Toned is. For a full explanation of style sheets, visit the style sheet documentation.
Documentation
The entire documentation for Toned is available here.
Beta
Toned is currently in beta testing and therefore features may change in the future. There also may be bugs that should be reported and other areas of the module still requiring polish.
Glad it looks useful. I’ve been using it myself on my own UIs and have found it completely changes the way you design your UI and leaves you with way more time to focus on functionality and user experience.
I thought about having the language itself be stand-alone but the problem is it doesn’t really make sense. If you’re creating your own UI in Roblox rather than by script then you’ve already designed your UI the way you want and there really isn’t a need for a module like this. There may be a Roact port or something in the future though as I’m sure it could be handy there too. There’s still a lot of features I intend to add like contexts (for passing in data to style sheets) and selector grouping (to have more precise selection options).
What I meant was, you could apply styles to buttons with classes, that way in the future, if you decide to change the style and make them look different, they all change at once.
It can also be helpful (in combination with a plugin) to auto style new buttons that you create.
You can do the same in HTML but nobody does because CSS exists. Why take the longer route of rewriting the exact same properties for every instance and filling all your functional code with fluff when you could just do that separately in a way more efficient manner?
Is this implying hex and RGB are both supported to set colors?
Also, I feel like the syntax should be like this:
TextLabel {} -- All TextLabels
.Title {} -- GuiObject named Title
TextLabel.Title {} -- TextLabel named Title
TextLabel .Title {} -- GuiObjects named Title inside a TextLabel
Yes both Hex and RGB are supported. If you check out the documentation it explains lists more and how they dynamically conform to expected types. The syntax is still very open to change I’m looking for feedback so I appreciate that. The current language design also ignores white space and I personally prefer that over having certain syntax dependent on white space like in your example. In v0.1.4 grouping is being added using the + operator. This adds the ability to check for multiple selectors at once:
.TextLabel {} -- All TextLabels
@Title {} -- GuiObject named Title
.TextLabel + @Title {} -- TextLabel named Title
TextLabel > @Title {} -- GuiObjects named Title inside a TextLabel
I don’t think I’m comfortable writing style sheets entirely within a string—this removes the ability to use autocomplete and automatic formatting in VSCode. Manually typing each block will be a process. Additionally, users may want values in style sheets to be dynamic and respect state objects. Consider creating a Luau style sheet mode:
local Class = Toned.Class
local Named = Toned.Named
{ -- One style sheet
Class "TextLabel" {
BackgroundColor3 = Color3.fromHex("#FFFFFF")
},
Named "Hello" {
TextColor3 = Color3.new(0, 1, 0)
},
Named "Goodbye" {
TextColor3 = Color3.new(1, 0, 0)
},
}
I haven’t looked too deep into the documentation, so this may make little sense—but consider supporting custom properties?
I’m curious to know what your Fusion workflow looks like. I have a bunch of modules that return functions that produce components. Components can call other components within them as well. Components have properties that decide how they look and act, and I have several databases for state objects that higher-level components reflect. I don’t think I’ve ever had to struggle with components being “filled with fluff,” so I’d love some insight into how you do things
The initial design for Toned looked very similar to what you described. The problem was that I wanted to design something that was unique, fast to use, and made sense in the context of UI design. While at first it might seem daunting writing style sheets in a string (trust me I agreed with you 100% when I first thought of this), once you learn the language it becomes secondhand. You can design your UI far quicker than using standard Luau syntax. This module is still in beta but there are plans on better error handling so you can better understand where you may have made a mistake in writing your code.
For dynamic state objects we already offer a solution. You simply don’t use Toned for styling. Let’s say you have a Text property on a TextLabel that needs to change with state. Instead of defining that property in the style sheet you just define it how you normally would with Fusion. You would use Toned for static properties that don’t change. In v0.1.4 we are adding contextual style sheets which allow you to support custom properties. It looks something like this:
I consider a factory-style workflow "fluff" and don't support that style of design. It's ugly in my opinion and even you describing the entire system sounds exhausting. That said you already designed an entire framework for your Fusion UI and that's great but many other casual users don't have your same workflow and this offers a public alternative.