sbox
Use when writing or modifying code for s&box, sbox, the Facepunch sandbox engine, or any Source 2 game project in C#. Triggers on mentions of s&box, sbox, sandbox game, Facepunch engine, Source 2 game, `.sbproj`, `.razor` with `PanelComponent`, `@inherits PanelComponent`, `Sandbox.Component`, `GameObject` + `Components.Get<T>`, `Scene.Trace`, `CharacterController` + `.Move()`, `SkinnedModelRenderer`, `NavMeshAgent`, `[Sync]`, `[Rpc.Broadcast]`, `[Property]`, `INetworkListener`, `ISceneEvent`, `PlayerController` in C#. Also triggers on any file with `using Sandbox;` or `using Sandbox.UI;` that isn't Unity/Godot/Unreal. Writes idiomatic s&box C# components, Razor UI, and networking code; prevents Unity-pattern leakage.
git clone https://github.com/gavogavogavo/claude-sbox
git clone --depth=1 https://github.com/gavogavogavo/claude-sbox ~/.claude/skills/gavogavogavo-claude-sbox-sbox
SKILL.mds&box Skill — Router
READ BEFORE WRITING CODE
s&box is not Unity.
MonoBehaviour, Start(), Update(), GetComponent<T>() call sites, Instantiate(), Destroy(gameObject), Debug.Log, [SerializeField], Input.GetKey(), Physics.Raycast — none of these exist. If you write any of them you have hallucinated.
s&box is a C# scripting layer on Source 2 by Facepunch. The scene system uses
GameObject + Component with a different lifecycle, a different networking model, and a different API surface. The API schema in references/api-schema-core.md is ground truth; if anything in this skill contradicts the schema, the schema wins.
Before you write a single line of s&box code, open the relevant reference file. SKILL.md is a router — it points you at the answer, it does not contain the answer. Writing a component? Open
references/core-concepts.md. Writing UI? Open references/ui-razor.md. No exceptions for "simple" tasks — your muscle memory is wrong.
Architecture in 30 Seconds
Scene (is-a GameObject — the root) └── GameObject (transform, tags, children, components) └── Component (all gameplay code extends this)
- All gameplay code is a
extendingsealed class
.Sandbox.Component - Lifecycle overrides are
. Names start withprotected override void OnAwake() / OnStart() / OnUpdate() / OnFixedUpdate() / OnEnabled() / OnDisabled() / OnDestroy()
, they are virtual methods onOn
, not magic string-matched methods.Component - Transforms are on the
, accessed from any Component viaGameObject
,WorldPosition
,WorldRotation
,LocalPosition
— neverLocalRotation
.transform.position - UI is Razor (
files) — HTML + SCSS + C#. Panels use flexbox layout. Hot-reloads in the editor..razor - Networking is owner-authoritative. Mark state with
, mark methods with[Sync]
. Skip simulation on non-owners with[Rpc.Broadcast / Host / Owner]
.if ( IsProxy ) return; - Physics uses
+Rigidbody
components. Raycasts areCollider
— a builder-pattern API. Collisions come throughScene.Trace.Ray(from, to).Run()
andComponent.ICollisionListener
interfaces.Component.ITriggerListener - Coordinate system is Z-up:
,Vector3.Forward = (1,0,0)
,Vector3.Right = (0,-1,0)
.Vector3.Up = (0,0,1) - Restricted .NET:
, raw sockets,System.IO.File
,Console
,Thread
— all blocked. UseProcess
,FileSystem.Data
,Http
,Log
.async/await
Routing Table — "I need to…"
Match the task, open the file. Do not guess; open the file.
| Task | Read |
|---|---|
| Understand the scene/GameObject/Component model | |
Write a (lifecycle, , Tags, async) | |
| Spawn / clone / destroy a prefab | → Prefabs |
Fire a scene event () | → Scene Events |
Write a | → GameObjectSystem |
Use / / bones / animgraph | → Rendering |
Use , any , joints | → Physics |
Use for movement | → CharacterController |
Use the full (built-in FPS/TPS) | → Gameplay |
| Set up a camera, HUD painter, post-processing | → Camera, Post-Processing |
| Use lights, fog, envmap probes, skybox | → Lighting, Environment |
Add audio (, ) | → Audio |
Use , , query NavMesh | → Navigation |
| Create particles, decals, trails, beams | → Effects, Rendering |
Write a Razor UI panel (, , ) | |
Style with SCSS — flexbox, transitions, / , | → Styling, Layout System, Transitions |
Use built-in controls (, , , ) | → Built-in Controls |
| Build a world-space panel or a NavigationHost app | → WorldPanel, Navigation |
Set up a lobby, connect/disconnect, query | → Lobby & Connection |
Network an object (, , ownership) | → Networked Objects, Ownership |
Use / / / / | → [Sync] Properties |
Write RPCs (, , caller info, filtering) | → RPC Messages |
React to connections (, , snapshot data) | → Network Events |
Use for host vs client initialization | → Scene Startup |
Dedicated server / / user permissions | → Dedicated Servers |
| Poll keyboard/mouse/controller input, haptics, glyphs | → Input |
| Raycast / sphere / box / capsule trace with tag filters | → SceneTrace |
Access , gravity, physics events | → Physics World |
| Implement collision/trigger listeners | → Collision System |
Use / / / / / / | → Math Types |
Use , , , | → Time |
Draw debug gizmos (, ) | → Gizmo |
Need the full signature of , , , , etc. | |
| Look up whether a given type exists & what it does | |
| See a complete worked example of a pattern before writing your own | |
Unity → s&box Translation Table
Any time you write one of the left column, you are hallucinating. Use the right column.
| Unity / Wrong | s&box / Correct |
|---|---|
| |
| |
| |
| |
| |
/ | / |
| |
| |
| |
| (or ) |
| |
| |
| |
| |
/ | / / |
| |
| |
in | is fine; also for ancestor/descendant searches |
/ | / / |
| |
| Implement |
| Implement |
| (builder; returns ) |
| |
| |
| |
| (capital V) |
| — actions are strings configured in Project Settings |
| |
/ | () |
| () |
| |
| |
with | with ; call as |
| |
| |
/ / | / / |
| |
| |
| |
| |
| / |
| — s&box is Z-up; re-check every literal direction |
| or |
| |
| (or ) |
| / |
| / |
reads AND moves rigidbody | Read input in , move in |
If a Unity pattern isn't in the table, assume it doesn't exist in s&box and look it up in
references/api-schema-core.md before writing it.
The Ten Rules You Must Not Break
- Every gameplay class extends
. NotComponent
, notMonoBehaviour
, notobject
— justScriptableObject
. Mark itComponent
unless inheritance is required.sealed - Lifecycle methods are
. If you wroteprotected override void On*()
instead ofvoid Update()
, your code does nothing.protected override void OnUpdate() - Serialize fields with
. Not[Property]
, not[SerializeField]
alone.public
both shows in the inspector and saves to prefab/scene.[Property] - Networked state uses
. Only the object owner may assign. Everyone else sees replicated values. Combine with[Sync]
for change callbacks.[Change(nameof(Method))] - Guard networked logic with
. Every component that reads input or drives movement starts with this line — otherwise every client tries to move every player.if ( IsProxy ) return; - Ray/box/sphere traces go through
. It's a builder:Scene.Trace
returns aScene.Trace.Ray(from, to).UseHitboxes(true).WithoutTags(new[]{"player"}).Run()
. NeverSceneTraceResult
.Physics.Raycast - UI is Razor + flexbox.
is the default and effectively the only layout.display: flex
does not exist. Propertiesdisplay: block
/:intro
animate creation and deletion. Every root panel overrides:outro
to control re-render.BuildHash() - Coroutines don't exist — use
.async Task
,await Task.DelaySeconds( n )
. Fire-and-forget withawait Task.Frame()
. The_ = MyTask();
property scopes cancellation to the GameObject lifetime.Component.Task - Never touch blocked .NET APIs.
,System.IO.File
,Console
, raw sockets,Thread
— useSystem.Net.Http.HttpClient
,FileSystem.Data
,Log
,async/await
instead. Code that references these won't compile in the sandbox.Http - Look up every API before you use it. The schema is ground truth. If you can't find a method in
orapi-schema-core.md
, either you're guessing (stop) or it's nested on a specific type (search the topical reference).api-schema-extended.md
Project Structure (s&box Game)
An s&box game project (
.sbproj) typically looks like:
MyGame/ ├── MyGame.sbproj # project manifest ├── code/ # C# source (gameplay code) │ ├── GameManager.cs │ ├── Player.cs │ ├── weapons/ │ │ └── Rifle.cs │ └── ui/ │ ├── Hud.razor # Razor panel │ ├── Hud.razor.scss # auto-loaded stylesheet │ └── InventoryPanel.razor ├── prefabs/ # .prefab files ├── scenes/ # .scene files ├── models/ # .vmdl, .vmdl_c ├── materials/ # .vmat, .vmat_c ├── sounds/ # .sound, .wav, .mp3 ├── ui/ # UI images, textures └── localization/ └── en/ └── mygame.json
Notable:
and.razor
files pair by name — the stylesheet auto-loads when the panel is built..razor.scss
files are hot-reloaded in the editor; saving a file rebuilds and re-injects within seconds..cs- Asset paths in code are forward-slash strings rooted at the project:
.Model.Load( "models/dev/box.vmdl" ) - There is no
folder; paths are flat under the project root.Assets/
A Reference Component (Shape Only — Not the Content)
This is the shape of a component. The content depends on what you're building — read the referenced file, then write it.
using Sandbox; public sealed class MyComponent : Component { [Property] public float Speed { get; set; } = 200f; [Property] public GameObject Target { get; set; } [Sync] public int Score { get; set; } TimeSince _lastAction; protected override void OnStart() { // runs once before first update } protected override void OnUpdate() { if ( IsProxy ) return; // networking guard if ( !Target.IsValid() ) return; // per-frame logic (input, visuals, camera) } protected override void OnFixedUpdate() { if ( IsProxy ) return; // physics / movement — deterministic timestep } [Rpc.Broadcast] public void PlayEffect( Vector3 position ) { // runs on all clients — cosmetic / non-authoritative } }
For complete runnable examples — a full FPS controller, a networked player, a Razor HUD, a hitscan weapon, a NavMeshAgent AI, a physics grenade, a prefab spawner, a trigger pickup — see
references/patterns-and-examples.md.
Gotchas Captured From Real Builds
These are things that will bite you. They're documented deeper in the reference files; this is the quick-lookup list.
parameter names areICollisionListener
, notcollision
(the raw docs are wrong about this).other
,Color
,Capsule
,Vector3
,Rotation
,Angles
,Transform
,BBox
are global types, notRay
.Sandbox.*
andLobbyConfig
live inLobbyPrivacy
— you needSandbox.Network
.using Sandbox.Network;
is-aScene
— it is the root GameObject.GameObject
walks the tree.Scene.GetAllObjects(true)- Most
interfaces are nested onComponent.ISomething
:Component
,Component.IDamageable
,Component.ICollisionListener
,Component.ITriggerListener
,Component.INetworkListener
. ButComponent.INetworkSpawn
is top-levelIGameObjectNetworkEvents
.Sandbox.IGameObjectNetworkEvents
requires theComponentList.GetOrCreate<T>( FindMode )
arg. For the common "on this GameObject" case, useFindMode
onGetOrAddComponent<T>()
orGameObject
instead.Component
/SceneTrace.WithoutTags
/WithAnyTags
takeWithAllTags
— notstring[]
. Passparams
, or usenew[] { "tag" }
for the single-tag case.WithTag(string)
isGame.Random
—System.Random
,NextSingle()
work directly. TheNext(n)
extension exists but requires aFromList
;defVal
is simpler.list[Game.Random.Next(list.Count)]
is a static facade. Actual methods are onFileSystem
, accessed viaBaseFileSystem
(game user data) orFileSystem.Data
(mounted content).FileSystem.Mounted- There is no standalone
class — it'sLog
, but the globalSandbox.Diagnostics.Logger
instance works fine everywhere.Log
has 4 parameters (the 4th isPlayerController.TraceBody
), not 3.heightScale- Operators (
,Rotation * Rotation
) aren't listed in the API schema because they're systematically excluded — they do exist, use them normally.Vector3 * Rotation
is inNavigationHost
, needsSandbox.UI.Navigation
in your Razor file.@using Sandbox.UI.Navigation
Verification Loop (When In Doubt)
If you're about to write an API call and you're not sure it exists:
- Check the topical file for the area first (
,networking.md
, etc.). Topical files include inline signatures for the APIs they cover.ui-razor.md - If not there, check
. It has full signatures for the ~50 most-used types.api-schema-core.md - If not there, check
. It's a namespace-organized index of 738 more types — find the type, then look up full signatures elsewhere if needed.api-schema-extended.md - If a method or property is in NONE of the above, it does not exist. Do not write it. Revisit your design — there is almost certainly an s&box-idiomatic way to do what you want.
The schema under
raw/api-schema.json is not shipped with the skill and is not for you to read directly; the reference files are the curated, searchable view of it.
This file is a router. Reference files teach. Do not answer s&box questions from SKILL.md alone — open the relevant reference and read it.