npx claudepluginhub creator-hian/claude-code-plugins --plugin unity-pluginWant just this skill?
Then install: npx claudepluginhub u/[userId]/[slug]
UniRx (Reactive Extensions) library expert for legacy Unity projects. Specializes in UniRx-specific patterns, Observable streams, and ReactiveProperty. Use for maintaining existing UniRx codebases. For new projects, use unity-r3 skill instead.
This skill uses the workspace's default tool permissions.
references/unirx-patterns.mdUnity UniRx - Reactive Extensions for Unity (Legacy)
Overview
UniRx is a legacy Reactive Extensions library for Unity, widely used in pre-2022 Unity projects. For new projects, prefer R3 (unity-r3 skill).
Library: UniRx by neuecc
UniRx vs R3: UniRx is the predecessor to R3. R3 offers better performance and modern C# features, but UniRx is still maintained and used in many existing projects.
Status: ⚠️ Legacy library - Maintained but not actively developed. New projects should use R3.
Foundation Required: unity-csharp-fundamentals (TryGetComponent, FindAnyObjectByType), csharp-async-patterns (async fundamentals), unity-async (Unity context)
Core Topics:
- Observable sequences and observers
- Reactive operators and transformations
- ReactiveProperty and ReactiveCommand
- UniRx-specific Unity integration
- MessageBroker pattern
- MainThreadDispatcher
Learning Path: C# events → UniRx basics → Observable composition → MVVM with UniRx
Quick Start
Basic Observable Patterns
using UniRx;
using UnityEngine;
public class Example : MonoBehaviour
{
void Start()
{
// Button clicks
button.OnClickAsObservable()
.Subscribe(_ => Debug.Log("Clicked"))
.AddTo(this);
// Update loop as observable
Observable.EveryUpdate()
.Where(_ => Input.GetKeyDown(KeyCode.Space))
.Subscribe(_ => Jump())
.AddTo(this);
// Time-based
Observable.Timer(TimeSpan.FromSeconds(1))
.Subscribe(_ => Debug.Log("1 second passed"))
.AddTo(this);
}
}
ReactiveProperty (UniRx)
using UniRx;
public class Player : MonoBehaviour
{
// IntReactiveProperty is UniRx-specific
public IntReactiveProperty Health = new IntReactiveProperty(100);
public ReadOnlyReactiveProperty<bool> IsDead;
void Awake()
{
IsDead = Health
.Select(h => h <= 0)
.ToReadOnlyReactiveProperty();
IsDead.Where(dead => dead)
.Subscribe(_ => OnDeath())
.AddTo(this);
}
public void TakeDamage(int amount)
{
Health.Value -= amount;
}
}
When to Use
Unity UniRx (This Skill)
- ✅ Maintaining existing UniRx projects
- ✅ Unity 2019 - 2021 LTS projects
- ✅ Projects with large UniRx codebase
- ✅ Teams experienced with UniRx
When to Choose R3 Instead
- ✅ New projects (Unity 2022+)
- ✅ Better performance requirements
- ✅ Async enumerable integration needed
- ✅ Modern C# feature support
UniRx-Specific Features
MessageBroker Pattern
using UniRx;
// Global event system
public class GameEvents
{
public struct PlayerDiedEvent { }
public struct ScoreChangedEvent { public int NewScore; }
}
// Publish
MessageBroker.Default.Publish(new GameEvents.PlayerDiedEvent());
// Subscribe
MessageBroker.Default.Receive<GameEvents.PlayerDiedEvent>()
.Subscribe(_ => ShowGameOver())
.AddTo(this);
ReactiveCommand
using UniRx;
public class ViewModel
{
// Command can be enabled/disabled reactively
public ReactiveCommand AttackCommand { get; }
private IntReactiveProperty mStamina = new IntReactiveProperty(100);
public ViewModel()
{
// Command only enabled when stamina > 10
AttackCommand = mStamina
.Select(s => s > 10)
.ToReactiveCommand();
AttackCommand.Subscribe(_ => ExecuteAttack());
}
}
MainThreadDispatcher
using UniRx;
using System.Threading.Tasks;
async Task DoBackgroundWork()
{
// Do background work
await Task.Run(() => HeavyComputation());
// Return to Unity main thread
await UniRx.MainThreadDispatcher.SendStartCoroutine(UpdateUI());
}
Common UniRx Patterns
UI Event Handling
// Input field with validation
inputField.OnValueChangedAsObservable()
.Where(text => text.Length >= 3)
.Throttle(TimeSpan.FromMilliseconds(500))
.Subscribe(text => ValidateInput(text))
.AddTo(this);
// Toggle button
toggle.OnValueChangedAsObservable()
.Subscribe(isOn => OnToggleChanged(isOn))
.AddTo(this);
Coroutine Integration
// Convert coroutine to observable
Observable.FromCoroutine<string>(observer => GetDataCoroutine(observer))
.Subscribe(data => ProcessData(data))
.AddTo(this);
IEnumerator GetDataCoroutine(IObserver<string> observer)
{
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
observer.OnNext(www.downloadHandler.text);
observer.OnCompleted();
}
MVVM Pattern (UniRx)
// ViewModel
public class PlayerViewModel : IDisposable
{
private CompositeDisposable mDisposables = new CompositeDisposable();
public IReadOnlyReactiveProperty<int> Health { get; }
public IReadOnlyReactiveProperty<string> Status { get; }
public ReactiveCommand HealCommand { get; }
private IntReactiveProperty mHealth = new IntReactiveProperty(100);
public PlayerViewModel()
{
Health = mHealth.ToReadOnlyReactiveProperty().AddTo(mDisposables);
Status = mHealth
.Select(h => h <= 30 ? "Critical" : h <= 70 ? "Wounded" : "Healthy")
.ToReadOnlyReactiveProperty()
.AddTo(mDisposables);
HealCommand = mHealth
.Select(h => h < 100)
.ToReactiveCommand()
.AddTo(mDisposables);
HealCommand.Subscribe(_ => mHealth.Value += 20).AddTo(mDisposables);
}
public void Dispose()
{
mDisposables.Dispose();
}
}
Migration to R3
If migrating from UniRx to R3:
API Differences
// UniRx
IntReactiveProperty health = new IntReactiveProperty(100);
ReadOnlyReactiveProperty<bool> isDead = health
.Select(h => h <= 0)
.ToReadOnlyReactiveProperty();
// R3 (nearly identical)
ReactiveProperty<int> health = new ReactiveProperty<int>(100);
ReadOnlyReactiveProperty<bool> isDead = health
.Select(h => h <= 0)
.ToReadOnlyReactiveProperty();
Key Migration Points
- Namespace:
using UniRx;→using R3; - Types:
IntReactiveProperty→ReactiveProperty<int> - MessageBroker: No direct equivalent in R3 (implement custom or use event aggregator)
- MainThreadDispatcher: R3 uses
Observable.ReturnOnMainThread()and Unity'sSynchronizationContext
Integration with Other Skills
- unity-r3: Modern alternative for new projects
- unity-unitask: UniRx can work with UniTask via conversion methods
- unity-vcontainer: Inject ReactiveProperty as dependencies
- unity-ui: Bind UniRx observables to UI elements
- unity-async: Bridge async operations with
Observable.FromAsync()
Platform Considerations
- WebGL: Full support with frame-based timing
- Mobile: Efficient for UI and event handling
- All Platforms: Mature and battle-tested
Best Practices
- Always use AddTo(): Prevent memory leaks with automatic disposal
- Use CompositeDisposable: Group related subscriptions for cleanup
- Throttle/Debounce input: Prevent excessive processing
- ReactiveProperty for state: Better than manual event raising
- MessageBroker for global events: Decoupled communication
- MainThreadDispatcher awareness: Always return to main thread for Unity APIs
- Consider migration to R3: For long-term projects on Unity 2022+
Performance Notes
UniRx performance is good but R3 offers:
- 30-50% better allocation performance
- Struct-based observers (zero allocation)
- Better GC pressure management
- Async enumerable integration
For performance-critical applications on Unity 2022+, migrate to R3.
Reference Documentation
UniRx Advanced Patterns
Detailed UniRx patterns:
- MVVM architecture with ReactiveProperty
- Event aggregator and state management
- Custom operator creation
- Error handling strategies
External Resources
Migration Guide: See unity-r3 skill for R3 patterns and migration considerations.
Similar Skills
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.