Dynamic Stylesheets for BSN
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## What problem does this solve or what need does it fill?
As part of the "BYOA" (Bring Your Own Artwork) widget proposal, we propose an extension of BSN to provide a dynamic stylesheets feature. This proposal is based on a private discussion with @cart on discord.
Unlike Bevy Feathers, which is an opinionated widget set focused on building editors, the BYOA collection is intended for games. As such, it is much less opinionated, allowing for different styles (futuristic / cyberpunk, medieval, cartoony, etc.). The visual appearance of the widgets is determined primarily by user-supplied properties and textures: one should be able to download icons directly from kenny.nl, plug them in, and be ready to go. Like Feathers, it is built on the headless widgets foundation.
The mechanism proposed here is somewhat adjacent to the issue of reactivity; everything described here could be implemented with a reactive framework, however this proposal has two major differences: it is much simpler (it only supports simple state changes like hover), and it is serializable. (Reactions cannot be serialized without developing some kind of scripting language VM, which is a longer-term project).
## What solution would you like?
The basic idea is that a dynamic stylesheet will consist of:
* A set of selector conditions which trigger when the entity is in a particular state. For now, we'll support a fixed set of selectors such as DISABLED, HOVERED, PRESSED, CHECKED, SELECTED and FOCUSED.
* Selector conditions can also be boolean expressions which combine multiple selectors.
* With each selector is associated a BSN scene fragment; that is, a partial scene containing properties to patch.
When the state of the entity changes, the stylesheets are re-evaluated: first, the base style is applied, then conditional styles are stacked on top of it. To prevent spurious change detection, the stacking of styles should be performed in the resolved scene, not on the actual entities. The entities should only be updated once the stack of patches is merged, and (ideally) only if the properties actually changed, otherwise the renderer and layout system have to do extra work.
One way to represent the conditional expressions is using a pair of bitfields, similar to the collision group filters used by Avian and Rapier: one bitfield represents the bits that we want to be set, the other is used as a mask to ignore the bits we don't care about. In this scheme, we only allow the first matching condition to be active.
This will also need a mechanism for styling child entities, since many widgets such as sliders and checkboxes consist of multiple parts. Bevy has does not have a CSS-like "class" name property, and the `Name` component is problematic since entities can only have a single name. Instead, we'll need some other way for the stylesheet to specify which child entity a given scene fragment should apply to.
While this might sound a little bit like CSS, it is not: it uses BSN-style syntax, and ECS conventions for states. Also, unlike CSS, there are no global matching rules - stylesheets only apply to the entity holding the asset handle, and it's direct descendants.
## What alternative(s) have you considered?
* A CSS-based solution.
* A more code-based approach.
* This document outlines the general requirements for BYOA widgets, although the proposed solution is somewhat different: https://hackmd.io/@dreamertalin/BJAsbThSMe
@alice-i-cecile @kfc35
Contributor guide
Research direction
Start with issue #25326 and the linked BYOA requirements document; the payload names no repository files, tests, or implementation entry point. Done would require an agreed design for serializable conditional styles, resolved-scene patch stacking, and child-entity targeting before implementation can be scoped.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100