---
path: /studio/aja/inverse-kinematics
surface: studio
domain: aja
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/aja/inverse-kinematics/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; body
  re-derived 2026-06-03 from current source (lane-console architecture)'
---

# Aja Inverse Kinematics

## Purpose

Admin lane console wired to the real `@aja/optimization-ik` FABRIK solver via
`/v1/admin/aja/inverse-kinematics`: solve a two-bone arm
(shoulder→elbow→wrist) so the wrist reaches a target, reporting reachability,
convergence, chain length / target distance, residual position error, and
iteration count. The operator sets the upper-arm and forearm lengths and a
target.

## Entry points

- **Direct URL** — `/studio/aja/inverse-kinematics` (signed-in + studio entitlement)
- **Sibling quick-actions from this page** — Animation Blending, Back to Studio

## Layout regions

`page.tsx` mounts `ShellLayout` with `active="studio"` and renders three panels.

- **Workspace panel** (`data-aja-inverse-kinematics-workspace`):
  - `<h1>` "Aja Inverse Kinematics Workspace" (via `WorkspaceHeading`)
  - `<p data-aja-inverse-kinematics-summary>` — "Solve a two-bone arm with the
    FABRIK solver so the wrist reaches a target — preview reach, convergence, and
    the residual position error."
  - `data-aja-ik-solver` (solver + chain + tolerance) + the solve form
- **Route Map panel** (`data-aja-inverse-kinematics-route-map`): `<h2>` "Route
  Map" + one `<article>` per `STUDIO_AJA_INVERSE_KINEMATICS_ROUTE_MAP` entry
  (5 entries)
- **Quick actions panel**: `.quickAction` `<Link>`s — see Interactions

## States

- [ ] **Loading** — `data-aja-ik-loading` "Loading inverse-kinematics solver…"
- [ ] **Unauthorized** — on 401/403, `data-aja-ik-unauthorized` ("Access
      restricted." + reason, default "Aja workspace scope required to view
      inverse kinematics.")
- [ ] **Error** — non-OK / malformed / unreachable → `data-aja-ik-error`
- [ ] **Ready (form)** — catalog present: `data-aja-ik-solver` + the solve form
- [ ] **Result** — `data-aja-ik-result` with `data-aja-ik-reach` (reachable /
      converged), `data-aja-ik-total` (chain length / target distance),
      `data-aja-ik-position-error`, `data-aja-ik-iterations`
- [ ] **Validation error** — `data-aja-ik-solve-error` (e.g. "Bone lengths must
      be positive numbers." / "Target coordinates must be finite numbers.")

## Interactions

### Solve form (`data-aja-ik-solve-form`)

- [ ] **Upper-arm length (m)** — `input data-aja-ik-field-upper`
- [ ] **Forearm length (m)** — `input data-aja-ik-field-forearm`
- [ ] **Target X / Y / Z** — `input data-aja-ik-field-x` / `-y` / `-z`
- [ ] **Solve IK** — `button data-aja-ik-solve-submit`; `POST
      /v1/admin/aja/inverse-kinematics/solve` with `{ upperArmLength,
      forearmLength, target }`

### Route Map panel (`data-aja-inverse-kinematics-route-map`)

Non-interactive `<article>` blocks from
`STUDIO_AJA_INVERSE_KINEMATICS_ROUTE_MAP` (5 entries):
`/studio/aja/inverse-kinematics` plus `…/scenes/[sceneId]`,
`…/exports/[exportId]`, `…/revisions/[revisionId]`, `…/governance/[policyId]`.

### Quick actions panel

- [ ] **Open Aja Animation Blending workspace** → `/studio/aja/animation-blending`
- [ ] **Back to Studio workspace index** → `/studio`

## Data & contracts

- **Reads**: `GET /v1/admin/aja/inverse-kinematics` (catalog: `solver`, `chain`,
  `positionTolerance`) on mount via `buildBffAuthHeaders()`, `cache: 'no-store'`
- **Writes**: `POST …/solve` → `{ solution }`
- **Realtime**: none
- **Caching**: client fetch on mount (no-store); SSR shell only
- **Auth**: BFF endpoints admin-scoped + fail-closed (401/403 → unauthorized
  render); the route is signed-in + studio (proxy gate)

## Cross-references

- Parent: [`../../studio-overview.md`](../../studio-overview.md)
- Component sources:
  - `apps/oshun/web/src/components/studio/StudioAjaInverseKinematicsWorkspace.tsx`
  - `apps/oshun/web/src/components/studio/StudioAjaInverseKinematicsRouteMap.ts`
- Sibling from quick-actions: `/studio/aja/animation-blending`

## Open questions / known gaps

- [ ] Route-map sub-routes are descriptive only; confirm implementation status
- [ ] Document the exact studio entitlement / proxy gate governing `/studio/aja/*`
