drawnui/drawnui.net/drawnui-game

Claude Code and agent skill by drawnui/drawnui.net

Trust tier 3
  • community
  • ext:[{"type":"hook","description":"Pre/post lifecycle hooks"},{"type":"plugin","description":"Custom plugin integration"}]
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when creating or modifying games built on DrawnUi.Gaming.DrawnGame for MAUI, Blazor WASM, pure WebAssembly (DrawnUi.Web), OpenTK and WPF targets. Covers game loop, sprites, physics, canvas rendering, input, and cross-platform game patterns.

Install

npx vskill@latest install drawnui/drawnui.net/drawnui-game

Semi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard

SKILL.md

DrawnUI Game Development Skill

Use this skill when creating or modifying games built on DrawnUi.Gaming.DrawnGame for MAUI and/or Blazor WASM targets (the same base class ships for pure WebAssembly, OpenTK and WPF).

HeadGame packagePong sample (shared src/Shared/Samples/Pong.Shared)
MAUIDrawnUi.Maui.Gamesrc/Maui/Samples/MauiPong
Blazor WASMDrawnUi.Blazor.Gamesrc/Blazor/Samples/BlazorSandbox (Pages/PongPage.razor)
Pure WebAssemblyDrawnUi.Web.Gamesrc/Wasm/Samples/PongWeb (see drawnui-web-app skill)
OpenTKDrawnUi.OpenTk.Gamesrc/OpenTk/Samples/OpenTkPong
WPFDrawnUi.Wpf.Gamesrc/Wpf/Samples/WpfPong

Every addon compiles the same src/SharedGame sources (DrawnGame.cs, Game.Input.cs, IGame.cs).

IMPORTANT: This skill must always be updated when new findings are discovered during game development - patterns, pitfalls, API quirks, project structure details, platform differences. Update this file before closing any game-related task that produced reusable knowledge.
IMPORTANT: For game examples and samples, never keep the whole game in one file. Split immediately by concern using partials, starting with GameName.cs, GameName.UI.cs, and GameName.Gestures.cs, then add more slices like GameName.Settings.cs, GameName.Theme.cs, GameName.Audio.cs, or GameName.Pieces.cs as needed. If the project uses .projitems, add every new partial file explicitly.
IMPORTANT: For puzzle trays or refill batches, do not generate the next pieces purely at random when the live board state matters. Build the next batch from the current occupancy so at least some pieces fit the available gaps, and prefer batches whose intended placements can clear a row or column when the board allows it. Only fall back to random fillers for leftover tray slots when the board is too constrained to support a full planned batch.
IMPORTANT: When a puzzle tray is intentionally planned around the first two pieces clearing lines, do not evaluate the third fallback piece only against the current board. If the third piece cannot fit now, choose it against the post-collapse board state produced by those first two planned moves so the tray remains solvable through the intended clear sequence.
IMPORTANT: Discuss DrawnUI game rendering and FX architecture like a senior game developer, not a cheerleader. Push back when the proposed approach is brittle, overfit, or engine-hostile. Prefer clean rendering contracts, explicit effect scopes, and theme material sets over giant all-in-one shaders or ad hoc control-tree hacks.
IMPORTANT: During live gameplay, never create new controls on demand. Prewarm fixed-size pools for every gameplay visual that can appear at runtime: board cells, tray-piece tiles, preview tiles, FX tiles, and transient host layers. While the game is running, acquire from the pool, reconfigure, show, hide, and return to the pool. If the pool runs dry, treat that as a bug in pool sizing or release flow, not as a reason to allocate a new control.
IMPORTANT: For board or field shader effects in grid-based puzzle games, separate source region from output scope. Use a dedicated field-sized FX layer when glow, particles, or dissolve can extend beyond the triggering tiles; keep local scope only for genuinely local effects. Prefer grid/cell masks or state textures over arrays of arbitrary rects.

Solution / project templates

A) MAUI only
MyGame/
MyGame.Mobile.csproj (Sdk="Microsoft.NET.Sdk", UseMaui=true)
MainPage.cs
Game/
MyGame.cs
MyGame.Loop.cs
MyGame.Ui.cs
MyGame.Input.cs
Platforms/Android|iOS|Windows|MacCatalyst/...

`MyGame.Mobile.csproj`

xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net10.0-android;net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">
$(TargetFrameworks);net10.0-windows10.0.19041.0
</TargetFrameworks>
<OutputType>Exe</OutputType>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationTitle>My Game</ApplicationTitle>
<ApplicationId>com.mycompany.mygame</ApplicationId>
</PropertyGroup>
<ItemGroup>
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
<MauiFont Include="Resources\Fonts\*" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.80" />
<PackageReference Include="DrawnUi.Maui.Game" Version="1.10.8.13" />
</ItemGroup>
</Project>

B) Blazor WASM only
MyGame/
MyGame.Web.csproj (Sdk="Microsoft.NET.Sdk.BlazorWebAssembly")
Program.cs
App.razor
Pages/
GamePage.razor ← entry point
Game/
MyGame.cs
MyGame.Loop.cs
wwwroot/
Images/ Sounds/ Music/ ← assets go here
index.html

