arkavo-org / arkavo-org/VRMMetalKit
Implement runtime VRM export functionality
- Dominant language
- Swift
- Stars
- 6
- Forks
- 2
- Avg merge
- 18h 51m
- Merged PRs (30d)
- 26
Description
## Issue Description
VRMMetalKit currently only supports importing VRM files but lacks runtime export functionality. UniVRM (the reference implementation) supports both import and export, making this a feature gap.
## Current State
✅ **Implemented:**
- VRM 1.0 import
- VRM 0.x import (with fallback)
- VRMA animation import
- Complete model parsing and loading
❌ **Missing:**
- VRM 1.0 export
- VRM 0.x export
- Runtime model serialization
- glTF/GLB export with VRM extensions
## Use Cases
1. **Avatar Customization:** Export modified avatars after customization
2. **Format Conversion:** Convert between VRM versions (0.x ↔ 1.0)
3. **Model Processing:** Export processed models (optimized, retargeted, etc.)
4. **Content Creation:** Generate VRM files programmatically
5. **Migration Tools:** Export from other formats to VRM
## Implementation Requirements
### Core Export Functionality
```swift
// Proposed API
extension VRMModel {
/// Export VRM model to file
public func export(
to url: URL,
version: VRMSpecVersion = .v1_0,
options: VRMExportOptions = .default
) async throws
/// Export to Data for in-memory operations
public func exportData(
version: VRMSpecVersion = .v1_0,
options: VRMExportOptions = .default
) async throws -> Data
}
public struct VRMExportOptions {
var embedTextures: Bool = true
var compressTextures: Bool = false
var optimizeMeshes: Bool = false
var includeMetadata: Bool = true
var prettyPrintJSON: Bool = false
public static let default = VRMExportOptions()
}
```
### Components to Implement
1. **glTF Serialization**
- JSON structure generation
- Binary buffer packing
- GLB container format
2. **VRM Extension Serialization**
- VRMC_vrm extension (VRM 1.0)
- VRM extension (VRM 0.x fallback)
- Humanoid bone mapping
- Expression data
- SpringBone configuration
- First-person settings
- Metadata
3. **Asset Serialization**
- Mesh data export
- Texture encoding (PNG/JPEG)
- Material properties
- Animation data (VRMA)
4. **Validation**
- Pre-export validation
- Specification compliance checks
- Required field verification
## Reference Implementation
UniVRM export structure:
```csharp
// UniVRM/Packages/VRM10/Runtime/IO/
- Vrm10Exporter.cs
- Vrm10ExportSettings.cs
- Material exporters
- Texture exporters
```
## Suggested File Structure
```
Sources/VRMMetalKit/Exporter/
├── VRMExporter.swift # Main export coordinator
├── GLTFSerializer.swift # glTF JSON/binary serialization
├── VRMExtensionSerializer.swift # VRM extension data
├── MeshExporter.swift # Mesh data export
├── TextureExporter.swift # Texture encoding
├── MaterialExporter.swift # Material properties
└── VRMExportOptions.swift # Export configuration
```
## Implementation Phases
### Phase 1: Basic Export (MVP)
- [ ] glTF JSON serialization
- [ ] Binary buffer packing
- [ ] GLB container format
- [ ] Basic VRM 1.0 extension
- [ ] Mesh export
- [ ] Texture export (embedded)
### Phase 2: Complete VRM 1.0
- [ ] Full humanoid bone mapping
- [ ] Expression export
- [ ] SpringBone configuration
- [ ] First-person settings
- [ ] Metadata export
- [ ] Material properties
### Phase 3: Advanced Features
- [ ] VRM 0.x export (migration)
- [ ] Texture compression options
- [ ] Mesh optimization
- [ ] External texture references
- [ ] VRMA animation export
### Phase 4: Validation & Testing
- [ ] Pre-export validation
- [ ] Specification compliance checks
- [ ] Round-trip testing (import → export → import)
- [ ] Compatibility testing with other VRM tools
## Testing Strategy
```swift
// Test cases
func testBasicExport() async throws {
let model = try await VRMModel.load(from: testVRMURL, device: device)
let exportURL = temporaryDirectory.appendingPathComponent(exported.vrm)
try await model.export(to: exportURL)
// Verify exported file
let reimported = try await VRMModel.load(from: exportURL, device: device)
XCTAssertEqual(model.humanoidBones.count, reimported.humanoidBones.count)
}
func testRoundTrip() async throws {
// Import → Export → Import should preserve data
}
func testVersionConversion() async throws {
// VRM 1.0 → VRM 0.x conversion
}
```
## Acceptance Criteria
- [ ] Export VRM 1.0 files that can be imported by UniVRM
- [ ] Export VRM 1.0 files that can be imported by VRMMetalKit
- [ ] Preserve all model data (meshes, textures, bones, expressions)
- [ ] Pass VRM validator checks
- [ ] Documentation with examples
- [ ] Unit tests with >80% coverage
- [ ] Performance benchmarks
## Priority
**Medium** - Important for feature completeness but not blocking core functionality
## Estimated Effort
- Phase 1 (MVP): 2-3 weeks
- Phase 2 (Complete): 2-3 weeks
- Phase 3 (Advanced): 1-2 weeks
- Phase 4 (Testing): 1 week
- **Total:** 6-9 weeks
## Related Issues
- Depends on: None
- Blocks: Format conversion tools, avatar customization features
- Related: #66 (spec compliance)
## References
- VRM 1.0 Specification: https://github.com/vrm-c/vrm-specification
- glTF 2.0 Specification: https://registry.khronos.org/glTF/
- UniVRM Exporter: https://github.com/vrm-c/UniVRM/tree/master/Assets/VRM10/Runtime/IO
Contributor guide
Research direction
Start by reviewing the existing VRM import and model-parsing implementation, then compare it with the proposed Sources/VRMMetalKit/Exporter/ structure and the UniVRM exporter reference. The work is complete when VRM 1.0 export, GLB serialization, asset and extension handling, validation, round-trip tests, and the documented acceptance checks are implemented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- computer-graphics
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100