s&box/field-guide
the symptom, in your words

"s&box component lifecycle in practice"

✓ verified on engine 26.07lane: Writing gameplayposted
▸ SYMPTOM
  • Spawn helper sets [Property] values after Create<T>(), but OnAwake already ran on defaults — seeds, waypoint indices, hashes are wrong.
  • Session statics (SFX loop registry, caches) survive Play→Stop→Play and either leak old state or get wiped after bootstrap already started the new session.
  • Managers aren't visible when world/state components start.
▸ CAUSE

OnAwake() fires synchronously inside Components.Create<T>(), before the calling code's next line.

snippet
var c = go.Components.Create<Foo>(); // OnAwake already ran here
c.SomeProperty = x;                  // too late for OnAwake

OnStart runs on the first enabled frame, after synchronous property assignments from the spawn helper have landed.

Runtime creation order matters: create manager singletons first (their OnAwake publishes .Instance), world next, state-holding components last so their OnStart can see the world.

Session-reset trap: a boot singleton's OnAwake runs synchronously at the Create line inside Bootstrap's own OnStartbefore Bootstrap's later lines start loops/registrations. That singleton's OnStart is deferred to frame 1 — after Bootstrap already started them — so resetting statics in OnStart wipes the fresh session.

▸ FIX
snippet
public sealed class Workbench : Component
{
    [Property, Group("Tuning")] public float X { get; set; } = 1f;
    [RequireComponent] public Rigidbody Body { get; set; }

    protected override void OnAwake()  { /* Create-time: publish singletons HERE */ }
    protected override void OnStart()  { /* first enabled frame: children/visuals, derive from Properties */ }
    protected override void OnUpdate() { /* input, visuals */ }
    protected override void OnFixedUpdate() { /* 50 Hz: physics, sim */ }
    protected override void OnDestroy() { }
}

Rules:

  1. Publish singletons in OnAwake (see singleton-no-reference-wiring).
  2. Derive per-instance state (hashes, seeded timers, waypoint indices) from [Property] values in OnStart, not OnAwake.
  3. Bootstrap order: managers → world → state.
  4. Reset static-only facades (ResetForNewSession()) from a boot singleton's OnAwake, never its OnStart. Reset related flags and shared registries at the same boundary so they don't disagree.
  5. Also hard-reset static input gates in OnStart and OnDestroy — they leak across play sessions in one editor process.
▸ WHY IT WORKS

Create is synchronous by design so the object is usable on the next line — but that means Awake cannot see properties assigned after Create. Start is deferred until the GO is enabled in the scene graph, which is after the spawn helper finished wiring. Matching reset hooks to that ordering keeps session statics cleared before the new session registers work, not after.

Verified on engine 26.07 — seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?