# Place And Connect Objects Without Matrix Math

Type: Guide.

Use connector frames when one object must be placed relative to another. Application code
should name connection points and let `Scene` solve the source node transform.

For the full viewer setup around this workflow, including automatic camera
framing, studio lighting, grid floor, auto exposure, and projected connector
labels, see [Easy scene setup](easy-scene-setup.md).

## Scene-Authored Connectors

```rust
let motor_shaft = scene.add_connector(
    ConnectorFrame::new(motor, Transform::at(Vec3::new(0.5, 0.0, 0.0))).named("shaft"),
)?;
let pump_drive = scene.add_connector(
    ConnectorFrame::new(pump, Transform::at(Vec3::new(-0.25, 0.0, 0.0))).named("drive"),
)?;

scene.connect_by_key(motor_shaft, pump_drive, ConnectOptions::default())?;
```

Use `ConnectionAlignment::ForwardToBack` when plug/socket frames should face each other:

```rust
let options = ConnectOptions::default().with_alignment(ConnectionAlignment::ForwardToBack);
scene.connect(source_frame, target_frame, options)?;
```

Use `with_axial_gap` when the connection should leave scene-unit clearance
along the target connector's forward axis:

```rust
let options = ConnectOptions::default().with_axial_gap(0.4);
scene.connect(source_frame, target_frame, options)?;
```

Use roll options when the part is correctly mated but should keep or snap its twist around
the connector forward axis:

```rust
let options = ConnectOptions::default()
    .with_alignment(ConnectionAlignment::ForwardToBack)
    .choose_nearest_roll_degrees(90.0);
scene.connect(source_frame, target_frame, options)?;
```

Use `Scene::preview_connection` or `Scene::validate_connections` before applying a batch in
an editor UI.

Use `Scene::preview_connector_magnet` while dragging parts near a compatible
mate. It returns the same solved ghost transform as `preview_connection`, plus
the current connector distance, the active snap tolerance, and a
`ConnectionMagnetVisualCue` for viewer styling:

```rust
let magnet = scene.preview_connector_magnet(source_frame, target_frame, options)?;
if magnet.is_snap_ready() {
    draw_outline(magnet.ghost_transform(), magnet.visual_cue().css_class());
}
```

## Imported Connectors

For glTF assets with `extras.scena.connectors[]`, connect imports by stable names:

```rust
scene.connect_import_connectors(
    &source_import,
    "mount",
    &target_import,
    "mount",
    ConnectOptions::default(),
)?;
```

This preserves connector kind, allowed mates, tags, snap tolerance, roll policy, polarity,
and opaque metadata from the glTF extras.

For the common shaft/hub case, the direct mating helper keeps application code
free of raw transform math:

```rust
let drive = scene.instantiate(&drive_part)?;
let load = scene.instantiate(&load_part)?;
scene.mate(&drive, "shaft", &load, "hub")?;
```

When showing a before/after replay, use `Scene::bounds_for_transforms()` to
frame every pose that may be visible, and use `Scene::project_world_point()` for
connector labels so they continue to track the parts during orbit and replay.

## Locked Nodes

Use `Scene::lock_node_for_connections(node)` when an assembly helper must not move a node.
The solver returns `ConnectionError::ConnectionWouldMoveLockedNode` before mutating the
scene.
