# Sample Project Setup

> Sample Project Setup for FlatRedBall2. Use when creating a new sample project, setting up a .csproj, configuring MonoGame content pipeline, or troubleshooting 'Cannot find a manifest file' / 'dotnet-mgcb does not exist' build errors. Covers the complete checklist for new sample projects.

- Skill: `vchelaru/sample-project-setup` (Agent Skill)
- Install (CLI): `npx skillmds@latest add vchelaru/sample-project-setup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vchelaru/sample-project-setup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: vchelaru (https://skillmd.com/u/vchelaru)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vchelaru/sample-project-setup

---


# Sample Project Setup

> **See `content-boundary` skill first.** New projects should scaffold placeholder content files (TMX, Gum, coefficients JSON) rather than hardcoding content in C#. Set the project up so the human can drop in real art, levels, and UI without recompiling.

How to create a new sample project (`.csproj`) under `samples/`. Follow this checklist exactly — two of these steps are easy to forget and cause hard-to-diagnose build failures.

> **Do not read existing sample files to verify these templates.** The content below is authoritative. Only read source files if something fails and you have a specific reason to doubt the template.

---

## Checklist

### 1. Create the directory and `.csproj`

Copy the structure from an existing sample (e.g., `AnimationChainSample`). The minimal `.csproj`:

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <RollForward>Major</RollForward>
    <PublishReadyToRun>false</PublishReadyToRun>
    <TieredCompilation>false</TieredCompilation>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="MonoGame.Framework.DesktopGL" />
    <PackageReference Include="MonoGame.Content.Builder.Task" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\src\FlatRedBall2.csproj" />
  </ItemGroup>
</Project>
```

No `Version` attribute on either `PackageReference` — the repo uses NuGet Central Package Management, so every version is pinned once in the root `Directory.Packages.props`. If restore complains a package has no version, add it there instead of on the `PackageReference`.

Do **not** pin `Apos.Shapes` — version flows transitively from the engine. Its shader is embedded in the assembly, so it needs no content-pipeline wiring.

### 1b. Add `YourSample.slnx` (REQUIRED — easy to forget)

A sibling solution file lets the user open the sample in VS / Rider without loading every other sample in the repo. Minimal content — the sample csproj, the engine csproj, and the engine's `AnimationChain.Common` dependency:

> **Anti-precedent warning.** Roughly a third of the existing samples in `samples/auto/` are missing this file — that's drift, not the rule. If you scaffolded a new project by copying a sibling sample, the `.slnx` may not be there to copy. Add it from the template below; do not infer the pattern from the directory listing of one neighbor.


```xml
<Solution>
  <Project Path="../../src/FlatRedBall2.csproj" />
  <Project Path="../../src/AnimationChain.Common/AnimationChain.Common.csproj" />
  <Project Path="YourSample.csproj" />
</Solution>
```

Include `AnimationChain.Common` even though the sample never references it directly: `FlatRedBall2.csproj` project-references it, and IDE solution restore (Rider/VS) needs every project in the reference graph. Omit it and the solution fails to restore with `NU1105: Unable to find project information for ...AnimationChain.Common.csproj`. The `dotnet` CLI follows the `ProjectReference` transitively, so a `dotnet build`/`run` of the csproj hides the gap — the error only surfaces when someone opens the `.slnx`.

### 2. Add `.config/dotnet-tools.json` (REQUIRED — easy to forget)

Without this file, the first build fails with **"Cannot find a manifest file"** / **"dotnet-mgcb does not exist"**, even though other samples build fine (they have the file already).

Copy from any existing sample:
```
samples/AnimationChainSample/.config/dotnet-tools.json  →  samples/YourSample/.config/dotnet-tools.json
```