`MyGame.Web.csproj`

xml
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<WasmBuildNative>true</WasmBuildNative>
<DefineConstants>$(DefineConstants);BROWSER</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.7" PrivateAssets="all" />
<PackageReference Include="DrawnUi.Blazor.Game" Version="1.10.8.13" />
</ItemGroup>
<ItemGroup>
<TrimmerRootAssembly Include="SkiaSharp" />
</ItemGroup>
</Project>

C) MAUI + Blazor shared solution (Arkanoid pattern)
MyGame.sln
src/
Shared/ ← shared game logic, no output
MyGame.Shared.shproj
MyGame.Shared.projitems
GlobalAliases.cs ← global using MauiGame = DrawnUi.Gaming.DrawnGame;
Game/
MyGame.cs
MyGame.Loop.cs
MyGame.Ui.cs
MyGame.Input.cs
MyGame.Sound.cs ← uses IAudioService interface
Internals/
GameState.cs
IReusableSprite.cs
Sprites/
BallSprite.cs ...
Sound/
IAudioService.cs ← interface; impl stays in platform project
Mobile/ ← MAUI head project
MyGame.Mobile.csproj
MauiProgram.cs
MainPage.cs
Game/
Sound/
MobileAudioService.cs ← IAudioService impl for MAUI
Platforms/...
Resources/Raw/... ← MauiAsset (audio, images)
Web/MyGame.Web/ ← Blazor head project
MyGame.Web.csproj
Program.cs
Pages/
GamePage.razor
Sound/
WebAudioService.cs ← IAudioService impl using JS interop
wwwroot/
Images/ Sounds/ Music/ ← assets (copied manually from Mobile/Raw)

`MyGame.Shared.shproj` (boilerplate, one GUID)

xml
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>YOUR-GUID-HERE</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition="Exists(...)" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\...\Microsoft.CodeSharing.Common.Default.props"
Condition="Exists(...)" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\...\Microsoft.CodeSharing.Common.props"
Condition="Exists(...)" />
<PropertyGroup />
<Import Project="MyGame.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\...\Microsoft.CodeSharing.CSharp.targets"
Condition="Exists(...)" />
</Project>

`MyGame.Shared.projitems` (lists every shared .cs file)

xml
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>YOUR-GUID-HERE</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>MyGame</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)GlobalAliases.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\MyGame.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\MyGame.Loop.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\MyGame.Ui.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\MyGame.Input.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\MyGame.Sound.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\Internals\GameState.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\Internals\IReusableSprite.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Game\Sprites\BallSprite.cs" />
<!-- add every shared .cs file here -->
<Compile Include="$(MSBuildThisFileDirectory)Game\Sound\IAudioService.cs" />
</ItemGroup>
</Project>

MAUI head imports shared:

xml
<!-- In MyGame.Mobile.csproj -->
<Import Project="../Shared/MyGame.Shared.projitems" Label="Shared" />
<ItemGroup>
<PackageReference Include="DrawnUi.Maui.Game" Version="1.10.8.13" />
</ItemGroup>

Blazor head imports shared:

xml
<!-- In MyGame.Web.csproj -->
<DefineConstants>$(DefineConstants);BROWSER</DefineConstants>
<!-- ... -->
<Import Project="../../Shared/MyGame.Shared.projitems" Label="Shared" />
<ItemGroup>
<PackageReference Include="DrawnUi.Blazor.Game" Version="1.10.8.13" />
</ItemGroup>

`GlobalAliases.cs` (in Shared root)

csharp
global using MauiGame = DrawnUi.Gaming.DrawnGame;

Platform guards in shared code
csharp
// Audio init example in shared game class:
#if BROWSER
BeginStartupAssetLoading(); // Blazor: JS-interop preload
#else
if (USE_SOUND)
_ = InitializeAudioAsync(); // MAUI: native audio
#endif
// Focus (keyboard) - Blazor doesn't support Focus():
#if !BROWSER
Focus();
#endif
// Blazor-only compat helpers go in a file guarded by #if BROWSER

Asset management: shared vs platform
Asset typeMAUIBlazor
Images/SpritesResources/Raw/Images/ as MauiAssetwwwroot/Images/ (static file)
Audio filesResources/Raw/Sounds/ as MauiAssetwwwroot/Sounds/ (JS fetch)
FontsResources/Fonts/ as MauiFontwwwroot/fonts/ in index.html
LoadingFileSystem.OpenAppPackageFileAsync(path)SkiaImageManager.PreloadImages(paths)

Maintain both wwwroot/ and Resources/Raw/ as parallel copies (no symlink; just duplicate).


Base class

csharp
public class MyGame : DrawnUi.Gaming.DrawnGame // alias: MauiGame = DrawnUi.Gaming.DrawnGame

DrawnUi.Gaming.DrawnGame (source src/SharedGame/DrawnGame.cs) extends SkiaLayout. Key members:

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Extension points

  • hookPre/post lifecycle hooks
  • pluginCustom plugin integration

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/drawnui/drawnui.net/drawnui-game/badge)](https://verified-skill.com/skills/drawnui/drawnui.net/drawnui-game)

Something wrong with this skill or its page? Tell us.