arkavo-org / arkavo-org/VRMMetalKit
Architecture: extract VRM authoring (VRMBuilder) out of VMK — keep VMK render-only
- Dominant language
- Swift
- Stars
- 6
- Forks
- 2
- Avg merge
- 18h 51m
- Merged PRs (30d)
- 26
Description
## Summary
VRMMetalKit should be a **render-only** library for VRM **and** VRMA (load `.vrm`/`.vrma` → `VRMModel` → `VRMRenderer`). It currently also **authors** VRM via `VRMBuilder` and friends. This issue proposes extracting all authoring code out of VMK into a separate package that *depends on* VMK, restoring a clean render-only boundary.
## Good news: the render path is already clean
`Sources/VRMMetalKit/Renderer/` has **no dependency** on `Sources/VRMMetalKit/Builder/`. Removing the authoring code does not touch loading or rendering — this is a carve-out, not surgery on the render core.
## What is authoring (to move out)
Everything under `Sources/VRMMetalKit/Builder/` (~1,740 LOC):
| File | LOC | Notes |
|---|---|---|
| `VRMBuilder.swift` | 789 | the fluent VRM authoring builder; also defines `SkeletonPreset` |
| `CharacterRecipe.swift` | 325 | recipe → builder; also defines `SkeletonPresetMapper` |
| `VRMModel+Serialization.swift` | 333 | `VRMModel.serialize()` → `.vrm` (writing/export is authoring, not rendering) |
| `SynthBodyGeometry.swift` | 199 | per-part procedural body geometry (recent, branch `feat/synth-npc-body`) |
| `SynthBodySpec.swift` | 93 | bounded geometry vocabulary (recent, branch `feat/synth-npc-body`) |
`SkeletonPreset` / `SkeletonPresetMapper` move with the authoring code.
## Recommended target boundary: bytes, not the model graph
`VRMBuilder` currently constructs a `VRMModel` **directly** from `GLTFDocument`/`GLTFNode`/`GLTFMesh`/`VRMHumanoid`/`VRMExpressions`/`VRMMeta`. Two ways to relocate it:
- **(a) Publicize the model graph** so external code can build a `VRMModel`. `VRMModel.init` and `VRMHumanoid` are already `public`; the GLTF types' visibility is **the pivotal unknown** (needs a quick check). Risk: wide public surface if they are `internal`.
- **(b) Recommended — byte boundary.** Authoring emits **`.vrm` bytes**; VMK only ever *loads* bytes for rendering. Fully decoupled, no need to expose the model graph. The byte path already exists (`build()` → `GLTFDocument` → `serialize()` → `Data`). A short spike confirms feasibility.
## Dominant cost: VMK's own test suite (~35 files)
`VRMBuilder`/`SkeletonPreset` is VMK's **test-fixture factory** — spring-bone, animation, expression, MToon, and VRMA tests build a model in-memory to render-test it. Removing it from the library means these tests need a new fixture source. Options:
1. **VMK test target depends on the new authoring package** (the library stays authoring-free; a test-target dependency that points back at VMK is not a *library* cycle). Lowest churn: import swaps, fixtures unchanged.
2. Replace programmatic fixtures with bundled sample `.vrm`/`.vrma` assets loaded via `VRMModel.load`.
3. Keep a minimal fixture builder inside `Tests/` only.
This migration is the bulk of the effort regardless of approach.
## Downstream consumers (other arkavo-org repos — coordinate)
Out-of-repo code that imports `VRMBuilder`/`SkeletonPreset`/`CharacterRecipe` and will need to repoint to the new authoring package:
- **GameOfMods** app — `ConstructKit/CharacterCreation`, `ConstructKit/CharacterRecipe`, `OperatorCore/{CharacterState, MLXBridge, ToolCreateVRMCharacter, ToolModifyCharacter, VRMCopilot}` (Construct-mode / Operator character authoring).
- **SynthNPCKit** (in the GameOfMods repo) — `AvatarSynthesizer`, `NPCSpec` (PreviewRenderer is render-only and stays on VMK).
Note for packaging: GameOfMods resolves VMK both via SynthNPCKit's local path **and** transitively via MuseCore; the new authoring package must slot into that same dependency graph, and any MuseCore VMK pin needs a version story.
## Suggested steps
1. Spike the **byte-boundary** (option b) to settle the public-API question and de-risk.
2. Create a `VRMAuthoring` package depending on VMK; move the `Builder/` files into it.
3. Migrate VMK's test target to source fixtures from `VRMAuthoring` (or bundled assets).
4. Repoint downstream consumers (coordinated with the GameOfMods repo).
5. Reconcile the dual-VMK / MuseCore dependency graph.
## Effort / risk
Roughly **3–4 focused days**, dominated by the ~35-file test migration. Top risks: GLTF-type visibility (mitigated by the byte boundary) and the MuseCore/dual-VMK pinning reconciliation. The render path is untouched throughout.
Contributor guide
Research direction
Start with the byte-boundary spike described in the issue, checking the visibility of the GLTF types and the existing build-to-Data path. Then review Sources/VRMMetalKit/Builder/ and the roughly 35 tests that use VRMBuilder or SkeletonPreset. Done means the authoring files have a separate package dependency, VMK remains render-only, and the test and downstream dependency paths are accounted for.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- build-system, testing
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100