s&box gotchas I hit,
so you don't have to.
A growing pile of miscellaneous gotchas, fixes, and pipelines I ran into building s&box games: the kind of thing that quietly eats an afternoon. Every fix here was hit in a real project and stamped with the engine version it was verified on.
Where are you in the build?
// organized by what you're doing, not by subsystemNew project skeleton: .sbproj, folder layout, compile verification.
Blender / AI model → in-game, correct scale & facing.
Blends, ragdolls, retargeting mocap onto custom rigs.
Components, movement, save/load, owner-simulated networking.
Razor HUD that actually re-renders. The BuildHash trap.
.sound events by hand, looping, 3D positional resolution.
Triangle census, collider choice, what actually costs you.
sbox.game store, Play Fund, the whitelist divergence.
Coordinating agents to build a game: spec, ownership, tuning.
Windows / PowerShell / dotnet traps that corrupt source.
From the bench
// playable things I build with the same fixes
The games I build and ship on s&box, free to play. Berm drops you into a sculptable voxel world with friends. Every fix on this site came out of building it.

s&box libraries pulled straight out of shipped games: driving, accessory placement, onboarding, day and night, more as they ship. Install one and the source lands in your project, readable and yours.
Latest field notes
// freshest fixes off the workbenchThe [GameResource("Name","ext","desc")] attribute on a GameResource subclass now raises CS0618 obsolete. It is a warning, so a green dotnet build hides it unless the project treats warnings as errors. Switch to [AssetType] with named properties. The type still derives from GameResource, still writes an .ext file, and is still found by ResourceLibrary.GetAll<T>(). Only the declaring attribute changes, and the old Icon argument has no replacement.
A single-line XML doc comment that shares a line with the field it documents pulls the declaration into the comment. The compiler then sees no field at all. Nothing fails at the comment site. The break shows up later as a 'does not contain a definition' error wherever the field is used, which reads like a typo or a missing using. Put every XML doc comment on its own line, directly above the member.
A scene-authored component cannot resolve, inside its own OnStart, a component that another component creates inside that other component's OnStart. Authored beside is not authored before, so the binder looks up the target before it exists, gets null, and holds that null for the whole session behind one warning line. The whole feature does nothing while every part it depends on works. Bind lazily instead: retry the lookup on a short interval until the target resolves, and warn once if it never does.
A timeout accumulator gated on a control-signal sample (throttle > threshold) resets to zero on frames where the signal legitimately reads zero, so it never fills. A gear change drives the throttle magnitude through zero on a fixed cadence, and an unstick routine that alternates gears makes that happen forever, so a stuck vehicle is never declared wrecked. Drive give-up timers from ground-truth state, such as position progress since the last known-good, never from a control signal that pulses through the reset value by design.
On a track that crosses itself (a figure-eight, or any lap that revisits the same ground), a per-frame nearest-waypoint lookup jumps about half a lap at the crossing, because two points that sit close together can be arclength-distant. Drive lap position from a monotone cursor that only advances along the committed branch, do lateral math in a left-of-travel frame, and keep the branch-discrimination cone tighter than the branches' angular separation.
Compiling an s&box game assembly outside the editor needs the exact csproj shape the editor generates, and even a perfectly green offline build cannot surface whitelist violations. The SB1000 analyzer runs only in the editor compile pass, so code can build with 0 errors and 0 warnings offline and still be rejected in-editor. Build the editor-generated Code/<project>.csproj directly and confirm against the editor compile_status, never the offline build alone.
A primitive authored with a rotation parameter spins about its own object origin, wherever it was placed, not about the part's intended pivot. A raked hood then see-saws about its own middle and shows half the intended wedge in each direction. Rotate the placement coordinate around the pivot first, then place the box there with the same rotation baked in, and remember that a rotated box's own bounding box is trigonometric, not its declared half-length.