> For the complete documentation index, see [llms.txt](https://postica.gitbook.io/binding-system-3/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://postica.gitbook.io/binding-system-3/tutorials/settings-panel.md).

# A Settings Panel That Drives the Scene

One slider, several objects, and a named value in between.

A settings panel has an awkward shape. The slider is in the UI, the things it changes are all over the scene, and the value has to survive both of them. The usual answer is a `Settings` singleton, an event, and a subscriber on every object that cares.

This tutorial replaces all three with a **bind variable**: a named value that bindings refer to without referring to each other. Nothing in the panel knows a light exists, and no light knows a slider exists.

## What you will build

A Brightness slider that drives two lights and a level readout at once, with the value held in a variable. It works while the game runs, and it also works with the game stopped.

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FUrSEHrOuzIcZ7h5hdl3l%2FScreenshot%202026-09-26%20at%2015.12.23.png?alt=media&amp;token=b247f08c-b934-4eef-bcb2-01c8cd6d2c2a" alt=""><figcaption><p>One slider, one variable, three things in the scene following it</p></figcaption></figure>

**About 20 minutes.**

## What you need

An empty scene. Everything is created as you go, and nothing is written in code.

## 1. Make something worth lighting

Add **GameObject ▸ 3D Object ▸ Plane**, then **GameObject ▸ 3D Object ▸ Cube** and lift it so it sits on the plane.

A new scene already has a **Directional Light**. Add a second one, **GameObject ▸ Light ▸ Point Light**, and drop it near the cube so its contribution is obvious.

You now have two independent light sources, which is the point: one setting is about to move both.

## 2. Build the panel

Add **GameObject ▸ UI ▸ Slider**. Unity creates a Canvas and an EventSystem around it.

Select the Slider and, in the Inspector, leave **Min Value** at `0` and **Max Value** at `1`.

Add **GameObject ▸ UI ▸ Image** as a child of the Canvas, name it `Readout`, and make it a short wide rectangle under the slider. Set its **Source Image** to `UISprite`, its **Image Type** to **Filled**, **Fill Method** to **Horizontal** and **Fill Origin** to **Left**.

That is the whole panel: one control and one readout. Neither has a script.

## 3. Bind the first light, and create the variable while you are there

Select the **Directional Light**. Right click the **Intensity** label and choose **Enable Binding**.

Click the **hexagon toggle** that appears beside the label, and the field becomes a bind row. Instead of dragging an object onto it, open the **source view** ![](https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FSAO4O5wF9yAPRUyFHp9H%2Fimage.png?alt=media\&token=c606b4a2-921d-46dd-98e1-2386781e98c2): it is the toggle on the path button whose tooltip reads *Show Bind Source Field*, if the view is not already showing. It has a mode dropdown, and it reads **From Object**.

Change that dropdown to **From Variable**.

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FyD5zOhRdtDKpgTIVvqtn%2FScreenshot%202026-09-26%20at%2015.01.22.png?alt=media&amp;token=25bfcd00-f7e5-4cf4-8815-76e79b68c821" alt=""><figcaption><p>The source view, switched from From Object to From Variable</p></figcaption></figure>

A variable picker appears with two small buttons beside it. Click the one whose tooltip reads *Create a new variable and assign it here*.

In the popup:

* pick **Single** as the type
* set **Name** to `masterBrightness`
* set **Scope** to `Settings`
* press **Create Variable**

The popup closes and the variable is already assigned to this binding. Now click the path button. There is exactly one entry, **Variable Value**, because a variable holding a plain number has no members to walk into: the number itself is the only bindable thing. Pick it.

The row now reads V`ar: master Brightness`.

{% hint style="info" %}
There was no container in the scene a moment ago. Creating the variable made one: a hidden GameObject carrying the scene's variable list. You never have to place it, and nothing in the scene refers to it by name.
{% endhint %}

## 4. Give the light a sensible range

A brightness setting runs 0 to 1. A directional light at intensity 1 is already bright, and at 0 the scene is black, so map the one range onto the other rather than changing what the setting means.

Open the bind menu and, under **Add Modifier**, choose **Remap Range**. Set:

* **In Min** `0`, **In Max** `1`
* **Out Min** `0.2`, **Out Max** `2`

The modifier row now reads `[0, 1] → [0.2, 2]`. **Clamp** is on by default, so a setting outside 0 to 1 cannot push the light past those ends.

## 5. Make it work with the game stopped

Open the bind menu again, choose **Update Points ▸ Update On**, and tick **EDITOR** alongside **UPDATE**.

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FICJqTUNER6OCgVLFcRdo%2FScreenshot%202026-09-26%20at%2015.02.55.png?alt=media&amp;token=b8b08a7b-15b0-4d00-81ce-72f2a299d954" alt="" width="563"><figcaption><p>EDITOR ticked next to UPDATE</p></figcaption></figure>

Now open **Window ▸ Binding System ▸ Bind Variables**. The window lists every container in the project, and yours is there with `masterBrightness` under the `Settings` scope.

Drag its value from 0 to 1 and **watch the scene light up in the Scene view, with the game stopped**.

{% hint style="warning" %}
Do not expect the Slider to do this. A UI Slider needs the EventSystem to process a drag, and that only runs in play mode. **EDITOR** drives the binding, not the control: it means the connection is live while you author, so you can dial a value in the variable and see the result without a play-stop cycle.
{% endhint %}

## 6. Fan the same variable out

This is the step that pays for the variable. Do the same thing twice more, and notice that neither new binding refers to the first one.

**The point light.** Select it, right click **Intensity**, **Enable Binding**, click the hexagon, open the source view, set the mode to **From Variable**. This time `masterBrightness` is already in the picker: choose it, pick **Variable Value** on the path button, add a **Remap Range** with **Out Min** `0` and **Out Max** `5`, and tick **EDITOR**.

**The readout.** Select `Readout`, right click **Fill Amount**, **Enable Binding**. Open the bind path menu and this time use the shortcut: under **Other Sources ▸ From Variable ▸ Settings**, pick `masterBrightness`. That sets the source mode, the variable and the path in one click. No modifier: the setting is already 0 to 1, and so is `fillAmount`. Tick **EDITOR**.

{% hint style="info" %}
**Other Sources** only appears on a binding with no path yet. Once a path is set, switching source mode from the menu would silently drop it, so that change is left to the source view where it is explicit.
{% endhint %}

Go back to the Bind Variables window and drag the value again. Both lights and the readout move together, still with the game stopped. Three bindings, one value, no references between them.

## 7. Bind the slider both ways

The slider is the only piece left, and it is the only one that has to write.

Select the Slider, right click **Value**, and choose **Enable Binding**. Set the source to `masterBrightness` the same way, with **Variable Value** as the path.

Now click the **mode icon** at the left of the bind row until it reads ![](https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FE4JzX2s4oF6LzZufo6bg%2Fimage.png?alt=media\&token=da8d9a4d-6300-4f60-b9c0-3167d6d97941).

<figure><img src="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FXFI6i3SpoKb0K03wlqPy%2FScreenshot%202026-09-26%20at%2015.09.53.png?alt=media&amp;token=24ee4af7-0024-4e75-bc49-c2d765bf175d" alt="" width="563"><figcaption><p>The slider's binding in ReadWrite mode</p></figcaption></figure>

Leave the update point at **UPDATE** and leave **EDITOR** off. Writing at edit time would let the slider's stored value overwrite the one you are dialling in.

## 8. Press play

Drag the slider. Both lights and the readout follow it, and so does the value in the Bind Variables window.

Stop, and change the variable in the window instead. The slider handle moves to match. That is the read half of `RW` doing its job: the slider is a view of the variable, not the owner of it.

## What just happened

**The variable is the only thing anything refers to.** Four bindings name `masterBrightness`. None of them names another object in the scene. Delete the point light and the other three carry on. Add a fourth target tomorrow and nothing existing changes. That is the difference between a shared value and a web of direct references, and it is the reason [Bind Variables](/binding-system-3/overview/bind-variables.md) exist.

**The variable's value is directly readable and writable.** A variable holding a `UnityEngine.Object` is a source you walk a path through. A variable holding a plain value is the value itself, reached by the special **Variable Value** path, and that accessor both reads and writes. That is why the slider could be `RW` against it with nothing else in the way.

**`RW` on a proxy binding is two stages, not one.** At the update point the engine reads the source and pushes it into the field, then, *after* your `Update` code has run, it reads the field back and writes it to the source. The slider is refreshed before anything else in the frame touches it, and whatever the drag left in it is written out afterwards. [Bind Modes and Update Points](/binding-system-3/overview/modes-and-updates.md) has the full stage list.

**EDITOR is a real update point, and it is the reason this is worth doing.** A settings panel you cannot see the effect of until you press play is a settings panel you tune slowly. Ticking EDITOR on the read-only bindings makes the connection live while authoring. It is deliberately off on the writing one, because at edit time the two directions have no frame boundary to keep them apart.

**Nothing here is scene-specific.** The variable lives in this scene, so a prefab using `masterBrightness` works in any scene that defines it, and gets that scene's value. Put it in a **Bind Variables Asset** instead and it becomes project-wide, surviving scene loads. Where two containers define the same name, the one registered later wins, which makes a scene variable a per-scene override of a project default.

## Try changing this

**Rename the variable.** In the Bind Variables window, change `masterBrightness` to `brightness`. All four bindings keep working. Each variable carries a stable id that a rename does not touch, and the bindings refer to the id, not to the text.

**Delete the variable.** Now the bindings report *Variable 'masterBrightness' not found* on the row rather than failing silently at runtime. Undo brings it back. This is worth seeing once, because it is what a missing variable looks like in someone else's scene.

**Add a readout label.** Put a **Text** or **TextMeshPro** object in the panel and bind its text to the same variable. The `float` to `string` conversion is chosen for you; add a **Text Template** modifier with a template like `Brightness {x|truncate:4,}` to cut the number down to two decimals. Five bindings on one variable now, and the panel still has no script.

**Turn it around.** Everything here has the objects pull from the variable. Open the Bind Variables window, expand `masterBrightness` and add an [On Value Change](/binding-system-3/overview/bind-variables.md#on-value-change) target instead: the wiring then lives on the variable, and it runs when the value moves rather than every frame. Worth trying once to feel which shape suits which value.

**Give the point light its own scale.** Change its Remap Range **Out Max** from `5` to `1`. Both lights still follow the one setting, but they no longer follow it by the same amount. The shared thing is the intention, not the number.

## Related pages

* [Bind Variables](/binding-system-3/overview/bind-variables.md): containers, scopes, ids, and registering your own.
* [Sources](/binding-system-3/overview/sources.md): the Variable mode next to the other seven ways to find a source.
* [Bind Modes and Update Points](/binding-system-3/overview/modes-and-updates.md): `RW`, and what EDITOR actually runs.
* [Modifier Catalogue](/binding-system-3/pipeline/modifier-catalogue.md): Remap Range and the rest.
* [Pinned Paths](/binding-system-3/overview/pinning.md): the other way to make a source reusable, by path rather than by name.
