Skip to content

render-iki: drive idle/physics through IkiMotion, load the hero model - #69

Open
zeikar wants to merge 6 commits into
mainfrom
feat/iki-motion-hero
Open

render-iki: drive idle/physics through IkiMotion, load the hero model#69
zeikar wants to merge 6 commits into
mainfrom
feat/iki-motion-hero

Conversation

@zeikar

@zeikar zeikar commented Sep 7, 2026

Copy link
Copy Markdown
Owner

What

  • @charivo/render-iki moves to @ikijs/engine 0.3.0 / @ikijs/format 0.2.0.
  • The adapter's hand-rolled breath/blink loop is replaced by the engine's IkiMotion (idle → hair physics → chains) stepped from one rAF loop registered before the engine's render loop.
  • Host gaze (lookAt, document mouse tracking) is blended over the idle sway in the sink (motion-blend.ts): head = 26°·gaze + sway, eyes = host wins, AngleZ passes through (the model's own rig already leans into a turn), mouth is host-owned via lip-sync. Physics reads the blended head.
  • paramIds presence gating is gone (the engine's store drops unknown ids); load() results are honoured (superseded / destroy during fetch).
  • examples/iki-test loads the Iki hero model (0.9 MB, two hair springs, 2D face warp) instead of the 4 KB sample.
  • First tests for render-iki: a pure blend unit test and a jsdom renderer test that mocks only IkiPlayer (real IkiMotion/ParameterStore → doubles as an engine contract check).

Why the lockfile churn

Only the two @ikijs entries change in packages:; the snapshots: churn is pnpm 11.25 re-resolving optional peers (supports-color under debug, etc.). Re-resolving the unchanged manifests yields the same shape; no other package changes version; pnpm install --frozen-lockfile passes.

Verification

  • pnpm install --frozen-lockfile, pnpm verify, pnpm test:coverage all exit 0 — 113 files / 1509 tests (1495 baseline + 14).
  • Plan + two adversarial code reviews (Claude subagents); all findings applied, incl. three tests that previously could not fail under the regressions they name.
  • Live (Playwright on the harness): hero renders; idle sway/blink/breath run; mouse left/right turns head + eyes (measured AngleX = 26.04 at full deflection); gaze slam writes HairSwayX/Z every frame; lip-sync writes ParamMouthOpenY (30 writes / 1.5 s, max 1.0) and the open mouth renders.

No changeset: both packages are private.

The engine now ships IkiMotion (idle + physics + hair chains behind one
update()), ParamAngleZ and the HairSway outputs the hero model uses. Only
the two @ikijs entries change in the lockfile's packages section; the wider
churn in snapshots is pnpm 11.25 re-resolving optional peers
(supports-color under debug, @babel/core under styled-jsx) — the same shape
appears when the unchanged manifests are re-resolved, no other package
changes version, and the result is a fixed point under --frozen-lockfile.
One pure function decides, per parameter, how the engine's idle writes meet
the host's own: head angles are the host target (26° per unit of gaze) plus
the idle sway, eyes are the host's outright while a gaze exists, and
everything else passes through. 26 rather than the parameters' full 30
leaves room for the sway: under document mouse tracking an off-canvas
pointer pins the gaze to ±1, so the parked head is the normal state, and at
30 the sway would rectify into a one-sided twitch there. No host lean on
AngleZ — the model's own AngleX→rotate binding already leans into a turn.
The adapter ran its own breath sine and blink curve and wrote gaze straight
into the player; the blink rescheduling was also broken (after the first
blink it re-armed every frame). It now builds one IkiMotion per loaded
model and steps it from a single rAF loop registered before the engine's
render loop, so the pose lands in the same frame it is computed. Host gaze
(lookAt, mouse) is stored and blended into the sink, so the physics springs
read the head the host actually set. The hand-kept paramIds presence set is
gone — the engine's store drops unknown ids. load() results are honoured:
a superseded load (or a destroy during the fetch) builds nothing.

The tests mock only IkiPlayer; IkiMotion and ParameterStore are the real
0.3.0 code, so they double as a contract check on the engine.
…tion

The 4 KB texture-less sample exercised nothing the new adapter does; the
hero (from iki's playground, 0.9 MB with its palette-quantized atlas) has
two hair springs, a 2D face warp and the full standard parameter set, so
idle, physics, gaze blending and lip-sync are all visible in the harness.
@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
charivo-companion Ready Ready Preview Sep 7, 2026 6:47am UTC
charivo-web Ready Ready Preview Sep 7, 2026 6:47am UTC

…passes through

The iki auto-rig dropped its ±6° AngleX lean (the crown swung ahead of the
face on every turn), so the harness's hero.iki is re-rigged, and the
"a host lean would double the rig's" rationale no longer holds — AngleZ
still passes through, now because no lean belongs on the turn at all.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant