Skip to main content
A composite component wraps an internal sub-graph. From the outside it looks identical to a primitive (same ports, same parameters, same solve() interface). Internally, Hardwave wires sub-components together and routes external ports through them.

When to use composites

Use a composite when you have a recurring assembly (a voltage divider, a motor driver stage, or a full control loop) that you want to drop into any graph as a single node.

Example: Voltage divider

BuildContext API

Use ctx.connect(Connection("a", "port_out", "b", "port_in")) for internal connections between sub-components. When multiple internal connections target the same aggregating input port, values are combined using that port’s aggregation settings before the sub-component solver runs.

Aggregating Input Ports

Multi-connection ports and custom aggregation

Using a composite

How it works internally

When solve() is called on a composite, Hardwave calls build() once (lazily on first use) to construct the internal graph. It then topologically sorts the sub-graph, feeds external inputs through _input_map, gathers and aggregates values on multi-connection internal ports, and reads outputs through _output_map. Callers never interact with internal instance IDs.
Every sub-component class used inside a composite must be registered in ComponentRegistry before the composite is deserialized from a saved graph.
See the Greenhouse Tutorial for a full composite assembly example (GreenhouseVentAssembly).