Introduction
What Reactive is, why it beats BSML, and where to start.
Reactive is a UI library for Beat Saber mods. You write the view in C#, next to the code that drives it, as a tree of components. The values that change over time live in states, and whatever reads a state follows it. No markup, no code-behind, nothing to refresh by hand.
The whole idea fits in one component. A label shows a number, and a button increments it:

class Counter : ReactiveComponent {
protected override GameObject Construct() {
var count = Remember(0);
return new Layout {
FlexController = {
FlexDirection = FlexDirection.Column,
AlignItems = Align.Center,
JustifyContent = Justify.Center,
Gap = 2.pt
},
Children = {
new Label {
FontSize = 9f,
sText = count.Map(x => x.ToString())
},
new BsPrimaryTextButton {
Text = "+1",
OnClick = () => count.Value++
}
}
}.Use();
}
}The button only changes count.Value. It doesn't know a label exists. The label reads the count through sText
and follows on its own. Everything else in these docs is that idea applied to layout, input, animation and lists.
Why not BSML
BSML describes a view in XML and wires it up through a class behind it. That is fine for a static panel, and gets harder the more the UI has to change while it's open.
Reactivity
In BSML, a value that changes needs a [UIValue] property and a NotifyPropertyChanged call in every setter that
affects it. In Reactive you bind once. Here one volume state drives the percentage, the meter, the slider and the
warning below it, and none of them knows about the others:
Layout
Layout uses flexbox, the same model as the web, and when flexbox isn't enough, you can write your own controllers. Drag this slider to see blocks of different sizes wrap onto new rows and grow to fill them, which BSML's layout groups can't do:
Animations
BSML has no animations of its own, so you write the loop yourself. Reactive can animate both a value and a target. An animated state eases a value toward its new one, and anything bound to it follows. An animation player plays an animation on a target, like fading, scaling or spinning a component. Try this grid, where each tile eases its scale and color as a wave runs across it:
Performance
BSML parses its markup on every mount, and its custom-list parses a new cell for each row that comes into view. A
Table reuses its cells instead. In our PC benchmarks, jumping far
through a table of 100000 rows is 16 times faster, and mounting is 2.8 to 7.8 times faster. Below you can see the
buttons jump through 100000 rows, all drawn by the few cells that fit on screen:
Performance Benchmarks has every number. You do give up BSML's hot reload and rebuild instead, though the Playground covers quick experiments.
Integration
BSML connects markup to code through strings, so a typo only shows up when the view is parsed. A Reactive view is plain C# in one class, so a typo is a compile error, and your IDE can navigate and rename through it.
In Debug, the Reactive compiler generates every s-property, so your IDE suggests them as you type. Release keeps only the ones you use, as Compiler Internals explains.
Where to start
Getting Started covers installing Reactive, and Coming from BSML covers migrating an existing UI.



