.claude/skills/patterns/SKILL.md
Shared architecture patterns — Config+Data, service pattern, installer pattern, MessagePipe events, reactive disposal. Use when creating new services, configs, events, or installers.
npx skillsauth add punkfuncgames/tetris-clone patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
All ScriptableObject configs follow Data-Oriented Design:
Config SO — thin wrapper:
[CreateAssetMenu(menuName = "GameTemplate/My Config")]
public sealed class MyConfig : ScriptableObject
{
public MyConfigData data;
private void OnValidate()
{
// Editor-time validation only
}
}
Data struct — pure data, no methods, no logic:
[Serializable]
public struct MyConfigData
{
public float duration;
public int maxCount;
public Color defaultColor;
}
Extension methods — logic lives here:
public static class MyConfigDataExtensions
{
public static bool IsValid(this MyConfigData data)
{
return data.duration > 0f && data.maxCount > 0;
}
}
Access pattern: _config.data.fieldName (never _config.PropertyName)
Testing: Create Data structs directly via ScriptableObject.CreateInstance<T>() + struct initializer. No CreateRuntime() factories.
Services implement domain logic. They are pure C# classes with constructor injection.
public sealed class MyService : IMyService, IAsyncStartable, ITickable, IDisposable
{
private readonly IDependency _dep;
private readonly IPublisher<MyEvent> _publisher;
private readonly CompositeDisposable _disposables = new();
public MyService(IDependency dep, IPublisher<MyEvent> publisher)
{
_dep = dep ?? throw new ArgumentNullException(nameof(dep));
_publisher = publisher ?? throw new ArgumentNullException(nameof(publisher));
}
public async UniTask StartAsync(CancellationToken ct)
{
// Initialization logic
}
public void Tick()
{
// Per-frame logic (if ITickable)
}
public void Dispose()
{
_disposables.Dispose();
}
}
Key patterns:
ArgumentNullExceptionIAsyncStartable for async initialization (VContainer auto-calls)ITickable for per-frame logic (replaces Update())IDisposable with CompositeDisposable for cleanupILogService (optional dependency)Installers register services and MessagePipe brokers in LifetimeScope.Configure().
public static class MyInstaller
{
public static void Install(IContainerBuilder builder, MessagePipeOptions options, MyConfig config = null)
{
builder.RegisterEntryPoint<MyService>()
.As<IMyService>();
if (config)
{
builder.RegisterInstance(config);
}
builder.RegisterMessageBroker<MyEvent>(options);
builder.RegisterMessageBroker<MyOtherEvent>(options);
}
}
Key patterns:
Install method with IContainerBuilder + MessagePipeOptionsRegisterEntryPoint for services with IAsyncStartable/ITickable.As<IInterface>() for interface registrationEvents are readonly structs published via MessagePipe brokers.
public readonly struct MyEvent
{
public string Id { get; }
public int Value { get; }
public MyEvent(string id, int value)
{
Id = id;
Value = value;
}
}
Publishing:
_publisher.Publish(new MyEvent("item1", 42));
Subscribing:
_subscriber.Subscribe(e => HandleEvent(e)).AddTo(_disposables);
Converting to Observable (R3):
_subscriber.AsObservable()
.Where(e => e.Value > 0)
.Subscribe(e => HandleEvent(e))
.AddTo(_disposables);
Pure C# classes:
public sealed class MyClass : IDisposable
{
private readonly CompositeDisposable _disposables = new();
public void Setup()
{
_property.Subscribe(OnChanged).AddTo(_disposables);
}
public void Dispose()
{
_disposables.Dispose();
}
}
MonoBehaviours:
public sealed class MyView : MonoBehaviour
{
private void Start()
{
_property.Subscribe(OnChanged).AddTo(this);
}
}
development
WalletModule reference — currency management with BigDouble support, reactive properties, caps, lifetime stats, and persistence. Use when working with currencies, wallets, or financial systems.
development
UnlockConditionModule reference — composable unlock conditions using ScriptableObjects with AND/OR/NOT logic, stat/currency/upgrade/prestige/gamestate/boolean checks, reactive service layer with progress tracking. Use when implementing unlock systems, gating, or progression requirements.
development
UndoModule reference — command pattern with undo/redo stacks, command merging, and reactive state. Use when implementing undo/redo, undoable actions, or command patterns.
tools
Unity UI Toolkit reference — UXML documents, USS styling, MVVM pattern (ViewModel + Presenter), custom VisualElements, responsive layout, animations, performance guidelines, and complete Figma-to-UI-Toolkit property mapping. Use when building or modifying UI with UI Toolkit, creating UXML/USS files, writing ViewModels or Presenters, designing screens/panels/components, or converting Figma designs to UI Toolkit.