> 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/reference/extending.md).

# Extending

Adding your own converters, modifiers, providers and routes.

The pipeline is made of interfaces, and every stage of it accepts your own implementations. Nothing here requires a partial class, a code generator or a build step: implement an interface, and the type is discovered.

## What you can add

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Custom Converters</strong></td><td>Cross a type boundary, with a conversion in each direction.</td><td><a href="/binding-system-3/reference/extending/converters.md">Custom Converters</a></td><td><a href="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FhnblJ1HBb3D1vMgEJ47Y%2FScreenshot%202026-09-27%20at%2011.20.28.png?alt=media&amp;token=8b3792e0-5a67-4a60-be21-59e8102681c3">Screenshot 2026-09-27 at 11.20.28.png</a></td></tr><tr><td><strong>Custom Modifiers</strong></td><td>Transform a value inside one type, with bindable parameters.</td><td><a href="/binding-system-3/reference/extending/modifiers.md">Custom Modifiers</a></td><td><a href="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2Fgit-blob-2ca76a6c3a7b1f7e0361e0aba8b959e8bb44c9cd%2Fcover-pipeline.svg?alt=media">cover-pipeline.svg</a></td></tr><tr><td><strong>Accessor Providers</strong></td><td>Expose paths that are not ordinary fields or properties.</td><td><a href="/binding-system-3/reference/extending/accessor-providers.md">Accessor Providers</a></td><td><a href="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2Fgit-blob-9e654bbbbfb909a765f9214ac562f442692cb2e6%2Fcover-reference.svg?alt=media">cover-reference.svg</a></td></tr><tr><td><strong>Value Providers</strong></td><td>Add a way for a modifier or parameter to obtain a value.</td><td><a href="/binding-system-3/reference/extending/value-providers.md">Value Providers</a></td><td><a href="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2Fgit-blob-bb43a743ab7c41ec26f4defdfcd891440b43a419%2Fcover-binding.svg?alt=media">cover-binding.svg</a></td></tr><tr><td><strong>Field Rerouting</strong></td><td>Redirect every binding on a field through another member.</td><td><a href="/binding-system-3/reference/extending/field-rerouting.md">Field Rerouting</a></td><td><a href="https://3048705056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLUfBXR02sJ5i0MxwYbaV%2Fuploads%2FsyREZrQWGaacS91FNlhH%2FScreenshot%202026-09-28%20at%2018.25.53.png?alt=media&amp;token=a13dd31a-685f-45ee-8b0f-6a12e349f03f">Screenshot 2026-09-28 at 18.25.53.png</a></td></tr></tbody></table>

## Discovery and registration

Custom converters, modifiers and providers are found and registered automatically. The scan runs on import and after an upgrade, and it is controlled by three settings in **Project Settings ▸ Binding System ▸ Configuration ▸ General Settings**:

<table><thead><tr><th width="290">Setting</th><th>What it does</th></tr></thead><tbody><tr><td><strong>Auto Register Converters</strong></td><td>On by default.</td></tr><tr><td><strong>Auto Register Modifiers</strong></td><td>On by default.</td></tr><tr><td><strong>Auto Register Providers</strong></td><td>On by default.</td></tr></tbody></table>

Register manually when the object is built at runtime, or when you want explicit control:

```csharp
ConvertersFactory.Register<float, string>(new SecondsToClockConverter());
ModifiersFactory.Register<ScaleModifier>();
AccessorsFactory.RegisterAccessorProvider(new MyAccessorProvider());
```

## Conventions worth following

<table><thead><tr><th width="270">Do this</th><th>Why</th></tr></thead><tbody><tr><td>Mark the class <code>[Serializable]</code></td><td>Otherwise Unity cannot store your configured instance in the binding.</td></tr><tr><td>Give it a short, unique <code>Id</code></td><td>It is the display name in the bind menu, and the key the factory registers it under. Two extensions sharing one <code>Id</code> collide: the modifier registry throws, and the converter registry logs an error and overwrites.</td></tr><tr><td>Write a real <code>Description</code></td><td>It is the tooltip. This is the only documentation most users will read.</td></tr><tr><td>Implement <code>ShortDataDescription</code></td><td>The one-line summary on a collapsed row. A stack of five modifiers is unreadable without it.</td></tr><tr><td>Make parameters <code>Bind&#x3C;T></code> or <code>ReadOnlyBind&#x3C;T></code></td><td>Costs nothing, and makes your extension composable with everything else.</td></tr><tr><td>Pick the right one of the two</td><td>A converter's two type arguments must differ. If the type does not change, it is a modifier, not a converter.</td></tr><tr><td>Be honest about <code>IsSafe</code></td><td>An unsafe converter that claims to be safe turns a handled fallback into an exception.</td></tr><tr><td>Declare <code>IsDynamic</code> if you are</td><td>If your output can change without your input changing, say so, or <a href="/binding-system-3/project-tools/performance/phased-bindings.md">phased bindings</a> will cache you incorrectly.</td></tr></tbody></table>

{% hint style="danger" %}
**What breaks a saved binding is renaming the class, not the `Id`.** A configured converter or modifier is stored with `[SerializeReference]`, which persists the **type**: its class name, its namespace and its assembly. Rename any of those three, or move the class to another assembly, and every binding holding one loads with an empty slot. The [Validator](/binding-system-3/project-tools/diagnostics/validator.md) reports it as a missing converter or modifier type, which is the only warning you get.

Unity's own `[MovedFrom]` attribute is the migration path, and it has to go on before the rename ships:

```csharp
using UnityEngine.Scripting.APIUpdating;

[MovedFrom(true, sourceClassName: "SecondsToClock")]
[Serializable]
public class SecondsToClockConverter : IConverter<float, string> { }
```

Changing the `Id` is a different and much smaller matter: existing bindings keep working, because nothing reads the `Id` to rebuild them. What moves is where the extension appears in the bind menu, and any [template](/binding-system-3/pipeline/templates.md) row that was listed under the old name.
{% endhint %}

## Working examples in the package

Import them from the Package Manager, under **Samples**:

<table><thead><tr><th width="290">Sample</th><th>What it shows</th></tr></thead><tbody><tr><td><strong>Additional Converters</strong></td><td><code>EnumToIntConverter</code>, <code>HexColorConverter</code>. Both heavily commented.</td></tr><tr><td><strong>Additional Modifiers</strong></td><td>Rounding modifiers, <code>StringPadding</code>, <code>TrimModifier</code>, a logging modifier.</td></tr><tr><td><strong>Bindings Demo</strong></td><td>A playable scene, including a propagate modifier and a PID controller written as samples.</td></tr></tbody></table>

They are the fastest way in: copy the closest one and change what it does.

## Where extensions should live

Anywhere in your project. If your code is in an assembly definition, it needs a reference to `Postica.BindingSystem.Runtime`, which auto referencing already provides unless you turned it off.

Do not put extensions inside the package folder. An update overwrites it.
