moeru-ai/airi · warning

[mmd] setIdleMotion skipped: "${name}" is not registered

Error message

[mmd] setIdleMotion skipped: "${name}" is not registered

What it means

setIdleMotion promotes a registered clip to the looping base that one-shot motions return to. Like playAction it looks the name up in the clip registry; on a miss it warns and returns false, leaving the previous idle action (if any) in place — the API is total, never throwing.

Source

Thrown at packages/stage-ui-mmd/src/composables/mmd/animation-manager.ts:183

    currentAction = action

    if (loop)
      removeFinishListener(action)
    else
      revertToIdleOnFinish(action)

    return true
  }

  /**
   * Makes a registered motion the looping base that one-shots return to.
   *
   * @returns `false` when no clip is registered under `name`.
   */
  function setIdleMotion(name: string, crossfade = DEFAULT_CROSSFADE): boolean {
    const clip = registry.get(name)
    if (!clip) {
      console.warn(`[mmd] setIdleMotion skipped: "${name}" is not registered`)
      return false
    }

    const action = mixer.clipAction(clip)
    action.reset()
    action.setLoop(LoopRepeat, Number.POSITIVE_INFINITY)
    action.clampWhenFinished = false
    action.setEffectiveWeight(1)
    action.fadeIn(crossfade).play()

    const previousIdle = idleAction
    idleAction = action
    if (currentAction && currentAction !== action) {
      removeFinishListener(currentAction)
      currentAction.fadeOut(crossfade)
    }
    else if (previousIdle && previousIdle !== action) {
      previousIdle.fadeOut(crossfade)

View on GitHub (pinned to 677329427f)

Solutions

  1. Ensure registerClip ran for the idle clip before setIdleMotion (await model/import readiness)
  2. Use the boolean return to detect the miss and keep the existing idle, or fall back to a known-registered default
  3. Validate configured motion names against availableClips() when loading settings

Example fix

// before
animation.setIdleMotion('stand_by') // not registered -> previous idle (or none) kept

// after
const clips = animation.availableClips()
if (!clips.includes('stand_by')) {
  console.warn('idle motion stand_by missing, using', clips[0])
  animation.setIdleMotion(clips[0])
}
else {
  animation.setIdleMotion('stand_by')
}
Defensive patterns

Strategy: validation

Validate before calling

const registered = animation.availableClips()
const idleName = registered.includes(configuredIdle) ? configuredIdle : registered[0]
animation.setIdleMotion(idleName)

Type guard

function isRegisteredMotion(manager: { availableClips(): string[] }, name: string): name is string {
  return manager.availableClips().includes(name)
}

Prevention

When it happens

Trigger: Passing a name to setIdleMotion that was never registered via registerClip: typo, motion import not finished, or a settings file referencing a motion that isn't part of the loaded model.

Common situations: Persisted user settings naming an idle motion that no longer exists in the current model files; startup code setting idle before the VMD import resolves.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/637ea6aa3d890203. Report an issue: GitHub.