Skip to content

VR viewer: support more VRChat model formats than VRM #329

Description

@linear-code

Mentioned in a DM as work coming "soon," but never written down anywhere. Filed so it exists outside one person's head.

Confirm before starting

This issue was created from a passing remark, not from a spec, and the code moves fast. Before writing anything, check all three:

  1. Linear. Search for VR and model-format issues. At filing time only VR avatar showcase: model + credits + platforms, behind the early-access gate #228, Retire the EARLY_ACCESS['vr-avatars'] entry at the next release #290, VR upload page: VRChat → VRM export tutorial (modal), built from the first real end-to-end export #300, and VR viewer: fullscreen dead on iPhone + camera framing lands badly on real uploads #308 mentioned VR, and none covered formats. That may no longer hold.
  2. The code. The findings below were read on 2026-08-12 and may already be stale.
  3. Open PRs. At filing time test: resolve pinned wrangler in dev-bootstrap integration test, never registry latest #326, ci: pin auto-assign action to v4.0.1 so PR events stop failing #327, fix(e2e): bound gallery-variants' hydration retries below an explicit slow budget (SONA-164) #328, and feat(staging): staging environment for beta.sona.fast (#166) #171 were open and none touched VR. Check again; another session may be mid-flight on exactly this.

If any of the three shows this is already done or underway, close this rather than duplicating the work.

Current state, read 2026-08-12

Upload already accepts two formats. src/lib/server/vr-models.ts sniffs by magic bytes and recognises VRM (glTF binary, glTF magic at offset 0) and FBX (both the Kaydara FBX Binary header and the ASCII ; FBX x.y.z comment convention). src/lib/server/vr-avatars.ts stores one of vrm, vrm0, or fbx. Accepted content types are application/octet-stream and model/gltf-binary.

The viewer renders VRM only. src/lib/components/VrViewer.svelte loads three, GLTFLoader, and the VRM loader plugin, then throws not a VRM model when the parsed result has no VRM data. So an FBX upload is accepted, stored, and downloadable, but cannot be previewed.

That makes the gap specific: it is not that other formats are rejected at the door, it is that the viewer only knows one of them.

What needs deciding

Which formats actually matter to people exporting from VRChat, and in what order. FBX is already half-supported and is the obvious first candidate, but "what VRChat users actually have on disk" should drive this rather than what the sniffer happens to recognise.

Whether unpreviewable formats stay uploadable. Accepting a file the viewer cannot show is defensible if the download is the point, and confusing if the visitor expects a 3D preview. Either way the UI should say which it is, rather than leaving a dead viewer.

Bundle cost. The viewer already defers three and the VRM plugin behind a click specifically so they never ride the initial page load. Any additional loader has to respect that, and a second loader is a second heavyweight import.

Tests

  • Sniffer tests for each newly supported format, including a rejection case.
  • A viewer test per format asserting it loads, and asserting the failure path stays graceful for anything unsupported.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions