About unity-unitask-design
A reference module for Unity developers using UniTask 2.5.10, covering timing, cancellation, composition, and adapters for Unity asynchronous operations. Rules include source locations to help verify behavior during implementation and review.
Key features
- 01UniTask and async method rules
- 02PlayerLoopTiming and delay behavior
- 03CancellationToken handling
- 04Composition with WhenAll and WhenAny
- 05Adapters for Unity async operations
Use cases
- 01Write or review UniTask async methods
- 02Choose PlayerLoopTiming and handle cancellation
- 03Compose multiple asynchronous operations
- 04Adapt Unity async operations to UniTask
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ besty0728/ unity-skills --skill unity-unitask-designAfter installing, type/unity-unitask-designin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
ASYNCENUMERABLE.mdBASICS.mdCANCELLATION.mdCOMPOSITION.mdCONVERSION.mdPITFALLS.mdPLAYERLOOP.mdTRIGGERS.mdDetails
From the project READMEBefore calling any skill in this module: if you are about to call a skill with parameters guessed from its name or description, STOP — read this file (or fetch its schema via
GET /skills/recommend?includeSchema=true) first. If you already have the parameter definitions from recommend/schema, you may proceed straight to dryRun.
Triggers
- Writing or reviewing async UniTask code
- Choosing PlayerLoopTiming
- Handling CancellationToken
- Composing WhenAll/WhenAny
- 编写或审查 async UniTask 代码、选择 PlayerLoopTiming、处理 CancellationToken、组合 WhenAll/WhenAny
UniTask - Design Rules
Advisory module. Every rule is distilled from Cysharp UniTask source at:
- 2.5.10 —
[email protected](Unity 2018.4 baseline; actively used with 2022.3 / Unity 6)
Each rule cites a concrete file/line so the reasoning is auditable and the AI does not improvise against stale memory.
Mode: Documentation only — no REST skills to gate; load freely under any operating mode (Approval / Auto / Bypass).
When to Load This Module
Load before writing or reviewing any of:
- Any
async UniTask/async UniTask<T>/async UniTaskVoidmethod signature .Forget(),.AttachExternalCancellation(token),.SuppressCancellationThrow()chainingUniTask.Yield,UniTask.NextFrame,UniTask.Delay,UniTask.WaitForEndOfFrame,UniTask.WaitForFixedUpdateUniTask.WaitUntil,UniTask.WaitWhile,UniTask.WaitUntilValueChanged,UniTask.WaitUntilCanceledUniTask.WhenAll,UniTask.WhenAny,UniTask.WhenEachUniTask.SwitchToMainThread,UniTask.SwitchToThreadPool,UniTask.RunAsyncOperation.ToUniTask(),UnityWebRequest.SendWebRequest().ToUniTask(),Coroutine.ToUniTask()this.GetCancellationTokenOnDestroy(),GetAsyncStartTrigger()and otherAsyncTrigger*extensionsUniTaskCompletionSource/UniTaskCompletionSource<T>manual completion sourcesIUniTaskAsyncEnumerable<T>/UniTaskAsyncEnumerable/AsyncReactiveProperty<T>/Channel<T>- WebGL-specific async code paths where
Task.Run/SwitchToThreadPoolare forbidden
Critical Rule Summary
| # | Rule | Source anchor |
|---|---|---|
| 1 | UniTask is a readonly partial struct (value type). Once awaited, its IUniTaskSource is recycled; awaiting the same UniTask variable twice throws. Use .Preserve() to obtain a memoized copy that can be awaited multiple times. | UniTask.cs:34, UniTask.cs:103-113 |
| 2 | A UniTask returned by a method must be either awaited, .Forget()ed, or .AttachExternalCancellation(token)ed. Orphan UniTasks silently swallow exceptions into UniTaskScheduler.UnobservedTaskException. | UniTaskScheduler.cs:13, UniTaskVoid.cs:11-17 |
| 3 | PlayerLoopTiming defines 16 timing slots (2020.2+; 14 on older Unity). Default UniTask.Yield() / UniTask.Delay uses PlayerLoopTiming.Update. Mixing LastPostLateUpdate with legacy WaitForEndOfFrame coroutines changes observed frame ordering. | PlayerLoopHelper.cs:71-99 |
| 4 | UniTask.Delay(int ms, DelayType, PlayerLoopTiming, CancellationToken, bool cancelImmediately) accepts DelayType.DeltaTime / UnscaledDeltaTime / Realtime. The old bool ignoreTimeScale overload still exists but mixes semantics — prefer the DelayType overload for new code. | UniTask.Delay.cs:12-20, UniTask.Delay.cs:147-165 |
| 5 | this.GetCancellationTokenOnDestroy() is defined for MonoBehaviour, GameObject, and Component in AsyncTriggerExtensions. Plain C# classes do NOT receive this extension — they must own a CancellationTokenSource explicitly. | Triggers/AsyncTriggerExtensions.cs:14,22,28 |
| 6 | UniTask.WhenAll(params UniTask[] tasks) and the IEnumerable<UniTask> overload both exist. Semantically match Task.WhenAll but are zero-alloc when tasks are UniTask-native. WhenAny returns (winnerIndex, result) tuple for UniTask<T>. | UniTask.WhenAll.cs:12,22,31,41, UniTask.WhenAny.cs |
| 7 | AsyncOperation.ToUniTask(IProgress<float>, PlayerLoopTiming, CancellationToken) is the canonical adapter. await operation works too but silently leaks the progress callback if you also set operation.completed += …. | UnityAsyncExtensions.cs |
| 8 | UniTaskCompletionSource and UniTaskCompletionSource<T> support TrySetResult / TrySetException / TrySetCanceled. Once any of the three succeeds, subsequent calls return false — they do not throw. | UniTaskCompletionSource.cs:573,610,754,792 |
| 9 | UniTask.SwitchToThreadPool() and UniTask.Run(...) are compile-time available on all platforms BUT throw NotSupportedException at runtime on WebGL. Guard with `#if !UNITY_WEBGL | |
| 10 | Returning async UniTaskVoid is the fire-and-forget idiom that lets await be used INSIDE the method. async void methods cannot return UniTask — a common compile error when porting from Task. | UniTaskVoid.cs:11-17, UniTask.Factory.cs:112-131 |
Sub-doc Routing
| Sub-doc | When to read |
|---|---|
| BASICS.md | UniTask vs Task differences, struct semantics, UniTaskVoid, zero-alloc state machine, AsyncUniTaskMethodBuilder |
| PLAYERLOOP.md | 16-value PlayerLoopTiming table, Yield/NextFrame/Delay/WaitForEndOfFrame/WaitForFixedUpdate, DelayType, frame-ordering with legacy coroutines |
| CANCELLATION.md | CancellationToken patterns, GetCancellationTokenOnDestroy (3 overloads), AttachExternalCancellation, CancelAfterSlim, AddTo, OperationCanceledException flow |
| COMPOSITION.md | WhenAll, WhenAny, WhenEach, Forget, SuppressCancellationThrow, ContinueWith, timeout patterns |
| CONVERSION.md | AsyncOperation.ToUniTask, UnityWebRequest.SendWebRequest().ToUniTask, IEnumerator.ToUniTask, Task.AsUniTask, UniTask.AsTask, UniTask.ToCoroutine |
| ASYNCENUMERABLE.md | IUniTaskAsyncEnumerable<T>, UniTaskAsyncEnumerable, AsyncReactiveProperty<T>, Channel<T>, EveryValueChanged, Publish, LINQ-to-async operators |
| TRIGGERS.md | AsyncTriggerBase, GetAsyncStartTrigger, GetAsyncDestroyTrigger, OnCollisionEnterAsync, OnClickAsync, MonoBehaviourMessagesTriggers, lifecycle cancellation |
| PITFALLS.md | 30 concrete hallucination / runtime pitfalls (double-await, forgotten Forget, WebGL threadpool, tracker memory, wrong PlayerLoopTiming, coroutine interop bugs) |
Routing to Other Modules
- Choice between
UniTask, rawTask, andIEnumeratorat the architecture layer → load async - DOTween tween → UniTask adapter (
tween.ToUniTask(TweenCancelBehaviour, token)) → load dotween-design - YooAsset handle → UniTask via
handle.ToUniTask()extension → load yooasset-design - Addressables
AsyncOperationHandle.ToUniTask()rules → load addressables-design - Performance review of UniTask-heavy code paths (tracker cost, state machine alloc) → load performance
- Asmdef layout for UniTask consumers (
Cysharp.Threading.Tasks.asmdefreference) → load asmdef
Version Scope
Targets UniTask 2.5.10. Earlier 2.x versions are mostly source-compatible; key differences:
WaitForEndOfFrame(MonoBehaviour coroutineRunner)overload added in recent 2.x — on 2023.1+ a parameterless overload is available (#if UNITY_2023_1_OR_NEWER). SeeUniTask.Delay.cs:78-103.UniTask.WhenEachis a newer addition; not all 2.x builds ship it.
When in doubt, read the cited source — not your memory.