Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,14 @@ Stage-contract version: **1**, authored since the Phase 0 importer.
also forwards the host-resolved Python development paths into the clean
installed-consumer configure, provisions Python for Windows runtime
validation, and recognizes the complete macOS OpenUSD foundation closure.
`mmdMotionBinding` now preserves the VMD model name
as provenance. End-to-end retarget and `UsdSkelAnimation` authoring remains
Phase 9 work. (`MOTION_CONTRACT.md` §10, §12.)
`mmdSkeletonAdapter` now also states `motionRetarget`'s pinned `motionCore`
artifact closure so its standalone build is complete. `mmdMotionBinding`
now preserves the VMD model name as provenance. A deterministic skeletal
acceptance now carries VMD-derived, IK-evaluated legs through `motionUsd`,
retargets them with `motionRetarget` onto both a PMX-derived stage skeleton
and a non-MMD skeleton, and binds the PMX target's `UsdSkelAnimation`;
`motionUsd` v0.5.0 is digest-pinned for that test only.
(`MOTION_CONTRACT.md` §10, §12; report 2026-09-22.)

- **Physics runtime integration direction.** A proposed focused contract now
fixes the future boundary: the existing `/Asset/physics` stage remains the
Expand Down
9 changes: 5 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Documentation is organized by responsibility: each category answers one class
of question. The layout is the one `usd-vrm-plugins`, `open-strata` and
`hydra-merlin` use, so the repositories read the same way.

**The tree holds Phases 0–7 and most of Phase 9 (2026-09-21):** the PMX structural parser reads
**The tree holds Phases 0–7 and most of Phase 9 (2026-09-22):** the PMX structural parser reads
every table of a PMX 2.0 or 2.1 file, `mmd_inspect` reports on it, and `.pmx`
opens as the canonical stage — mesh, UVs, material prims and subsets,
skeleton and skinning, Y-up, in meters. Phase 3 adds canonical MMD material
Expand All @@ -17,8 +17,9 @@ where it matches, simulating nothing. Phase 7 reads VMD motion without a
model (`motionVmd`, `vmd_inspect`) and binds it to one by MMD's name rule
(`mmdMotionBinding`), baking nothing. Phase 9 evaluates MMD's control rig over
a bound motion (`mmdControl`) and hands the result to `usd-motion-plugins`
through `mmdMotionAdapter` and `mmdSkeletonAdapter`. End-to-end retarget and
animation authoring acceptance remains. Future
through `mmdMotionAdapter` and `mmdSkeletonAdapter`. Skeletal end-to-end
retarget and animation authoring acceptance is covered; expression
interoperability and rest-direction evidence remain. Future
physics execution consumes the existing static stage through
`usd-physics-plugins`, with MMD coupling kept here and simulation outside the
importer. Everything
Expand All @@ -34,7 +35,7 @@ place that says what is implemented.
| [roadmap/](roadmap/) | What is planned next (incomplete work only), and which release carries it. | [README.md](roadmap/README.md) · [current.md](roadmap/current.md) |
| [contributing/](contributing/) | How to maintain these documents. | [documentation.md](contributing/documentation.md) |
| [releases/](releases/) | Immutable per-version release records, and how a release is cut. | [README.md](releases/README.md) · [v0.1.0.md](releases/v0.1.0.md) |
| [reports/](reports/) | Dated evidence from real runs; append-only. | [2026-09-15-phase2-local-models.md](reports/2026-09-15-phase2-local-models.md) · [2026-09-16-phase4-local-models.md](reports/2026-09-16-phase4-local-models.md) · [2026-09-16-phase5-local-models.md](reports/2026-09-16-phase5-local-models.md) · [2026-09-17-phase6-local-models.md](reports/2026-09-17-phase6-local-models.md) · [2026-09-17-phase7-local-motions.md](reports/2026-09-17-phase7-local-motions.md) |
| [reports/](reports/) | Dated evidence from real runs; append-only. | [2026-09-15-phase2-local-models.md](reports/2026-09-15-phase2-local-models.md) · [2026-09-16-phase4-local-models.md](reports/2026-09-16-phase4-local-models.md) · [2026-09-16-phase5-local-models.md](reports/2026-09-16-phase5-local-models.md) · [2026-09-17-phase6-local-models.md](reports/2026-09-17-phase6-local-models.md) · [2026-09-17-phase7-local-motions.md](reports/2026-09-17-phase7-local-motions.md) · [2026-09-22-phase9-motion-acceptance.md](reports/2026-09-22-phase9-motion-acceptance.md) |

