bc.Gem
0.0.15
dotnet add package bc.Gem --version 0.0.15
NuGet\Install-Package bc.Gem -Version 0.0.15
<PackageReference Include="bc.Gem" Version="0.0.15" />
<PackageVersion Include="bc.Gem" Version="0.0.15" />
<PackageReference Include="bc.Gem" />
paket add bc.Gem --version 0.0.15
#r "nuget: bc.Gem, 0.0.15"
#:package bc.Gem@0.0.15
#addin nuget:?package=bc.Gem&version=0.0.15
#tool nuget:?package=bc.Gem&version=0.0.15
bc.Gem
bc.Gem is a lightweight, MonoGame-friendly framework that provides scene management, an action/gesture input runtime, and supporting utilities for game loops and state history.
Features
- Scene lifecycle management (activate/show/hide/deactivate) with focus and render layers.
- Action-surface input system with typed gestures and phases.
- Device discovery and state history tracking (keyboard, mouse, gamepad).
- Scene transitions and state persistence helpers.
Requirements
bc.Gem targets Microsoft.Xna.Framework types. Add the MonoGame package that matches your target platform.
dotnet add package MonoGame.Framework.DesktopGL
Install
dotnet add package bc.Gem
Getting Started
This is a minimal path to a running scene manager with the input runtime.
1) Create a SceneInputContext
namespace MyGame;
public readonly record struct SceneInputContext(string Identity);
2) Create InputRuntime and SceneManager
using bc.Gem.Framework.Input;
using bc.Gem.Framework.Scenes;
using Microsoft.Xna.Framework;
public sealed class MyGame : Game
{
private readonly InputRuntime<string, SceneInputContext> _inputRuntime;
private readonly SceneManager _sceneManager;
public MyGame(IGameContext gameContext)
{
_inputRuntime = new InputRuntime<string, SceneInputContext>(id => new SceneInputContext(id));
var registry = new SceneRegistry();
var factoryRegistry = new SceneFactoryRegistry();
var stateStore = new SceneStateStore();
var activeScenes = new ActiveSceneSet(registry);
var focusChain = new FocusChain();
var renderSorter = new RenderSorter();
var router = new DemoSceneRouter();
_sceneManager = new SceneManager(
gameContext,
router,
registry,
factoryRegistry,
stateStore,
activeScenes,
focusChain,
renderSorter);
}
protected override void Update(GameTime gameTime)
{
_inputRuntime.Update(gameTime);
_sceneManager.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
_sceneManager.Draw(gameTime);
base.Draw(gameTime);
}
}
3) Define a Scene With Action-Surface Input
using bc.Gem.Framework;
using bc.Gem.Framework.Input;
using bc.Gem.Framework.Input.Actions;
using bc.Gem.Framework.Input.Contexts;
using bc.Gem.Framework.Input.Core;
using bc.Gem.Framework.Input.Devices.Core;
using bc.Gem.Framework.Input.Gestures;
using bc.Gem.Framework.Input.Handlers;
using bc.Gem.Framework.Scenes;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
public sealed class TitleScene : IScene
{
private const string StartActionId = "Start";
private readonly InputRuntime<string, SceneInputContext> _runtime;
private readonly ActionSurface _surface;
private readonly ActionGestureMapper _mapper;
private readonly ActionHandlerRegistry<SceneInputContext> _handlers;
private readonly InputContextDefinition<SceneInputContext> _context;
public TitleScene(InputRuntime<string, SceneInputContext> runtime)
{
_runtime = runtime;
_surface = new ActionSurface(new Dictionary<string, Type> { [StartActionId] = typeof(bool) });
_handlers = new ActionHandlerRegistry<SceneInputContext>(_surface.Actions);
_handlers.Register<bool>(StartActionId, GesturePhase.Performed, (_, _) => Start());
_mapper = new ActionGestureMapper(_surface);
_context = new InputContextDefinition<SceneInputContext>("Title", _surface, _handlers, _mapper);
}
public string Id => "Title";
public ScenePolicy Policy { get; } = new() { Participation = Participation.Input | Participation.Draw };
public SceneVisibility Visibility { get; set; } = SceneVisibility.Hidden;
public void OnShow()
{
if (_runtime.DeviceManager.TryGetStateHistory<KeyboardState>(
new DevicePath { Kind = DeviceKind.Keyboard, Index = 0 },
out var keyboard))
{
_mapper.Map(StartActionId, GesturePhase.Performed, keyboard.KeyPress(Keys.Enter));
}
_runtime.Router.SetActiveContexts(Id, [_context]);
}
public void OnHide() => _runtime.Router.Remove(Id);
public void HandleInput(GameTime gameTime) => _runtime.Router.Update(gameTime, Id);
public void LoadContent() { }
public void UnloadContent() { }
public void Update(GameTime gameTime) { }
public void Draw(GameTime gameTime) { }
public void OnEnter(IGameContext gameContext) { }
public void OnExit() { }
private void Start() { }
}
Input System Basics
- Define actions on an
ActionSurface(action id → value type). - Register behavior with
ActionHandlerRegistry(action id + phase → handler). - Map gestures to actions with
ActionGestureMapper. - Wrap those in an
InputContextDefinitionand activate viaInputRuntime.Router. - Call
Router.Update(gameTime, identity)inHandleInput.
Gesture Mapping Tips
Use the gesture helpers for common devices:
KeyboardGestures.KeyPress,KeyPressAndHold,KeyDoubleTapMouseGestures.ButtonPress,ButtonRelease,PositionGamePadGestures.ButtonPress,LeftThumbstick,DPad
Scene Transitions
Use SceneTransition to express changes:
_router.Enqueue(new SceneTransition(
SceneTransitionKind.Composite,
activate: ["Gameplay"],
hide: ["Title"],
focusOrder: ["Gameplay"]));
activate/deactivateload and unload scenes.show/hidetoggle visibility while keeping the scene active.focusOrdercontrols input focus order.
Rebinding Controls
ActionGestureMapper only adds mappings; it does not replace them.
For rebinding, create a new mapper and new context definition, then set it active again.
_mapper = new ActionGestureMapper(_surface);
// map new gestures
_context = new InputContextDefinition<SceneInputContext>("Gameplay", _surface, _handlers, _mapper);
_runtime.Router.SetActiveContexts(Id, [_context]);
Docs
doc/Scene Management Quickstart.mddoc/Screen Lifecycle.mddoc/Input System Overview.mddoc/Getting Started - Input System.mddoc/Input Contexts.mddoc/Input Gesture Lifecycle.md
Key Namespaces
bc.Gem.Framework(scenes, state, game helpers)bc.Gem.Framework.Scenes(scene manager, policies, transitions)bc.Gem.Framework.Input(input runtime, actions, gestures, devices)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- TestableIO.System.IO.Abstractions.Wrappers (>= 22.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.15 | 768 | 1/25/2026 |
| 0.0.13 | 133 | 1/22/2026 |
| 0.0.12 | 242 | 1/10/2026 |
| 0.0.11 | 225 | 1/4/2026 |
| 0.0.10 | 115 | 1/4/2026 |
| 0.0.9 | 127 | 1/4/2026 |
| 0.0.8 | 121 | 1/1/2026 |
| 0.0.7 | 116 | 1/1/2026 |
| 0.0.6 | 136 | 12/30/2025 |
| 0.0.5 | 116 | 12/30/2025 |
| 0.0.4 | 195 | 12/22/2025 |
| 0.0.3 | 194 | 12/21/2025 |
| 0.0.2 | 169 | 12/21/2025 |
| 0.0.1 | 158 | 3/1/2025 |