moeru-ai/airi · warning

[mmd] no vowel mouth morphs (あ/い/う/え/お) resolved; lip-sync c

Error message

[mmd] no vowel mouth morphs (あ/い/う/え/お) resolved; lip-sync cannot move the mouth. Available morphs:

What it means

After loading the MMD model, createMorphController(mesh, morphOverrides) resolves morph slots; none of them started with 'vowel', so the あ/い/う/え/お lip-sync morphs were not found on the model. Audio-driven lip sync will not move the mouth; rendering, motion, gaze and emotes still work.

Source

Thrown at packages/stage-ui-mmd/src/components/scenes/MMD.vue:377

  if (!scene)
    return

  componentState.value = 'loading'
  disposeModel()

  try {
    resolved = await loadMMDModelFromSource(src, { cacheKey: props.modelId })
    mesh = resolved.mesh

    modelGroup = new Group()
    modelGroup.add(mesh)
    applyTransform()
    scene.add(modelGroup)

    morphs = createMorphController(mesh, morphOverrides.value)
    mmdStore.availableMorphs = morphs.availableMorphs
    if (!morphs.resolvedSlots.some(slot => slot.startsWith('vowel'))) {
      console.warn(
        '[mmd] no vowel mouth morphs (あ/い/う/え/お) resolved; lip-sync cannot move the mouth. '
        + 'Available morphs:',
        morphs.availableMorphs,
      )
    }

    emote = useMMDEmote(morphs)
    gaze = createGazeController(mesh)

    animation = createMMDAnimationManager(resolved.mmd, { physicsEnabled: physicsEnabled.value })
    // No preset idle VMD ships yet; the runtime still advances solvers and
    // physics without an animation action.
    await animation.init()
    animation.setIKEnabled(ikEnabled.value)
    animation.setGrantEnabled(grantEnabled.value)
    animation.setGravity(physicsGravity.value)

    // Ensure the camera aspect matches the live canvas before fitting.

View on GitHub (pinned to 677329427f)

Solutions

  1. Inspect morphs.availableMorphs (logged with the warning) and map the actual mouth morphs to vowel slots via morphOverrides
  2. Fix or add the standard vowel morphs あ/い/う/え/お to the model in a PMX editor
  3. If you configured morph overrides, verify every override name exists exactly in the model's morph list
  4. Accept reduced functionality if lip sync is not required for this model
Defensive patterns

Strategy: validation

Validate before calling

// After creating the morph controller
const morphs = createMorphController(mesh, morphOverrides.value)
if (!morphs.resolvedSlots.some(slot => slot.startsWith('vowel'))) {
  // map actual mouth morph names from morphs.availableMorphs via morphOverrides
  console.warn('[mmd] no vowel mouth morphs resolved; lip-sync disabled for this model', morphs.availableMorphs)
}

Type guard

function modelSupportsLipSync(morphs: ReturnType<typeof createMorphController>): boolean {
  return morphs.resolvedSlots.some(slot => slot.startsWith('vowel'))
}

Prevention

When it happens

Trigger: The PMX model lacks standard Japanese vowel morphs — renamed, English-only names (A/I/U/E/O) not matched by the resolver, or missing entirely — or the morphOverrides config remaps vowel slots to morph names that do not exist on the model.

Common situations: Western-made MMD models with English morph names; models using variant names like あ2 that the resolver does not map; a user-supplied morph override config pointing at wrong names.

Related errors


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