Content (do not modify versions):
```json
{
  "version": 1,
  "isRoot": true,
  "tools": {
    "dotnet-mgcb": {
      "version": "3.8.5.1",
      "commands": ["mgcb"]
    },
    "dotnet-mgcb-editor": {
      "version": "3.8.5.1",
      "commands": ["mgcb-editor"]
    },
    "dotnet-mgcb-editor-linux": {
      "version": "3.8.5.1",
      "commands": ["mgcb-editor-linux"]
    },
    "dotnet-mgcb-editor-windows": {
      "version": "3.8.5.1",
      "commands": ["mgcb-editor-windows"]
    },
    "dotnet-mgcb-editor-mac": {
      "version": "3.8.5.1",
      "commands": ["mgcb-editor-mac"]
    }
  }
}
```

Then restore the tool (once per project directory):
```
cd samples/YourSample
dotnet tool restore
```

### 3. Add `Content/Content.mgcb` (REQUIRED — easy to forget)

`MonoGame.Content.Builder.Task` needs this file to drive the content pipeline for any textures, fonts, or audio the project loads via `ContentManager`. Without it, that content fails to build.

Create `Content/Content.mgcb` in the project directory with this minimal content:

```
#----------------------------- Global Properties ----------------------------#

/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False

#-------------------------------- References --------------------------------#


#---------------------------------- Content ---------------------------------#

```

Even a project with no custom content yet should keep this file present — `MonoGame.Content.Builder.Task` expects it, and it's one less thing to add later.

### 4. Ask about Gum mode (REQUIRED — do not skip)

Before writing any game code, ask the user:

> "Will this project use Gum for UI (menus, HUD, score labels, any text)? If so, which mode?
> 1. **Code-only** — UI defined in C#, no .gumx file
> 2. **Project + dynamic** — .gumx editable in the Gum editor, runtime string lookup
> 3. **Project + codegen** — .gumx + generated strongly-typed C# classes"

Then invoke the `gumcli` skill and follow its instructions for the chosen mode before writing any screen or entity code.

### 5. Add `Program.cs` and `Game1.cs`

```csharp
// Program.cs
using var game = new YourSample.Game1();
game.Run();

// Game1.cs — needs `using Microsoft.Xna.Framework.Graphics;` for GraphicsProfile.
public Game1()
{
    _graphics = new GraphicsDeviceManager(this);
    // REQUIRED — Apos.Shapes needs SM 4.0+. Default GraphicsProfile is Reach (SM 2.0),
    // which crashes at startup with "Shader model 4.0 is not supported by the current
    // graphics profile 'Reach'". MonoGame tops out at HiDef; KNI uses FL10_0.
#if KNI
    _graphics.GraphicsProfile = GraphicsProfile.FL10_0;
#else
    _graphics.GraphicsProfile = GraphicsProfile.HiDef;
#endif
    Content.RootDirectory = "Content";  // REQUIRED for ContentManager.Load of textures/fonts/audio
    IsMouseVisible = true;              // set to false only for keyboard/gamepad-only games
}

protected override void Initialize()
{
    base.Initialize();
    // Sizes the window, initializes, and starts the screen. A Glue project instead:
    // Initialize(this, "Content/FrbEditor/YourGame.gluj") — path relative, never rooted.
    FlatRedBall2.FlatRedBallService.Default.Initialize<YourScreen>(this);
}
protected override void Update(GameTime gt)
{
    if (Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit();
    FlatRedBall2.FlatRedBallService.Default.Update(gt);
    base.Update(gt);
}
protected override void Draw(GameTime gt)
{
    FlatRedBall2.FlatRedBallService.Default.Draw();
    base.Draw(gt);
}
```

### 6. Build

```
dotnet build samples/YourSample/YourSample.csproj
```

---

## Why the Tools File Is Needed

`MonoGame.Content.Builder.Task` invokes `mgcb` as a local dotnet tool to build any MonoGame content. Local tools require a manifest file (`.config/dotnet-tools.json`) to locate the tool. Existing samples work because their manifests are already present and `dotnet tool restore` was run when the repo was first set up.

A new project directory has no manifest, so the content build fails. The fix is to add the manifest (identical to all other samples) and run `dotnet tool restore` once.

