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.
/plugin marketplace add creator-hian/claude-code-plugins/plugin install unity-plugin@creator-hian-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
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:
Learning Path: C# events → UniRx basics → Observable composition → MVVM with UniRx
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);
}
}
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;
}
}
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);
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());
}
}
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());
}
// 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);
// 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();
}
// 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();
}
}
If migrating from UniRx to R3:
// 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();
using UniRx; → using R3;IntReactiveProperty → ReactiveProperty<int>Observable.ReturnOnMainThread() and Unity's SynchronizationContextObservable.FromAsync()UniRx performance is good but R3 offers:
For performance-critical applications on Unity 2022+, migrate to R3.
For detailed UniRx patterns, refer to:
Migration Guide: See unity-r3 skill for R3 patterns and migration considerations.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.