[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7CS4YNFGXFAQ3GFQBC6ACWC":3,"skill-same:01M7CS4YNFGXFAQ3GFQBC6ACWC":50},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":30,"repositoryHtmlUrl":31,"repositoryHomepageUrl":32,"ownerHtmlUrl":33,"ownerBlogUrl":6,"ownerDescription":34,"updatedAt":35,"install":36,"resources":49},"01M7CS4YNFGXFAQ3GFQBC6ACWC","unity-project-architecture",null,"Use when writing or restructuring Unity C# code - assembly definitions and dependency direction, small components with cached references, ScriptableObjects for data and events, DI instead of singletons, Input System, Addressables, serialization safety and Unity 6 API changes.","makifbaysal\u002Ftasktrooper","makifbaysal","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F25031940?v=4","01M7CRG3ZCSYZSSEVDMW3DEYC8","Mehmet Akif Baysal","01M7CRG401FJ8YAXH5ER730XYV",122,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fgame-developer\u002Fskills\u002Funity-project-architecture\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: unity-project-architecture\ncategory: architecture\ndescription: Use when writing or restructuring Unity C# code - assembly definitions and dependency direction, small components with cached references, ScriptableObjects for data and events, DI instead of singletons, Input System, Addressables, serialization safety and Unity 6 API changes.\ntech_stack: Unity\nsource: informed by the Unity 6 Manual (assembly definitions, ScriptableObject, Input System, Addressables, serialization); own wording\n---\n# Unity Project Architecture\n\n## Overview\n\nUnity makes it easy to put everything in one MonoBehaviour that finds its collaborators with `FindObjectOfType` and a static `Instance`. That works for a jam and collapses after a few months: nothing is testable, compile times grow, and scene order decides behaviour. Structure the project as assemblies with a dependency direction, plain C# for rules, thin components for engine glue, and data in assets.\n\n**Core principle:** Rules in plain C# assemblies, components as adapters, data in ScriptableObjects, dependencies passed in. The repository's existing layout and DI choice win.\n\n## Assemblies and direction\n\n```\nGame.Core      (noEngineReferences: rules, math, state machines, save DTOs)\n   ↑\nGame.Runtime   (MonoBehaviours, ScriptableObjects, adapters; references Core)\n   ↑\nGame.UI        (views and presenters; references Runtime\u002FCore, never the reverse)\nGame.Editor    (includePlatforms: Editor; tools, validators)\nTests.EditMode \u002F Tests.PlayMode (test assemblies; see unity-testing)\n```\n\n```json\n{\n  \"name\": \"Game.Core\",\n  \"rootNamespace\": \"Game.Core\",\n  \"references\": [],\n  \"noEngineReferences\": true,\n  \"autoReferenced\": false\n}\n```\n\n- An assembly per layer keeps compile times down and makes a wrong-way reference a compile error instead of a review comment.\n- `Game.Core` with `noEngineReferences: true` can be compiled and tested by plain `dotnet test` when the editor is missing (testable-game-logic).\n- Gameplay never references UI; UI observes gameplay through events.\n\n## Components\n\n```csharp\n\u002F\u002F ❌ lookups every frame, public mutable fields, rules inside the component\npublic class Enemy : MonoBehaviour {\n    public int hp = 100;\n    void Update() {\n        var player = GameObject.Find(\"Player\");\n        if (Vector3.Distance(transform.position, player.transform.position) \u003C 5) GetComponent\u003CAnimator>().SetTrigger(\"Attack\");\n    }\n}\n\n\u002F\u002F ✅ cached references, serialized private fields, rule delegated to plain C#\n[RequireComponent(typeof(Animator))]\npublic sealed class EnemyView : MonoBehaviour {\n    static readonly int AttackHash = Animator.StringToHash(\"Attack\");\n    [SerializeField] EnemyDefinition definition;\n    Animator _animator; EnemyBrain _brain; ITargetProvider _targets;\n\n    public void Construct(ITargetProvider targets) => _targets = targets;\n    void Awake() { _animator = GetComponent\u003CAnimator>(); _brain = new EnemyBrain(definition.AttackRange); }\n    void Update() {\n        if (_brain.ShouldAttack(transform.position, _targets.PlayerPosition)) _animator.SetTrigger(AttackHash);\n    }\n}\n```\n\n- `[SerializeField] private` over public fields; public API through properties and methods.\n- `Awake` initialises the object itself; `OnEnable`\u002F`Start` wire up to others; `OnDisable` unsubscribes everything `OnEnable` subscribed.\n- `[RequireComponent]` for hard dependencies on the same GameObject; `TryGetComponent` instead of `GetComponent` + null check.\n- Physics in `FixedUpdate` through the Rigidbody API (`MovePosition`, `AddForce`, `linearVelocity`), never `transform.position` on a dynamic body.\n\n## Data and events in ScriptableObjects\n\n- Definitions (weapons, enemies, levels) are ScriptableObjects (data-driven-gameplay-design); runtime state is a separate object built from them. Changes made to a ScriptableObject in Play mode persist in the editor — never write gameplay state into one.\n- Event channels (`GameEvent : ScriptableObject` with `Raise()` and listeners) decouple scenes, but keep them few and named for what happened (`PlayerDied`), not what should happen.\n\n## Dependencies, not singletons\n\n- Use the repository's container if it has one (VContainer, Zenject\u002FExtenject): register services in a `LifetimeScope`\u002Finstaller and inject via constructor (plain classes) or `[Inject]` method (components).\n- Without one: a bootstrap scene or composition root creates services and passes them in (`Construct(...)` as above).\n- No new `static Instance` for gameplay state. Engine-wide stateless helpers are fine as static classes.\n\n## Input, assets, async\n\n- **Input System**, not the legacy `Input` class — actions from the `.inputactions` asset, rebinding and device glyphs (game-input-and-accessibility). A project still on the legacy Input Manager stays on it unless the task migrates it.\n- **Addressables** for content loaded at runtime (game-asset-pipeline); no new content in `Resources\u002F`. Every `LoadAssetAsync` handle is released.\n- **Async:** `Awaitable` (Unity 6) or UniTask where the repo uses it; cancel with `destroyCancellationToken` so a destroyed object's continuation does not run. `async void` only for event handlers, with try\u002Fcatch.\n\n## Serialization safety\n\n- Renaming a serialized field loses its data in every scene and prefab unless you add `[FormerlySerializedAs(\"oldName\")]`.\n- Polymorphic serialized fields need `[SerializeReference]`; plain `[SerializeField]` slices to the base type.\n- Keep Asset Serialization on Force Text so scenes and prefabs diff and merge (UnityYAMLMerge); prefer prefabs and nested prefabs over large scene edits so changes stay reviewable.\n\n## Unity 6 API notes (follow the pinned version)\n\n- `Rigidbody.velocity` → `linearVelocity`; `drag`\u002F`angularDrag` → `linearDamping`\u002F`angularDamping`.\n- `FindObjectsOfType`\u002F`FindObjectOfType` → `FindObjectsByType(FindObjectsSortMode.None)` \u002F `FindAnyObjectByType` (and avoid both in gameplay paths).\n- `Object.InstantiateAsync` for large prefabs; `Awaitable.NextFrameAsync`, `Awaitable.WaitForSecondsAsync`.\n- Unity 6 LTS lines: 6000.0 LTS support ends in October 2026, 6000.3 LTS is supported to the end of 2027 — never upgrade the project on your own.\n\n## Common Mistakes\n\n- `GameObject.Find`, `FindAnyObjectByType` or `GetComponent` in `Update`.\n- A MonoBehaviour holding the rule logic, making it testable only in PlayMode.\n- `static Instance` managers that depend on scene load order.\n- Renaming serialized fields without `FormerlySerializedAs`.\n- Subscribing in `OnEnable` without unsubscribing in `OnDisable` — leaks and calls on destroyed objects.\n\n## Red Flags\n\n- A UI assembly referenced by gameplay code.\n- A new `Resources.Load` call.\n- `transform.position =` on an object with a non-kinematic Rigidbody.\n- A component longer than a few hundred lines with rules, input and presentation mixed.\n","# Unity Project Architecture\n\n## Overview\n\nUnity makes it easy to put everything in one MonoBehaviour that finds its collaborators with `FindObjectOfType` and a static `Instance`. That works for a jam and collapses after a few months: nothing is testable, compile times grow, and scene order decides behaviour. Structure the project as assemblies with a dependency direction, plain C# for rules, thin components for engine glue, and data in assets.\n\n**Core principle:** Rules in plain C# assemblies, components as adapters, data in ScriptableObjects, dependencies passed in. The repository's existing layout and DI choice win.\n\n## Assemblies and direction\n\n```\nGame.Core      (noEngineReferences: rules, math, state machines, save DTOs)\n   ↑\nGame.Runtime   (MonoBehaviours, ScriptableObjects, adapters; references Core)\n   ↑\nGame.UI        (views and presenters; references Runtime\u002FCore, never the reverse)\nGame.Editor    (includePlatforms: Editor; tools, validators)\nTests.EditMode \u002F Tests.PlayMode (test assemblies; see unity-testing)\n```\n\n```json\n{\n  \"name\": \"Game.Core\",\n  \"rootNamespace\": \"Game.Core\",\n  \"references\": [],\n  \"noEngineReferences\": true,\n  \"autoReferenced\": false\n}\n```\n\n- An assembly per layer keeps compile times down and makes a wrong-way reference a compile error instead of a review comment.\n- `Game.Core` with `noEngineReferences: true` can be compiled and tested by plain `dotnet test` when the editor is missing (testable-game-logic).\n- Gameplay never references UI; UI observes gameplay through events.\n\n## Components\n\n```csharp\n\u002F\u002F ❌ lookups every frame, public mutable fields, rules inside the component\npublic class Enemy : MonoBehaviour {\n    public int hp = 100;\n    void Update() {\n        var player = GameObject.Find(\"Player\");\n        if (Vector3.Distance(transform.position, player.transform.position) \u003C 5) GetComponent\u003CAnimator>().SetTrigger(\"Attack\");\n    }\n}\n\n\u002F\u002F ✅ cached references, serialized private fields, rule delegated to plain C#\n[RequireComponent(typeof(Animator))]\npublic sealed class EnemyView : MonoBehaviour {\n    static readonly int AttackHash = Animator.StringToHash(\"Attack\");\n    [SerializeField] EnemyDefinition definition;\n    Animator _animator; EnemyBrain _brain; ITargetProvider _targets;\n\n    public void Construct(ITargetProvider targets) => _targets = targets;\n    void Awake() { _animator = GetComponent\u003CAnimator>(); _brain = new EnemyBrain(definition.AttackRange); }\n    void Update() {\n        if (_brain.ShouldAttack(transform.position, _targets.PlayerPosition)) _animator.SetTrigger(AttackHash);\n    }\n}\n```\n\n- `[SerializeField] private` over public fields; public API through properties and methods.\n- `Awake` initialises the object itself; `OnEnable`\u002F`Start` wire up to others; `OnDisable` unsubscribes everything `OnEnable` subscribed.\n- `[RequireComponent]` for hard dependencies on the same GameObject; `TryGetComponent` instead of `GetComponent` + null check.\n- Physics in `FixedUpdate` through the Rigidbody API (`MovePosition`, `AddForce`, `linearVelocity`), never `transform.position` on a dynamic body.\n\n## Data and events in ScriptableObjects\n\n- Definitions (weapons, enemies, levels) are ScriptableObjects (data-driven-gameplay-design); runtime state is a separate object built from them. Changes made to a ScriptableObject in Play mode persist in the editor — never write gameplay state into one.\n- Event channels (`GameEvent : ScriptableObject` with `Raise()` and listeners) decouple scenes, but keep them few and named for what happened (`PlayerDied`), not what should happen.\n\n## Dependencies, not singletons\n\n- Use the repository's container if it has one (VContainer, Zenject\u002FExtenject): register services in a `LifetimeScope`\u002Finstaller and inject via constructor (plain classes) or `[Inject]` method (components).\n- Without one: a bootstrap scene or composition root creates services and passes them in (`Construct(...)` as above).\n- No new `static Instance` for gameplay state. Engine-wide stateless helpers are fine as static classes.\n\n## Input, assets, async\n\n- **Input System**, not the legacy `Input` class — actions from the `.inputactions` asset, rebinding and device glyphs (game-input-and-accessibility). A project still on the legacy Input Manager stays on it unless the task migrates it.\n- **Addressables** for content loaded at runtime (game-asset-pipeline); no new content in `Resources\u002F`. Every `LoadAssetAsync` handle is released.\n- **Async:** `Awaitable` (Unity 6) or UniTask where the repo uses it; cancel with `destroyCancellationToken` so a destroyed object's continuation does not run. `async void` only for event handlers, with try\u002Fcatch.\n\n## Serialization safety\n\n- Renaming a serialized field loses its data in every scene and prefab unless you add `[FormerlySerializedAs(\"oldName\")]`.\n- Polymorphic serialized fields need `[SerializeReference]`; plain `[SerializeField]` slices to the base type.\n- Keep Asset Serialization on Force Text so scenes and prefabs diff and merge (UnityYAMLMerge); prefer prefabs and nested prefabs over large scene edits so changes stay reviewable.\n\n## Unity 6 API notes (follow the pinned version)\n\n- `Rigidbody.velocity` → `linearVelocity`; `drag`\u002F`angularDrag` → `linearDamping`\u002F`angularDamping`.\n- `FindObjectsOfType`\u002F`FindObjectOfType` → `FindObjectsByType(FindObjectsSortMode.None)` \u002F `FindAnyObjectByType` (and avoid both in gameplay paths).\n- `Object.InstantiateAsync` for large prefabs; `Awaitable.NextFrameAsync`, `Awaitable.WaitForSecondsAsync`.\n- Unity 6 LTS lines: 6000.0 LTS support ends in October 2026, 6000.3 LTS is supported to the end of 2027 — never upgrade the project on your own.\n\n## Common Mistakes\n\n- `GameObject.Find`, `FindAnyObjectByType` or `GetComponent` in `Update`.\n- A MonoBehaviour holding the rule logic, making it testable only in PlayMode.\n- `static Instance` managers that depend on scene load order.\n- Renaming serialized fields without `FormerlySerializedAs`.\n- Subscribing in `OnEnable` without unsubscribing in `OnDisable` — leaks and calls on destroyed objects.\n\n## Red Flags\n\n- A UI assembly referenced by gameplay code.\n- A new `Resources.Load` call.\n- `transform.position =` on an object with a non-kinematic Rigidbody.\n- A component longer than a few hundred lines with rules, input and presentation mixed.\n",{"name":5,"source":24,"category":25,"tech_stack":26,"description":7},"informed by the Unity 6 Manual (assembly definitions, ScriptableObject, Input System, Addressables, serialization); own wording","architecture","Unity","main","910394a0b6db9fc8c9a8f36328ec421d3ebd8b38","catalog\u002Fagents\u002Fgame-developer\u002Fskills\u002Funity-project-architecture",18,"https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper","https:\u002F\u002Ftasktrooper.ai","https:\u002F\u002Fgithub.com\u002Fmakifbaysal","Senior Software Developer","2026-11-15 04:50:29",{"source":8,"skillName":5,"commands":37,"prompt":47,"zipAvailable":48},[38,41,44],{"tool":39,"command":40},"npx","npx skills add makifbaysal\u002Ftasktrooper --skill unity-project-architecture",{"tool":42,"command":43},"bunx","bunx skills add makifbaysal\u002Ftasktrooper --skill unity-project-architecture",{"tool":45,"command":46},"pnpm","pnpm dlx skills add makifbaysal\u002Ftasktrooper --skill unity-project-architecture","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fgame-developer\u002Fskills\u002Funity-project-architecture\u002FSKILL.md",true,[],[51,57,64,71,78,85],{"skillNo":52,"name":53,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":54,"categories":55,"keywords":56,"publishedAt":19},"01M7CSVEPQW6J6TD6CS2T5FPNZ","visual-craft","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fvisual-craft\u002FSKILL.md",[],[],{"skillNo":58,"name":59,"nameZh":6,"description":60,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":61,"categories":62,"keywords":63,"publishedAt":19},"01M7CSVAQG91ETHQ0HBNZDG5FR","ux-copy","Use when you write any words a user reads in a mockup or a hand-off - content language and voice, buttons, labels, errors, empty states, confirmations, numbers and dates, and the longest-string check","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fux-copy\u002FSKILL.md",[],[],{"skillNo":65,"name":66,"nameZh":6,"description":67,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":70,"publishedAt":19},"01M7CSV6H0J38659NDXHJQ8396","screen-mockup-html","Use when you draw screens as the design task's HTML mockup - ONE canvas document holding every screen and every variant side by side, the sanitizer-safe recipe, phone and wide frames, the states grid, static control states, and the loopback self-check with screenshots at 375, 768 and 1440 attached to the task","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fscreen-mockup-html\u002FSKILL.md",[],[],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":77,"publishedAt":19},"01M7CSV3JFRF3BM3XK52M7YEYR","performance-awareness","How the performance score moves for your role. Use when the score context shows a declining trend, or before handing off work you have not self-checked against every criterion.","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fperformance-awareness\u002FSKILL.md",[],[],{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":19},"01M7CSTZDH00YRF5SCT7BRT9QD","design-variants","Use when a screen design needs variants - how many, variants as side-by-side rows on the one canvas, what makes two variants genuinely different, recommending one, how the human's choice is read, and narrowing to the chosen one in revision","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fdesign-variants\u002FSKILL.md",[],[],{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":91,"publishedAt":19},"01M7CSTV6P3SM3PAE28DB0RF77","design-system-authoring","Use when you derive, change or extend a design system - where tokens live per stack, the DTCG token tree, role-based names for both themes, base vs layer vs drift, the DESIGN.md section order, the inventory format, the contrast check and the lint every proposal returns","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fdesign-system-authoring\u002FSKILL.md",[],[]]