arkavo-org / arkavo-org/VRMMetalKit

Architecture: extract VRM authoring (VRMBuilder) out of VMK — keep VMK render-only

Open
#368 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.