> ## Documentation Index
> Fetch the complete documentation index at: https://dadd.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# IK Control

> Inverse kinematics via useIkController

IK is provided by the `useIkController()` hook — it is not part of the core `MujocoSimAPI`. The hook returns an `IkContextValue` that you pass to `<IkGizmo>` or use directly.

## Setup

```tsx theme={null}
import { IkGizmo, ModelSites, useIkController } from "mujoco-react";

function MyScene() {
  const ik = useIkController({ siteName: ModelSites.franka.tcp });

  return (
    <>
      {ik && <IkGizmo controller={ik} />}
      <MyIkConsumer ik={ik} />
    </>
  );
}
```

## IkContextValue Methods

### setIkEnabled(enabled)

Enable or disable the IK solver.

```tsx theme={null}
ik?.setIkEnabled(true);   // IK writes to ctrl each frame
ik?.setIkEnabled(false);  // IK disabled — you control ctrl
```

<Warning>
  When IK is enabled, it overwrites `data.ctrl` for the arm joints inside `useBeforePhysicsStep`. Disable IK when running your own control (policies, teleoperation, etc.).
</Warning>

### moveTarget(pos, duration?)

Animate the IK target (gizmo) to a new position.

```tsx theme={null}
ik?.moveTarget(new THREE.Vector3(0.5, 0, 0.3));       // Instant
ik?.moveTarget(new THREE.Vector3(0.5, 0, 0.3), 500);  // 500ms animation
```

### syncTargetToSite()

Snap the IK gizmo to the current site position.

```tsx theme={null}
ik?.syncTargetToSite();
```

Useful after programmatic joint changes to re-align the gizmo with the actual end-effector.

### solveIK({ position, quaternion, currentQ })

Run IK solving manually (without the gizmo).

```tsx theme={null}
const targetPos = new THREE.Vector3(0.5, 0, 0.3);
const targetQuat = new THREE.Quaternion();
const currentJoints = Array.from(api.getQpos()).slice(0, 7);

const solution = ik?.solveIK({
  position: targetPos,
  quaternion: targetQuat,
  currentQ: currentJoints,
});
if (solution) {
  const qpos = api.getQpos();
  for (let i = 0; i < solution.length; i++) {
    qpos[i] = solution[i];
  }
  api.setQpos(qpos);
}
```

**Returns:** `number[] | null` — joint positions, or null if solver failed.

### getGizmoStats()

Get the current IK gizmo position and orientation.

```tsx theme={null}
const stats = ik?.getGizmoStats();
if (stats) {
  console.log("Gizmo position:", stats.pos);
  console.log("Gizmo rotation:", stats.rot);
}
```

**Returns:** `{ pos: THREE.Vector3, rot: THREE.Euler } | null`

## Disabling IK

Pass `null` to `useIkController()` to disable IK entirely. This is safe to call unconditionally (React hook rules):

```tsx theme={null}
const ik = useIkController(hasIk ? ikConfig : null);
// ik is null when hasIk is false
```

## Joint and Actuator Selection

The default config is model-aware:

```tsx theme={null}
const ik = useIkController({ siteName: ModelSites.franka.tcp });
```

The controller finds the site body and infers scalar hinge/slide joints by walking toward the model root. For nonstandard MJCFs, multi-arm scenes, or actuator orders that do not match qpos order, pass explicit selectors:

```tsx theme={null}
const ik = useIkController({
  siteName: ModelSites.franka.tcp,
  joints: ["shoulder", "elbow", "wrist"],
});

const pandaIk = useIkController({
  siteName: ModelSites.franka.tcp,
  actuators: /^actuator/,
});
```

## Custom IK Solver

Pass `ikSolveFn` to the config to replace the built-in solver:

```tsx theme={null}
import { ModelSites } from "mujoco-react";
import type { IKSolveFn } from "mujoco-react";

const myIK: IKSolveFn = ({ position, currentQ }) => {
  const solution = myAnalyticalSolver(position, currentQ);
  return solution;
};

const ik = useIkController({ siteName: ModelSites.franka.tcp, ikSolveFn: myIK });
```

**When to use a custom solver:**

* **Analytical IK** — faster and more reliable for specific robot geometries
* **Learned IK** — neural network solvers trained on your robot
* **External solvers** — calling into WASM-compiled libraries (e.g. KDL, TRAC-IK)
* **Constrained IK** — solvers that enforce joint limits, collision avoidance, or task-space constraints

## Built-in Solver Details

The default solver uses **Damped Least-Squares** (DLS) with finite-difference Jacobian:

* **Max iterations**: 50 per frame (configurable)
* **Damping**: 0.01 (configurable)
* **Position weight**: 1.0
* **Rotation weight**: 0.3
* **Tolerance**: 1e-3
* **Method**: Finite-difference Jacobian + pseudoinverse
