From d4217feb14a4222eb79b222004aa2722454a1ac9 Mon Sep 17 00:00:00 2001 From: Etienne Date: Tue, 7 Jul 2026 15:38:22 -0400 Subject: [PATCH 1/2] Add new-unity-project skill Orchestration skill that takes a user from idea to a running, version-controlled Unity project: gather concept, target platforms and monetization, install the CLI and Editor, create the project and source control, install packages via the C# PackageManager Client API, scaffold a game skeleton, save, and commit. Also refreshes the README skills table (was missing three existing skills). Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 4 + skills/new-unity-project/SKILL.md | 246 ++++++++++++++++++ .../references/editor-versions.md | 56 ++++ .../references/game-skeleton.md | 180 +++++++++++++ .../references/package-manager-api.md | 193 ++++++++++++++ .../references/select-packages.md | 79 ++++++ 6 files changed, 758 insertions(+) create mode 100644 skills/new-unity-project/SKILL.md create mode 100644 skills/new-unity-project/references/editor-versions.md create mode 100644 skills/new-unity-project/references/game-skeleton.md create mode 100644 skills/new-unity-project/references/package-manager-api.md create mode 100644 skills/new-unity-project/references/select-packages.md diff --git a/README.md b/README.md index 816d062..0e4baeb 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,11 @@ npx skills add Unity-Technologies/skills | Skill | Description | |---|---| +| `new-unity-project` | Start a new game from scratch — gather the concept, platforms, and monetization, install the CLI and Editor, create the project and source control, install packages, and scaffold a skeleton | | `unity-cli` | Interact with the Unity CLI — install editors, manage projects, run builds, check auth, and more | +| `build-live-game` | Build and operate a live game with Unity Gaming Services — auth, cloud save, cloud code, economy, remote config, leaderboards, and more | +| `implement-in-app-purchases` | Implement, configure, and debug Unity In-App Purchases (IAP) | +| `levelplay-unity-integration` | Integrate LevelPlay (IronSource) ad mediation — rewarded, interstitial, and banner ads | ## Usage diff --git a/skills/new-unity-project/SKILL.md b/skills/new-unity-project/SKILL.md new file mode 100644 index 0000000..07e56c8 --- /dev/null +++ b/skills/new-unity-project/SKILL.md @@ -0,0 +1,246 @@ +--- +name: new-unity-project +description: Use when starting a brand-new Unity game or project from scratch — the user says "make/start/create a new game", "bootstrap a Unity project", "I want to build a game", "scaffold a Unity project", or otherwise has no existing project yet. Walks from an idea to a running, version-controlled Unity project — it gathers the game concept, target platforms and monetization, installs the Unity CLI and Editor, creates the project and source control, installs the right packages via the C# PackageManager Client API, scaffolds a game skeleton, saves, and commits. Triggers on new game, greenfield, from scratch, prototype, game jam, blank project, project setup, scaffold, bootstrap. +allowed-tools: + - Bash + - Read + - Write + - Edit + - AskUserQuestion +--- + +# New Unity Project + +Take a user from an idea to a running, version-controlled Unity project with the right +packages installed and a game skeleton in place. + +**Work the steps in order, one at a time.** Ask only the questions for the current step — +do not gather information for later steps in advance. Wait for the user at each checkpoint +before proceeding. Every Unity CLI operation in this skill is documented in the +**`unity-cli`** skill; read it whenever you need exact command syntax or flags. + +## Overview of the flow + +1. **Concept** — what they want to build (genre, look, gameplay, UX). +2. **Ship & money** — target platforms and monetization. +3. **CLI** — install the Unity CLI if it isn't available. +4. **Editor** — install a supported Unity Editor (or the version they pick). +5. **Project + source control** — create the project and initialize git. +6. **Packages** — determine and install the right packages via the C# PackageManager Client API. +7. **Skeleton** — scaffold folders, a bootstrap scene, and starter scripts. +8. **Save & commit** — import, save, and make the first commit. + +--- + +## Step 1 — What do they want to build? + +Capture the game concept. Use `AskUserQuestion` so the user can pick fast, but let them +answer freely too. Cover: + +- **Genre / core loop** — platformer, top-down shooter, puzzle, idle/clicker, RPG, racing, + card/board, tower defense, sim, hyper-casual, first-person, etc. +- **Dimension & look** — 2D or 3D; art style (pixel, low-poly, stylized, realistic, flat/UI-only). +- **Gameplay** — the one-sentence "what the player does moment to moment." +- **UX / scope** — single-screen prototype vs. multi-scene game; menus, HUD, save system; + single-player or multiplayer. + +Write the answers down in a short **project brief** (2–4 lines) and read it back to the user +to confirm before moving on. This brief drives package selection (Step 6) and the skeleton +(Step 7). Also settle on a **project name** here. + +## Step 2 — When do they ship, and how do they make money? + +Two decisions, because both change which packages you install and which Editor modules the +Editor needs. + +- **Target platforms** (multi-select): Desktop (Windows / macOS / Linux), Mobile (iOS / + Android), WebGL, Console. Note whether a release date/deadline matters (a game jam vs. a + commercial launch pushes toward LTS in Step 4). +- **Monetization**: none / premium (paid up-front), in-app purchases, ads, or a mix. + - IAP → the **`implement-in-app-purchases`** skill (`com.unity.purchasing`). + - Ads → the **`levelplay-unity-integration`** skill (`com.unity.services.levelplay`). + - Live-service / backend (accounts, cloud save, economy, remote config) → the + **`build-live-game`** skill. + +Record platforms and monetization in the brief. Don't integrate monetization yet — you note +the packages now (Step 6) and hand off to the dedicated skills after the skeleton exists. + +## Step 3 — Install the Unity CLI + +Every later step drives the `unity` CLI. Check for it and install if missing: + +```bash +which unity && unity --version +``` + +If it's not found, install it (see the **`unity-cli`** skill for platform-specific commands +and troubleshooting), then open a new shell and re-verify `unity --version`. If it still +isn't on PATH, tell the user and stop — nothing downstream will work. + +Also confirm the user is signed in and licensed, since editor install and project creation +need it: + +```bash +unity auth status --format json +unity license status --format json +``` + +If not signed in, have the user run `unity auth login` (it prints a URL). If no license is +active, guide them through `unity license activate` (see the `unity-cli` skill for personal +vs. serial vs. floating). + +## Step 4 — Choose and install the Editor + +Ask which Editor version to use, and explain the trade-offs first. See +[references/editor-versions.md](references/editor-versions.md) for the LTS vs. Supported vs. +Pre-release explanation and how to list real current versions with `unity releases`. + +**Default recommendation: the latest LTS**, unless the user needs a feature only in a newer +Supported/Tech release, or is deliberately evaluating a pre-release. + +Show the actual options, then install the chosen version with the platform modules implied by +Step 2 (e.g. `--module android` / `--module ios` for mobile, `--module webgl` for WebGL): + +```bash +# See what's available (LTS shown; also try --stream tech / --stream beta) +unity releases --stream lts --limit 5 --format json + +# Install the chosen version + platform modules (installs the latest LTS with the `lts` alias) +unity install --module android --module ios --yes --accept-eula +``` + +Confirm it landed with `unity editors --installed --format json`. + +## Step 5 — Create the project and set up source control + +Pick a template that matches the concept (2D vs. 3D, URP vs. built-in vs. HDRP). List what +the chosen Editor actually offers, then create the project: + +```bash +# List the real template ids this editor offers — don't guess them. Common ones include +# com.unity.template.3d, com.unity.template.2d, and a URP template (id varies by version). +unity templates list --editor --format json + +# Create the project (first positional arg is the NAME; --path sets the parent directory) +unity projects new "" --path --editor-version \ + --template +``` + +**Source control.** Initialize git with a Unity-appropriate ignore so the multi-GB `Library/` +and other generated folders never get committed: + +```bash +cd / +git init -b main +curl -fsSL https://raw.githubusercontent.com/github/gitignore/main/Unity.gitignore -o .gitignore +# If offline, write a minimal .gitignore ignoring: [Ll]ibrary/ [Tt]emp/ [Oo]bj/ [Bb]uild/ +# [Bb]uilds/ [Ll]ogs/ [Uu]serSettings/ *.csproj *.sln +``` + +Recommend **Git LFS** for binary assets (textures, audio, models) if the game is asset-heavy — +`git lfs install` then track `*.png *.psd *.fbx *.wav *.mp3` etc. in `.gitattributes`. + +To publish straight to a remote (GitHub/GitLab/Unity Version Control), the CLI can do it in one +step via `unity projects create ... --vcs github ...` or `unity projects link vcs` — see the +`unity-cli` skill. Only do this if the user wants a remote now and has provided a token. + +**Do the first commit later (Step 8)** — after packages, skeleton, and `.meta` files exist. + +## Step 6 — Determine and install packages via the C# PackageManager Client API + +Map the brief (Step 1) and platforms/monetization (Step 2) to a concrete package list. See +[references/select-packages.md](references/select-packages.md) for the genre/look/platform → +package mapping and version guidance. + +Install them from C# using `UnityEditor.PackageManager.Client` — **not** by hand-editing +`Packages/manifest.json`. Write a small editor script into the project and run it headless. +The full, tested installer script and the exact `unity run` invocation are in +[references/package-manager-api.md](references/package-manager-api.md). + +The pattern, briefly: + +1. Write `Assets/Editor/ProjectBootstrap/PackageInstaller.cs` containing a static method that + calls `Client.AddAndRemove(packagesToAdd: ids)` and pumps `EditorApplication.update` until + the request completes, then `EditorApplication.Exit()`. +2. Run it headless by launching the **Editor binary directly** in `-batchmode` **without** + `-quit` (the `Client.Add*` call is async and the Editor must stay alive until it finishes; + `unity run` can't be used because it always injects `-quit`). The exact binary-resolution + and command are in [references/package-manager-api.md](references/package-manager-api.md). +3. Verify the resulting `Packages/manifest.json` lists every requested package and that the + run exited 0. + +Hand off monetization/backend package *integration* (not just install) to the dedicated skills +after the skeleton exists. + +## Step 7 — Scaffold the game skeleton + +Create a minimal but runnable structure matched to the concept. See +[references/game-skeleton.md](references/game-skeleton.md) for the folder layout, assembly +definition, a `GameManager` bootstrap, and genre-specific starter scripts. + +At minimum: + +- A consistent `Assets/` folder layout (`Scripts/`, `Scenes/`, `Prefabs/`, `Art/`, `Audio/`, + `UI/`, `Settings/`). +- An assembly definition so scripts compile into a named assembly. +- A bootstrap `GameManager` and one genre-appropriate gameplay script (e.g. a + `PlayerController` for a platformer, a `BoardController` for a puzzle). +- An initial scene wired to the bootstrap, set as the first scene in Build Settings. + +Write these as normal `.cs` / asset files on disk. Unity generates `.meta` files and imports +them on the next Editor launch (Step 8). + +## Step 8 — Save, import, and commit + +Open (or headless-run) the project once so Unity imports the new scripts and assets and +generates every `.meta` file — these MUST be committed alongside their asset: + +```bash +# Headless import + asset-database save (see references/package-manager-api.md for the method) +unity run "" --editor-version \ + -- -executeMethod ProjectBootstrap.ProjectSaver.SaveAll +# ...or simply open it once so the user can see it: unity open "" +``` + +Then commit everything: + +```bash +cd "" +git add -A +git status # sanity-check: Library/ etc. must NOT be staged +git commit -m "Initial Unity project: + +" +``` + +Verify the ignore worked (`git ls-files | grep -c '^Library/'` must be `0`). Report the +project path, Editor version, installed packages, and next steps — including which +monetization/backend skill to run next (from Step 2). + +--- + +## Checklist + +- [ ] Project brief captured and confirmed (genre, look, gameplay, UX, name) +- [ ] Target platforms + monetization recorded +- [ ] `unity` CLI installed, user signed in and licensed +- [ ] Editor version chosen (LTS by default) and installed with the right platform modules +- [ ] Project created from an appropriate template; git initialized with a Unity `.gitignore` +- [ ] Packages installed via the C# PackageManager Client API; `manifest.json` verified +- [ ] Skeleton scaffolded (folders, asmdef, GameManager, one gameplay script, a scene) +- [ ] Project imported/saved so `.meta` files exist +- [ ] First commit made; `Library/` and generated folders excluded +- [ ] Handed off to the monetization/backend skill(s) if applicable + +## Common mistakes + +- **Committing `Library/`, `Temp/`, `obj/`, `Build/`.** Always write the `.gitignore` before + the first `git add`. These are large and machine-specific. +- **Committing scripts without their `.meta` files** (or vice versa). Import the project once + (Step 8) so meta files exist, then `git add -A`. +- **Hand-editing `manifest.json`** instead of using the PackageManager Client API — the user + asked for the API, and it resolves dependencies/versions correctly. +- **Missing Editor modules.** A mobile target needs the `android`/`ios` modules; WebGL needs + `webgl`. Installing the Editor without them means the project can't build for the target. +- **Gathering all questions up front.** Ask per step; platform/monetization answers change the + Editor modules and package list, so don't scaffold before they're settled. diff --git a/skills/new-unity-project/references/editor-versions.md b/skills/new-unity-project/references/editor-versions.md new file mode 100644 index 0000000..84f901a --- /dev/null +++ b/skills/new-unity-project/references/editor-versions.md @@ -0,0 +1,56 @@ +# Choosing a Unity Editor version + +Explain these trade-offs to the user before they pick, then show real current versions with +the CLI. When in doubt, **default to the latest LTS.** + +## The three streams + +| Stream | What it is | Support window | Use it when | +|---|---|---|---| +| **LTS** (Long-Term Support) | The most stable release of a major version. Only bug/security patches land after it ships — no new features. | Longest (roughly 2 years of patches). | You're shipping a real game, working toward a launch, or want maximum stability. **This is the default recommendation.** | +| **Supported / Tech stream** | The newest *stable* feature releases (e.g. the mid-cycle innovation releases). Newer features than LTS, still production-usable, but a shorter support window and more churn. | Shorter than LTS. | You need a feature that isn't in the current LTS yet, and can tolerate faster version churn. | +| **Pre-release** (alpha / beta) | Preview builds of an upcoming version. Unstable, APIs can change, not for production. | None (preview only). | You're evaluating what's coming, or preparing a project for a future version. Never for a game you intend to ship soon. | + +**Rule of thumb:** ship on LTS; reach for a Supported/Tech release only for a specific feature; +use pre-releases only to evaluate. A deadline (game jam, commercial launch) always argues for LTS. + +## Show the real options + +Version numbers move constantly — don't guess them, list them: + +```bash +# Latest LTS releases (recommended default) +unity releases --stream lts --limit 5 --format json + +# Newer Supported / Tech-stream releases +unity releases --stream tech --limit 5 --format json + +# Pre-releases (evaluation only) +unity releases --stream beta --limit 5 --format json +unity releases --stream alpha --limit 5 --format json + +# What's already installed on this machine +unity editors --installed --format json +``` + +The CLI also accepts the aliases `lts` and `latest` wherever a version is expected +(`unity install lts`, `unity editors default lts`), so you can install the current LTS without +pinning an exact number. + +## Install with the right modules + +Install the chosen version together with the platform modules the target platforms (Step 2) +require — otherwise the project can't build for them: + +```bash +# Latest LTS + mobile modules +unity install lts --module android --module ios --yes --accept-eula + +# A specific version + WebGL +unity install 6000.0.47f1 --module webgl --yes --accept-eula +``` + +Common module names: `android`, `ios`, `webgl`, `windows-mono`, `mac-mono`, `linux-mono`. +List what a version offers with `unity install-modules --editor-version --list`. + +See the **`unity-cli`** skill for the full `install`, `releases`, and module command reference. diff --git a/skills/new-unity-project/references/game-skeleton.md b/skills/new-unity-project/references/game-skeleton.md new file mode 100644 index 0000000..fda2cbe --- /dev/null +++ b/skills/new-unity-project/references/game-skeleton.md @@ -0,0 +1,180 @@ +# Scaffolding the game skeleton + +Create a minimal but runnable structure matched to the concept from Step 1. Write plain +`.cs`/asset files to disk; Unity generates `.meta` files and imports on the next launch (Step 8). + +Keep it small — a skeleton, not a game. Enough to open, press Play, and build on. + +## Folder layout + +Create these under `Assets/` (Unity creates `.meta` files on import): + +``` +Assets/ + Editor/ + ProjectBootstrap/ # the bootstrap scripts (PackageInstaller, ProjectSaver, SceneScaffolder) + Scripts/ + Runtime/ # gameplay code (compiled into the game) + Editor/ # game-specific editor tooling (custom inspectors, etc.) + Scenes/ + Prefabs/ + Art/ + Audio/ + UI/ + Settings/ +``` + +The Step-6/8 bootstrap scripts live in `Assets/Editor/ProjectBootstrap/` (see +[package-manager-api.md](package-manager-api.md)); `Assets/Scripts/Editor/` is for game-specific +editor tooling you add later. + +## Assembly definition + +Put an `.asmdef` at `Assets/Scripts/Runtime/.Runtime.asmdef` so runtime code compiles +into a named assembly (faster iteration, clean references). Reference `Unity.InputSystem` etc. as +needed by the installed packages. + +```json +{ + "name": ".Runtime", + "rootNamespace": "", + "references": [], + "autoReferenced": true +} +``` + +Add package references (e.g. `"Unity.InputSystem"`) to `references` only once the corresponding +package is installed, or leave `references` empty and add them when a script needs them. + +## GameManager bootstrap + +A single entry point that persists across scenes. `Assets/Scripts/Runtime/GameManager.cs`: + +```csharp +using UnityEngine; + +namespace +{ + // Central bootstrap: lives from the first scene, survives scene loads. + public sealed class GameManager : MonoBehaviour + { + public static GameManager Instance { get; private set; } + + void Awake() + { + if (Instance != null && Instance != this) { Destroy(gameObject); return; } + Instance = this; + DontDestroyOnLoad(gameObject); + } + + void Start() + { + Debug.Log(" booted."); + // TODO: initialize systems, load the first gameplay scene, etc. + } + } +} +``` + +## One genre-appropriate gameplay script + +Add exactly one starter script that matches the core loop, so Play does something. Examples: + +**Platformer / action — `PlayerController.cs`:** + +```csharp +using UnityEngine; + +namespace +{ + [RequireComponent(typeof(Rigidbody2D))] + public sealed class PlayerController : MonoBehaviour + { + [SerializeField] float moveSpeed = 6f; + [SerializeField] float jumpForce = 12f; + Rigidbody2D _rb; + + void Awake() => _rb = GetComponent(); + + void Update() + { + // linearVelocity is the Unity 6 name; on pre-6 LTS use `velocity` instead. + var x = Input.GetAxisRaw("Horizontal"); + _rb.linearVelocity = new Vector2(x * moveSpeed, _rb.linearVelocity.y); + if (Input.GetButtonDown("Jump")) + _rb.linearVelocity = new Vector2(_rb.linearVelocity.x, jumpForce); + } + } +} +``` + +> **Input handling:** this sample uses the legacy `UnityEngine.Input` API for brevity. If the +> project installs `com.unity.inputsystem` **and** Active Input Handling is set to "Input System +> Package (New)" only, these `Input.*` calls throw at runtime — set Active Input Handling to +> "Both" (Project Settings > Player), or rewrite the reads using `UnityEngine.InputSystem` +> (e.g. `Keyboard.current`) and reference the `Unity.InputSystem` assembly in the asmdef. + +For other genres, scaffold the equivalent single controller: + +| Genre | Starter script | Responsibility | +|---|---|---| +| Puzzle / match | `BoardController` | Holds the grid, handles a tap/swap, checks matches | +| Top-down / twin-stick | `PlayerController` | Move on X/Y, aim toward cursor | +| Idle / clicker | `ResourceManager` | Tick a resource on an interval, respond to a click | +| RPG / adventure | `PlayerController` + `DialogueTrigger` | Movement + a stub interaction | +| Racing | `VehicleController` | Throttle/steer a Rigidbody | + +Keep each to one clear responsibility. Match namespace and coding style to the rest of the project. + +## Initial scene + +Create `Assets/Scenes/Main.unity` with a `GameManager` object (carrying the `GameManager` +component) and register it as scene 0 in **Build Settings** so the project can build. + +Do it fully headless with a bootstrap method. Write +`Assets/Editor/ProjectBootstrap/SceneScaffolder.cs` (synchronous — run it the same way as +`ProjectSaver`, see [package-manager-api.md](package-manager-api.md)): + +```csharp +using System.IO; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace ProjectBootstrap +{ + public static class SceneScaffolder + { + const string ScenePath = "Assets/Scenes/Main.unity"; + + // Invoke with: -executeMethod ProjectBootstrap.SceneScaffolder.CreateMainScene + public static void CreateMainScene() + { + Directory.CreateDirectory("Assets/Scenes"); + + var scene = EditorSceneManager.NewScene( + NewSceneSetup.DefaultGameObjects, NewSceneMode.Single); + + var manager = new GameObject("GameManager"); + // Attach the GameManager MonoBehaviour by type name so this compiles without a ref. + var type = System.Type.GetType(".GameManager, .Runtime"); + if (type != null) manager.AddComponent(type); + else Debug.LogWarning("[SceneScaffolder] GameManager type not found yet."); + + EditorSceneManager.SaveScene(scene, ScenePath); + EditorBuildSettings.scenes = new[] { new EditorBuildSettingsScene(ScenePath, true) }; + Debug.Log($"[SceneScaffolder] Created {ScenePath} and registered it as scene 0."); + EditorApplication.Exit(0); + } + } +} +``` + +Run it **after** the package install and the runtime scripts exist (so `GameManager` is +compiled). Add a `Player` object with the starter controller on first open, or extend this +method. Templates already provide a camera and light via `NewSceneSetup.DefaultGameObjects`. + +## Save & meta files + +After writing these files, run the project once so Unity imports them and writes `.meta` files +(Step 8). Every `.cs` and asset MUST be committed together with its `.meta`. diff --git a/skills/new-unity-project/references/package-manager-api.md b/skills/new-unity-project/references/package-manager-api.md new file mode 100644 index 0000000..074574a --- /dev/null +++ b/skills/new-unity-project/references/package-manager-api.md @@ -0,0 +1,193 @@ +# Installing packages with the C# PackageManager Client API + +Install packages programmatically with `UnityEditor.PackageManager.Client` and run the script +headless. Do **not** hand-edit `Packages/manifest.json`. + +## The `-quit` problem — why NOT `unity run` for the installer + +`Client.Add` / `Client.AddAndRemove` are **asynchronous**: they return a `Request` that only +completes on later `EditorApplication.update` ticks (the UPM child process marshals its result +back on the Editor's main-loop pump — a blocking `while(!req.IsCompleted)` busy-wait deadlocks +it). So the Editor must **stay alive** after `-executeMethod` returns, until the request finishes. + +`unity run` **cannot** be used here: it always injects `-quit` (see the `unity-cli` skill — +"Reserved flags … The command adds them itself: `-batchmode`, `-quit`, …"). With `-quit`, the +Editor quits the instant `Install()` returns, before UPM resolves — packages never install and +the callback never runs. + +**Solution:** for the async installer, launch the **Editor binary directly** in `-batchmode` +**without** `-quit`. The Editor stays alive, `EditorApplication.update` keeps ticking, the poll +callback runs, and it calls `EditorApplication.Exit(code)` itself when done — which both quits +and sets the process exit code. + +(Purely *synchronous* bootstrap methods — the savers below — finish before returning, so those +*can* use `unity run`.) + +## The installer script + +Write this to `Assets/Editor/ProjectBootstrap/PackageInstaller.cs`. It must live under an +`Editor/` folder (or an Editor-only assembly) because it uses `UnityEditor`. + +```csharp +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.PackageManager; +using UnityEditor.PackageManager.Requests; +using UnityEngine; + +namespace ProjectBootstrap +{ + // Installs a fixed set of packages via the PackageManager Client API, headless-safe. + public static class PackageInstaller + { + // EDIT this list to match the package selection (see select-packages.md). + static readonly string[] PackagesToAdd = + { + "com.unity.inputsystem", + "com.unity.cinemachine", + "com.unity.render-pipelines.universal", + // "com.unity.package@1.2.3" // pin a version with @ when a skill requires a minimum + }; + + const double TimeoutSeconds = 600; // UPM resolution + downloads can be slow + + static AddAndRemoveRequest _request; + static double _deadline; + + // Invoke with: -executeMethod ProjectBootstrap.PackageInstaller.Install (NO -quit) + public static void Install() + { + if (PackagesToAdd == null || PackagesToAdd.Length == 0) + { + Debug.Log("[PackageInstaller] Nothing to install."); + EditorApplication.Exit(0); + return; + } + + Debug.Log($"[PackageInstaller] Adding: {string.Join(", ", PackagesToAdd)}"); + _request = Client.AddAndRemove(packagesToAdd: PackagesToAdd); + _deadline = EditorApplication.timeSinceStartup + TimeoutSeconds; + EditorApplication.update += Poll; + } + + static void Poll() + { + if (_request == null) return; + + if (!_request.IsCompleted) + { + if (EditorApplication.timeSinceStartup > _deadline) + { + EditorApplication.update -= Poll; + Debug.LogError("[PackageInstaller] Timed out waiting for UPM."); + EditorApplication.Exit(2); + } + return; + } + + EditorApplication.update -= Poll; + + if (_request.Status == StatusCode.Success) + { + var names = _request.Result.Select(p => $"{p.name}@{p.version}"); + Debug.Log($"[PackageInstaller] Installed: {string.Join(", ", names)}"); + EditorApplication.Exit(0); + } + else + { + Debug.LogError($"[PackageInstaller] Failed: {_request.Error?.message}"); + EditorApplication.Exit(1); + } + } + } +} +``` + +`AddAndRemove` installs the whole set in a single UPM resolution pass, which is faster and less +error-prone than one `Client.Add` per package. To also *remove* packages (e.g. drop a template's +unwanted default), pass `packagesToRemove:`. + +## Run it headless (direct Editor invocation, no `-quit`) + +Resolve the Editor binary from the version, then run it in batch mode. The script owns quitting +via `EditorApplication.Exit`, so do **not** pass `-quit`: + +```bash +VERSION="" # e.g. 6000.0.47f1 +PROJECT="" + +# Install directory of that editor (Hub layout) +ED=$(unity editors path "$VERSION" --format json | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['path'])") + +# Resolve the executable per-OS (handles both "dir containing Unity.app" and the ".app" itself) +case "$(uname)" in + Darwin) if [ -d "$ED/Unity.app" ]; then UNITY_BIN="$ED/Unity.app/Contents/MacOS/Unity"; + elif [[ "$ED" == *.app ]]; then UNITY_BIN="$ED/Contents/MacOS/Unity"; + else UNITY_BIN="$ED/Unity"; fi ;; + Linux) UNITY_BIN="$ED/Unity" ;; + *) UNITY_BIN="$ED/Unity.exe" ;; # Windows (Git Bash / MSYS); use Unity.exe in PowerShell +esac + +"$UNITY_BIN" -batchmode -projectPath "$PROJECT" \ + -executeMethod ProjectBootstrap.PackageInstaller.Install -logFile - +echo "Exit code: $?" # 0 = success, 1 = UPM error, 2 = timeout +``` + +`-logFile -` streams the Editor log (including the `[PackageInstaller]` lines) to stdout so you +can watch resolution progress and read any UPM error. If `unity editors path` output shape +differs on your build, get the directory from `unity editors --installed --format json` instead. + +## Verify + +```bash +# Every requested id should appear as a dependency +cat "/Packages/manifest.json" +``` + +Confirm the run exited `0` and each package from the list is present in `manifest.json`. + +## The synchronous bootstrap methods (Steps 7–8) + +These finish before returning, so they're safe to run via `unity run` (its injected `-quit` is +harmless — they also call `EditorApplication.Exit` for a clean exit code). Write them to +`Assets/Editor/ProjectBootstrap/`. + +**Import + save the AssetDatabase (Step 8)** — generates `.meta` files before committing. +`Assets/Editor/ProjectBootstrap/ProjectSaver.cs`: + +```csharp +using UnityEditor; +using UnityEngine; + +namespace ProjectBootstrap +{ + public static class ProjectSaver + { + // Invoke with: -executeMethod ProjectBootstrap.ProjectSaver.SaveAll + public static void SaveAll() + { + AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); + AssetDatabase.SaveAssets(); + Debug.Log("[ProjectSaver] Assets imported and saved."); + EditorApplication.Exit(0); + } + } +} +``` + +```bash +unity run "" --editor-version \ + -- -executeMethod ProjectBootstrap.ProjectSaver.SaveAll +``` + +Merely opening the project once (`unity open ""`) also imports and generates +`.meta` files — use `SaveAll` when you want it headless in a script or CI. A `SceneScaffolder` +method (see [game-skeleton.md](game-skeleton.md)) is also synchronous and runs the same way. + +## Notes + +- These editor scripts are a bootstrap convenience. Leave them in `Assets/Editor/ProjectBootstrap/` + (they do nothing unless invoked) or delete them after setup — your call; mention it to the user. +- If a package fails to resolve, `_request.Error.message` is logged; read it and check the + package id/version against the Unity registry. `unity logs --level error` surfaces Editor logs. diff --git a/skills/new-unity-project/references/select-packages.md b/skills/new-unity-project/references/select-packages.md new file mode 100644 index 0000000..832518a --- /dev/null +++ b/skills/new-unity-project/references/select-packages.md @@ -0,0 +1,79 @@ +# Selecting packages from the project brief + +Turn the Step 1 concept and Step 2 platforms/monetization into a concrete package list, then +install it via the C# PackageManager Client API (see +[package-manager-api.md](package-manager-api.md)). + +**Principle:** install what the concept actually needs, not everything. A hyper-casual 2D +prototype needs far less than a 3D multiplayer RPG. Prefer packages already provided by the +chosen template (URP templates already include the render pipeline, Input System, etc.) — only +add what's missing. Don't pin exact versions unless a skill requires a minimum; `Client.Add` +without a version resolves the latest compatible release. + +## Foundation (almost every project) + +| Need | Package | Notes | +|---|---|---| +| Modern input | `com.unity.inputsystem` | Preferred over the legacy Input Manager. | +| Text / UI | `com.unity.ugui` | uGUI + TextMeshPro (bundled). UI Toolkit ships with the Editor. | +| Camera framing | `com.unity.cinemachine` | Great for almost any 3D and many 2D games. | +| Testing | `com.unity.test-framework` | Enables `unity test`; usually already present. | +| Large/streamed assets | `com.unity.addressables` | Add when the game has many assets or needs content updates. | + +## Render pipeline (pick one; usually set by the template) + +| Choice | Package | Use when | +|---|---|---| +| **URP** (Universal) | `com.unity.render-pipelines.universal` | Default for most 2D/3D, mobile, and WebGL. Broadest platform reach. | +| **HDRP** (High-Definition) | `com.unity.render-pipelines.high-definition` | High-fidelity PC/console only. Not for mobile/WebGL. | +| **Built-in** | (none) | Simplest/legacy; fine for tiny prototypes. | + +## By dimension & look + +| Look | Packages | +|---|---| +| **2D** (any) | `com.unity.2d.feature` (sprites, tilemap, animation, pixel-perfect bundle) | +| **2D pixel-perfect** | `com.unity.2d.pixel-perfect` (included in the 2D feature set) | +| **3D navigation** | `com.unity.ai.navigation` (NavMesh for AI/pathfinding) | +| **Cutscenes / sequencing** | `com.unity.timeline` | +| **No-code logic** | `com.unity.visualscripting` | + +## By genre (starting points, combine with the above) + +| Genre | Typical additions | +|---|---| +| Platformer / action | URP, Input System, Cinemachine, 2D feature (if 2D), AI Navigation (if 3D) | +| Puzzle / match / card | URP or 2D feature, Input System, uGUI/TextMeshPro, Timeline (juice) | +| Top-down / twin-stick | URP, Input System, Cinemachine, AI Navigation | +| RPG / adventure | URP, Input System, Cinemachine, AI Navigation, Addressables, Timeline | +| Racing / physics | URP, Input System, Cinemachine; Physics is built in | +| Idle / hyper-casual | 2D feature or URP, Input System, uGUI/TextMeshPro (keep it lean) | +| Multiplayer (any) | `com.unity.netcode.gameobjects` + Multiplayer Services → see **build-live-game** | + +## By target platform (Step 2) + +Platform support is mostly Editor **modules** (installed in Step 4), not packages. Package-wise: + +| Platform | Consider | +|---|---| +| Mobile (iOS/Android) | Keep dependencies lean; URP over HDRP; Addressables for download size; monetization below | +| WebGL | URP (not HDRP); small footprint; avoid heavy packages | +| Desktop / Console | URP or HDRP depending on fidelity target | + +## By monetization (Step 2) — install now, integrate via the dedicated skill + +| Goal | Package | Integration skill | +|---|---|---| +| In-app purchases | `com.unity.purchasing` | **implement-in-app-purchases** | +| Ads / mediation | `com.unity.services.levelplay` | **levelplay-unity-integration** | +| Accounts, cloud save, economy, remote config, leaderboards, analytics | see the UGS package table | **build-live-game** | + +Install the package(s) here so the manifest is complete, but do the actual wiring by invoking +the matching skill after the skeleton exists (Step 7). For the full UGS package/version matrix +(`com.unity.services.core`, `authentication`, `cloudsave`, `cloudcode`, `economy`, +`remote-config`, `analytics`, etc.), read the **build-live-game** skill. + +## Output + +Produce a deduplicated list of package IDs and pass it to the installer script in +[package-manager-api.md](package-manager-api.md). Read it back to the user before installing. From ca978660fe8fd8402c73c78e28871dbe26cf21ed Mon Sep 17 00:00:00 2001 From: Etienne Date: Tue, 7 Jul 2026 15:58:26 -0400 Subject: [PATCH 2/2] new-unity-project: add UPM registry search for package discovery Add Client.SearchAll()/Client.Search() (PackageSearch bootstrap method) for in-Editor discovery, plus a curl https://packages.unity.com/ metadata query for the terminal. Note the npm free-text search endpoint (-/v1/search) is unavailable on Unity's registry. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/new-unity-project/SKILL.md | 4 +- .../references/package-manager-api.md | 71 +++++++++++++++++++ .../references/select-packages.md | 33 +++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/skills/new-unity-project/SKILL.md b/skills/new-unity-project/SKILL.md index 07e56c8..dc248d9 100644 --- a/skills/new-unity-project/SKILL.md +++ b/skills/new-unity-project/SKILL.md @@ -150,7 +150,9 @@ step via `unity projects create ... --vcs github ...` or `unity projects link vc Map the brief (Step 1) and platforms/monetization (Step 2) to a concrete package list. See [references/select-packages.md](references/select-packages.md) for the genre/look/platform → -package mapping and version guidance. +package mapping and version guidance. That list is a starting point — **search the UPM registry** +to discover packages beyond it and confirm ids/versions, via `Client.SearchAll()` in-Editor or a +`curl https://packages.unity.com/` metadata query (see select-packages.md). Install them from C# using `UnityEditor.PackageManager.Client` — **not** by hand-editing `Packages/manifest.json`. Write a small editor script into the project and run it headless. diff --git a/skills/new-unity-project/references/package-manager-api.md b/skills/new-unity-project/references/package-manager-api.md index 074574a..a90b9c2 100644 --- a/skills/new-unity-project/references/package-manager-api.md +++ b/skills/new-unity-project/references/package-manager-api.md @@ -108,6 +108,77 @@ namespace ProjectBootstrap error-prone than one `Client.Add` per package. To also *remove* packages (e.g. drop a template's unwanted default), pass `packagesToRemove:`. +## Searching the registry + +To discover packages or verify ids/versions before building the install list (see +[select-packages.md](select-packages.md#discovering-and-verifying-packages)), use +`Client.SearchAll()` (all packages in the configured registries) or `Client.Search("")` (one +package). These are async, so they use the same poll-and-`Exit` pattern as the installer and must +be launched the same way (direct Editor invocation, **no** `-quit`). + +Write `Assets/Editor/ProjectBootstrap/PackageSearch.cs`: + +```csharp +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.PackageManager; +using UnityEditor.PackageManager.Requests; +using UnityEngine; + +namespace ProjectBootstrap +{ + public static class PackageSearch + { + const double TimeoutSeconds = 120; + static SearchRequest _request; + static double _deadline; + + // Invoke with: -executeMethod ProjectBootstrap.PackageSearch.SearchAll (NO -quit) + public static void SearchAll() + { + _request = Client.SearchAll(); // or Client.Search("com.unity.cinemachine") + _deadline = EditorApplication.timeSinceStartup + TimeoutSeconds; + EditorApplication.update += Poll; + } + + static void Poll() + { + if (_request == null) return; + if (!_request.IsCompleted) + { + if (EditorApplication.timeSinceStartup > _deadline) + { + EditorApplication.update -= Poll; + Debug.LogError("[PackageSearch] Timed out."); + EditorApplication.Exit(2); + } + return; + } + EditorApplication.update -= Poll; + + if (_request.Status == StatusCode.Success) + { + foreach (var p in _request.Result.OrderBy(p => p.name)) + Debug.Log($"[PackageSearch] {p.name}@{p.versions.latestCompatible} {p.displayName}"); + Debug.Log($"[PackageSearch] {_request.Result.Length} packages found."); + EditorApplication.Exit(0); + } + else + { + Debug.LogError($"[PackageSearch] Failed: {_request.Error?.message}"); + EditorApplication.Exit(1); + } + } + } +} +``` + +Run it with the same direct-Editor invocation shown below (swap the `-executeMethod` for +`ProjectBootstrap.PackageSearch.SearchAll`) and read the `[PackageSearch]` lines from the log. +`_request.Result` is a `PackageInfo[]`; each entry exposes `name`, `displayName`, `description`, +and `versions` (`.latest`, `.latestCompatible`, `.all`). + ## Run it headless (direct Editor invocation, no `-quit`) Resolve the Editor binary from the version, then run it in batch mode. The script owns quitting diff --git a/skills/new-unity-project/references/select-packages.md b/skills/new-unity-project/references/select-packages.md index 832518a..d539e90 100644 --- a/skills/new-unity-project/references/select-packages.md +++ b/skills/new-unity-project/references/select-packages.md @@ -10,6 +10,39 @@ chosen template (URP templates already include the render pipeline, Input System add what's missing. Don't pin exact versions unless a skill requires a minimum; `Client.Add` without a version resolves the latest compatible release. +The tables below are a starting point, not the whole registry. **Search the UPM registry** to +discover packages beyond this list, confirm an id exists, or check available versions before +installing — see [Discovering and verifying packages](#discovering-and-verifying-packages). + +## Discovering and verifying packages + +Two ways to search, depending on whether the Editor is involved: + +**In-Editor — the PackageManager Client API (preferred; same async pattern as the installer).** +`Client.SearchAll()` returns every package available in the project's configured registries +(the Unity registry plus any scoped registries), each with all its versions and metadata — this +is what the Package Manager window's search filters over. `Client.Search("")` inspects a +single package. Use this to discover candidates and verify ids/versions before building the +install list. A ready-to-run `PackageSearch` method is in +[package-manager-api.md](package-manager-api.md#searching-the-registry). + +**Terminal — query the npm-compatible registry directly** (no Editor needed) to confirm a known +id exists and list its versions: + +```bash +# Full metadata for one package: versions{}, dist-tags.latest, description, dependencies +curl -s https://packages.unity.com/com.unity.cinemachine | python3 -m json.tool | head -40 + +# Just the latest published version +curl -s https://packages.unity.com/com.unity.cinemachine \ + | python3 -c "import sys,json;print(json.load(sys.stdin)['dist-tags']['latest'])" +``` + +Note: the registry supports fetching a **known** package id, but **not** free-text search over +HTTP (the npm `-/v1/search` endpoint is not available — it 404s). For keyword discovery, use +`Client.SearchAll()` in-Editor, or the Package Manager window / the +[Unity package documentation](https://docs.unity3d.com/Manual/pack-keys.html). + ## Foundation (almost every project) | Need | Package | Notes |