Skip to content

What you write

Circuit logic and component logic each have their own code editor in the component editor. In each one you type fields, the hooks you fill in, and any helper methods of your own. You never write class, using or namespace lines: CRUMB takes care of those when the part compiles.

This is everything you type for a fixed resistor between two pins, A and B, with a Resistance property:

public override void StampInitial()
{
Simulation.StampResistor(ConnectionNodes[Connections.A], ConnectionNodes[Connections.B], Properties.Resistance);
}
public override void PreStep() { }
public override void Step() { }
public override void CalculateCurrent()
{
double v = ConnectionVoltages[Connections.A] - ConnectionVoltages[Connections.B];
SetCurrent(0, v / Properties.Resistance);
}

Connections.A and Connections.B come from the two pin markers, and Properties.Resistance from the property you added. You never declare them yourself.

This is everything you type for an LED that glows with the current its circuit logic recorded:

public override void Update(double delta)
{
float glow = (float)Math.Clamp(Circuit.GetDisplayAverage(0) / Properties.RatedAmps, 0.0, 1.0);
Rendering.Lens.Material.EmissionEnergyMultiplier = glow * Properties.MaxGlow;
}

Rendering.Lens is the mesh named Lens under Rendering, and RatedAmps and MaxGlow are properties on the component logic.

Your markers and properties appear in your code as members, named as you named them in the component editor:

  • Properties.<Name>: each property, with its type and saved value. Component logic can also read the circuit logic’s properties through CircuitProperties.
  • Connections.<Name>: in circuit logic, each pin’s index, a number you pass to ConnectionNodes. In component logic, each wire, which you can recolour or measure.
  • Rendering.<Node> in component logic: each node under Rendering. A mesh with a part body has Rendering.<Node>.Rigidbody.
  • Interactivity.<Zone> in component logic: each interactivity zone.

To get a new member, add the marker or the property in the component editor, and it appears. Renaming one renames its member, so update the code that names it.

Everything in your half’s API reference is yours by name. You write SetCurrent(0, amps), UserData[0] or SaveState("On", true) directly, with no prefix. BaseCircuitLogic and BaseComponentLogic list what each half has.

Hooks are overrides. Write each one with public override and the signature the reference shows under Methods you override.

  • Circuit logic must have all three of StampInitial, PreStep and Step, even when some are empty. The part won’t compile without them.
  • Every component logic hook is optional. Write only the ones you use.
  • When you override Reset, call base.Reset().

Fields and helpers go in the same block. Declare fields at the top, then hooks and helper methods in any order. Small nested types are fine too, such as a struct that holds one sample. Give fields their starting values where you declare them, or set them in a hook.

Don’t write a constructor. Put setup in StampInitial for circuit logic and Initialize for component logic. Both run again after Reset State.

Don’t write using lines. Math, List<T> and the types in your half’s API reference already work by their short names. For anything else on the whitelist for circuit logic or component logic, write its full name.

Don’t reuse the names from the component editor. Declaring your own Properties or Connections, or in component logic your own Rendering, Interactivity or CircuitProperties, won’t compile.

Keep state out of static fields. A static field is shared by every copy of the part. See State, saving and Reset.