## Canonical documents

Expand Down
13 changes: 9 additions & 4 deletions docs/architecture/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ exact version, and listed in `THIRD_PARTY_NOTICES.md`.
The shared motion core: vendor- and avatar-format-neutral poses and clips,
humanoid joint semantics, sampling, retargeting, recording and the
`UsdSkelAnimation` bridge. v0.5.0 was published on 2026-09-20 with installable
`motionCore` and `motionRetarget`; the two adapters consume their per-target,
digest-pinned OpenStrata artifacts.
`motionCore`, `motionRetarget` and `motionUsd`; the adapters and their skeletal
acceptance test consume per-target, digest-pinned OpenStrata artifacts.

| | |
| --- | --- |
| Packages | `motionCore` (`HumanJoint`, `MotionPose`, `RootMotion`, `MotionClip`) and `motionRetarget` (`SkeletonDescriptor`, `RetargetMap`, `SourceRestPose`), each by `find_package(<name> CONFIG)` and linked as `<name>::<name>`; `motionUsd` only where [WORKSPACE.md §2.4](WORKSPACE.md#24-edges-out-of-this-repository) allows it |
| Used by | `mmdMotionAdapter` (`motionCore`) and `mmdSkeletonAdapter` (`motionRetarget`); later perhaps `usdVmdFileFormat` (MOT-O2) |
| Packages | `motionCore` (`HumanJoint`, `MotionPose`, `RootMotion`, `MotionClip`), `motionRetarget` (`SkeletonDescriptor`, `RetargetMap`, `SourceRestPose`) and `motionUsd` (the standalone motion-stage writer/reader), each by `find_package(<name> CONFIG)` and linked as `<name>::<name>` |
| Used by | `mmdMotionAdapter` (`motionCore`), `mmdSkeletonAdapter` (`motionRetarget`, plus its required `motionCore` artifact closure) and the Phase 9 acceptance test (`motionRetarget`, `motionUsd`); later perhaps `usdVmdFileFormat` (MOT-O2) |
| Consumed as | an installed package, by `find_package` with a version range admitting the release it was verified against, the way siblings are ([WORKSPACE.md §5](WORKSPACE.md#5-build-modes)) |
| Version | `>=0.5,<0.6`, verified against v0.5.0 |
| OpenUSD | the same exact pin as §1 |
Expand All @@ -114,6 +114,11 @@ retarget and one USD mapping; a private MMD copy would be the permanent
duplication that policy forbids (its §37). What stays here is what needs MMD
to be understood ([MOTION_CONTRACT.md §10](../design/MOTION_CONTRACT.md#10-normalizing-into-the-shared-motion-core)).

`motionUsd` is test-only today. Its pin lives on `mmdMotionAdapter`'s manifest
so a standalone or workspace test has the same artifact CI uses; the exported
`mmdMotionAdapter::mmdMotionAdapter` target and installed package do not link
or require it.

## 7. usd-physics-plugins

The future backend-neutral physics layer: scene construction from authored
Expand Down
11 changes: 7 additions & 4 deletions docs/architecture/PACKAGE_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@ five packages alone. The installed-consumer lane's `control_probe` finds
| Version compatibility | `SameMinorVersion`, as `mmdPmx` |
| Installed files | `${CMAKE_INSTALL_LIBDIR}/` (the archive), `${CMAKE_INSTALL_LIBDIR}/cmake/mmdSkeletonAdapter/`, and `include/mmdSkeletonAdapter/` |

Its manifest pins `motionRetarget` by archive and OCI digest for each supported
target. The installed-consumer lane verifies the package from outside the
source tree against that external package.
Its manifest pins `motionRetarget` and that package's `motionCore` dependency
by archive and OCI digest for each supported target, so its isolated artifact
closure is complete. The installed-consumer lane verifies the package from
outside the source tree against those external packages.

## `mmdMotionAdapter`

Expand All @@ -138,7 +139,9 @@ source tree against that external package.
| Version compatibility | `SameMinorVersion`, as `mmdPmx` |
| Installed files | `${CMAKE_INSTALL_LIBDIR}/` (the archive), `${CMAKE_INSTALL_LIBDIR}/cmake/mmdMotionAdapter/`, and `include/mmdMotionAdapter/` |

Its manifest pins `motionCore` per target. The installed-consumer lane binds a
Its manifest pins `motionCore` per target, and pins `motionUsd` only to supply
the Phase 9 acceptance test; `motionUsd` is not in the exported target or
installed package contract. The installed-consumer lane binds a
generated VMD to a generated PMX, evaluates it, and builds a shared
`MotionClip` through both installed adapters.

Expand Down
16 changes: 13 additions & 3 deletions docs/architecture/WORKSPACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ mmdSkeletonAdapter ──→ mmdModel,
mmdMotionAdapter ────→ mmdControl, mmdModel, mmdSkeletonAdapter,
usd-motion-plugins motionCore (OpenUSD foundation
types only, through it)
mmdMotionAdapter acceptance test
────→ usd-motion-plugins motionRetarget, motionUsd
usdVmdFileFormat ────→ motionVmd, OpenUSD; usd-motion-plugins motionUsd if
MOT-O2 says so
mmd_convert ─────────→ usdMmdFileFormat's public entry point, OpenUSD
Expand Down Expand Up @@ -173,6 +175,9 @@ over `libs/mmdControl` with `mmdMotionBinding::mmdMotionBinding` and
`mmdSkeletonAdapter_boundaries` runs with that library, allowing
`motionRetarget`; `mmdMotionAdapter_boundaries` allows `motionCore` and the
skeleton adapter. Those are the two narrow external adapter edges (§2.4).
The separate `mmdMotionAdapter_acceptance` executable intentionally links
`motionRetarget` and stage-level `motionUsd`; it is not the library target the
boundary test inspects.
The five OpenUSD-free libraries are added before OpenUSD is resolved; the
adapters follow it because their shared packages expose OpenUSD foundation
types and reuse the root's already-resolved targets. The binary-import part
Expand All @@ -197,13 +202,17 @@ usd-stage-runner ────→ usd-physics-plugins

| Rule | Detail |
| --- | --- |
| Narrow crossings | `mmdMotionAdapter` depends on `motionCore`; `mmdSkeletonAdapter` depends on `motionRetarget`, which owns `SkeletonDescriptor`, `RetargetMap` and `SourceRestPose` ([MOTION_CONTRACT.md §10.4](../design/MOTION_CONTRACT.md#104-skeleton-and-humanoid-map)). `usdVmdFileFormat` may add `motionUsd` if MOT-O2 says so. No parser, canonical model, evaluator or importer crosses. |
| Narrow crossings | `mmdMotionAdapter` depends on `motionCore`; `mmdSkeletonAdapter` depends on `motionRetarget`, which owns `SkeletonDescriptor`, `RetargetMap` and `SourceRestPose` ([MOTION_CONTRACT.md §10.4](../design/MOTION_CONTRACT.md#104-skeleton-and-humanoid-map)). The Phase 9 acceptance executable, not either exported target, uses `motionRetarget` and `motionUsd`. `usdVmdFileFormat` may add `motionUsd` if MOT-O2 says so. No parser, canonical model, evaluator or importer crosses. |
| Installed packages only | The edge is a `find_package` on an installed package with a declared version range, never a sibling checkout, a submodule or a vendored copy (§5, [DEPENDENCIES.md §6](DEPENDENCIES.md#6-usd-motion-plugins)). |
| Never the reverse | `usd-motion-plugins` never depends on any component here, and nothing here is designed to be moved there: VMD is MMD's format (the motion policy's §26). |
| Same OpenUSD | `motionCore` and `motionRetarget` are built against the OpenUSD release this repository pins ([DEPENDENCIES.md §1](DEPENDENCIES.md#1-openusd)); a mismatch is a configure error, not a warning. |
| Same OpenUSD | `motionCore`, `motionRetarget` and test-only `motionUsd` are built against the OpenUSD release this repository pins ([DEPENDENCIES.md §1](DEPENDENCIES.md#1-openusd)); a mismatch is a configure error, not a warning. |

The two adapter edges are active since `usd-motion-plugins` v0.5.0: their
manifests pin `motionCore` and `motionRetarget` artifacts by target and digest.
manifests pin `motionCore` and `motionRetarget` artifacts by target and digest;
the skeleton adapter states `motionRetarget`'s `motionCore` artifact closure
explicitly so it can build in isolation.
The `mmdMotionAdapter` manifest additionally pins `motionUsd` for its test-only
acceptance edge; the adapter's link interface remains unchanged.
A future MMD-specific physics adapter may similarly consume
`usd-physics-plugins`; its identity and edge are added here only when the first
runtime consumer makes them concrete
Expand Down Expand Up @@ -348,6 +357,7 @@ target, header root and required packages — is
| pyramid | the bundle manifest's `tests:` | `ost plugin test` L0–L5, from the build tree and from the package | — (`ost`) |
| baseline | the bundle's `tests/fixtures/` | compact goldens do not change silently | the L5 goldens of `minimal.pmx` and `recoverable/unsafe-texture-paths.pmx` |
| installed consumer | `tests/installed_consumer/` | installed packages work from a clean prefix outside the repository | `workspace_installed_consumer` |
| shared-motion acceptance | `libs/mmdMotionAdapter/tests/` | VMD-derived IK motion survives `motionUsd`, poses a PMX-derived stage skeleton, and retargets through an MMD-free translation unit to a non-MMD skeleton | `mmdMotionAdapter_acceptance` |
| fuzz | `libs/mmdPmx/fuzz/`, `libs/motionVmd/fuzz/` | malformed input never crashes or over-reads, under ASan and UBSan | `mmdPmx_fuzz` and `motionVmd_fuzz` in [parser-sanitizers.yml](../../.github/workflows/parser-sanitizers.yml), which also runs every plain library's unit and robustness tests instrumented |

Fixtures are generated by committed code, never copied from distributed
Expand Down
2 changes: 1 addition & 1 deletion docs/design/MOTION_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ as a whole.
| MOT-O2 | What a directly opened `.vmd` stage looks like. `usd-motion-plugins` fixes the frame (`/Animation`, the body as `UsdSkelAnimation`, `customData.motion`); what remains is that a VMD without a model has only control-rig tracks, which no evaluator can turn into body motion (§10.2) — so either the stage carries source tracks outside `Body`, or no such stage exists | `usd-motion-plugins`' `motionUsd` contract, then a consumer |
| MOT-O4 | Camera and light tracks: any USD mapping at all | a consumer that needs one |
| MOT-O8 | Whether `mmdControl` must also evaluate from a stage alone — `/Asset/rig` and `/Asset/morph` — for a runtime that holds no `CanonicalDocument` (§10.3) | a consumer that holds only the stage |
| MOT-O10 | The rest a clip from MMD states. Every MMD bone rests at identity rotation, so §12.3's rotations are relative to the model's modelled pose, in which every local character's upper arms point 37–42° below horizontal ([report](../reports/2026-09-19-phase9-roles-and-root.md)) — not the level arms a VRM's identity rest describes. Whether `mmdSkeletonAdapter` states a `SourceRestPose` measured from the rest bone directions (as the shared core's BVH profiles state `rest-offsets`), and against which reference directions, or leaves the difference to a retarget option | the adapters' first retarget onto a non-MMD skeleton |
| MOT-O10 | The rest a clip from MMD states. Every MMD bone rests at identity rotation, so §12.3's rotations are relative to the model's modelled pose, in which every local character's upper arms point 37–42° below horizontal ([report](../reports/2026-09-19-phase9-roles-and-root.md)) — not the level arms a VRM's identity rest describes. Whether `mmdSkeletonAdapter` states a `SourceRestPose` measured from the rest bone directions (as the shared core's BVH profiles state `rest-offsets`), and against which reference directions, or leaves the difference to a retarget option | a measured A-pose-to-level-arm retarget comparison; the first generic skeletal acceptance used identity rest rotations and could not answer it ([report](../reports/2026-09-22-phase9-motion-acceptance.md)) |
| MOT-O11 | Whether a plane link starts from its keyed rotation. §11.7 starts an enabled chain's plane angles at zero, so a knee's keyed rotation never reaches the pose and the knee is solved from straight; three.js r168 starts from the keyed rotation. On a motion that keys its legs' rotations alongside their goals, that start alone leaves a median 0.05 mm where §11.7 leaves 2.4 mm, and moves the knees a median 4.6 mm and at most 66 mm; on an IK-authored motion it changes little ([report](../reports/2026-09-19-phase9-ik-reference.md)). Which MMD does | MMD's output on a motion that keys its IK links |

Resolved:
Expand Down
1 change: 1 addition & 0 deletions docs/guides/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ bundle's `plugInfo.json` expects it, `mmd_inspect` into
| `mmdControl_robustness` | 20,000 generated rigs and motions — appends and IK chains naming any joint, wild loop counts, limits and keys, cyclic group morphs — each evaluated at five times, twice: no crash, the same bits both times, and finite unit-rotation poses from the tame half |
| `mmdControl_boundaries` | `mmdControl`'s sources include no OpenUSD and no `motionCore/` header, it links `mmdMotionBinding` and `mmdModel` and nothing else, and a binary linking it imports no OpenUSD library |
| `mmdSkeletonAdapter_boundaries`, `mmdMotionAdapter_boundaries` | each adapter links only its declared local and shared-motion packages; its test binary may import the OpenUSD foundation closure those packages expose, including the private `usd_boost`/`usd_python` support libraries on macOS, but no stage, schema or imaging library |
| `mmdMotionAdapter_acceptance` | a synthetic VMD leg-IK motion is bound and evaluated, round-tripped through `motionUsd`, retargeted onto a PMX-derived `UsdSkelSkeleton` and authored as its animation, then retargeted again onto a non-MMD skeleton through a source file containing no MMD dependency |
| `mmd_inspect_fixtures` | `mmd_inspect` reads every generated fixture as `fixtures.json` says, from an ASCII and a non-ASCII directory |
| `mmd_inspect_boundaries` | `mmd_inspect` links `mmdPmx` and nothing else, and imports no OpenUSD library |
| `vmd_inspect_fixtures` | `vmd_inspect` reads every generated VMD fixture as its `fixtures.json` says, from an ASCII and a non-ASCII directory |
Expand Down
3 changes: 2 additions & 1 deletion docs/reference/CAPABILITY_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ What the current code supports, feature by feature. This page states **facts
about the tree**, not plans; a status here changes only in the change that adds
the fixture proving it.

**As of 2026-09-21 the tree holds Phases 0–7 and most of Phase 9:** `.pmx` is registered, every
**As of 2026-09-22 the tree holds Phases 0–7 and most of Phase 9:** `.pmx` is registered, every
table of a PMX 2.0 or 2.1 file is parsed and validated (by `mmdPmx`, reported
by `mmd_inspect`), canonicalized (by `mmdModel`), and authored as the
canonical stage — mesh, UVs, material prims and subsets, skeleton and
Expand Down Expand Up @@ -126,6 +126,7 @@ lane against digest-pinned `usd-motion-plugins` v0.5.0 packages.
| Non-bone morph weights under `mmd:morph:<source name>` channels | supported | [MOTION §10.7](../design/MOTION_CONTRACT.md#107-morphs-as-channels) |
| Evaluated model visibility under the reserved `mmd:model:visibility` channel | supported | [MOTION §10.7](../design/MOTION_CONTRACT.md#107-morphs-as-channels) |
| Non-finite evaluated shared values | rejected, never replaced | [MOTION §10.8](../design/MOTION_CONTRACT.md#108-diagnostics) |
| VMD-derived, IK-evaluated legs through a `motionUsd` round trip and `motionRetarget`, onto a PMX-derived stage skeleton and a non-MMD synthetic skeleton | supported | [Phase 9 acceptance report](../reports/2026-09-22-phase9-motion-acceptance.md) |
| Rest-direction correction for an A-pose source (MOT-O10) | unverified | [MOTION §9](../design/MOTION_CONTRACT.md#9-open-questions) |

## PMX model import
Expand Down
Loading
Loading