Skip to main content

Custom avatars and Unity packages

Read this page as Markdown · All docs for AI agents

Uploading a character​

Open Character & effects → Your own avatar → Upload model while signed in to a registered account. Choose a .glb, .vrm or .unitypackage file. A valid conversion becomes your custom avatar. A rejected upload keeps your previous avatar and selection unchanged.

Your upload is converted into a self-contained GLB that other players download. For Unity packages, include one assembled character model and its supported textures. Upload characters and textures you have permission to distribute.

Exact upload and rendering limits​

LimitValue
Original upload30,000,000 bytes, inclusive: decimal 30 MB
Attempts6 per registered player in a rolling 60-minute window
Failed conversionsConsume an attempt once admitted
Shared quotaGLB, VRM and Unity package uploads share the same six attempts
Converted downloadable avatar4,194,304 bytes, inclusive: 4 MiB
Expanded Unity archiveSmaller of 120,000,000 bytes and max(8,000,000, compressedBytes × 200)
Archive decompression time5 seconds
Archive entries / Unity assets4,096 / 1,024
Models inside one packageOne binary FBX, GLB or VRM, or one supported assembled text-mesh prefab
Meshes / material primitives48 / 96
Mesh vertices / triangles150,000 / 70,000
Vertices / triangles across placed mesh instances200,000 / 70,000
Draw calls across placed mesh instances256
Scenes4
Scene nodes / hierarchy depth256 / 32
Materials / textures32 / 16
Skins / total bone references4 / 256; FBX requires one armature
Bone influencesAt most four per vertex
Morph targets32 per primitive
Final texture sizeAt most 2,048 × 2,048 per texture
Final aggregate decoded textures4,194,304 pixels

The 70,000-triangle limit is a hard rejection threshold. It counts repeated mesh instances and inactive objects, and is checked again before browser loading. Texture resizing never reduces or bypasses this triangle count.

The file-size, format and HTTP-encoding preflight may reject a request before charging an attempt. Once admitted, malformed files, failed conversions, interrupted uploads and unavailable conversion capacity can consume it. Successful uploads also consume it. The API returns HTTP 429 with an ISO retryAt timestamp when the rolling allowance is exhausted. Uploading another format or making concurrent requests does not reset the counter. Registered players have a separate allowance of one profile-picture attempt per rolling hour, including failed conversions.

Keep your final character within 4 MiB using modest geometry and compact texture atlases. Direct GLB/VRM source textures may total up to 64 megapixels, with at most 4,096 × 4,096 per image; the converter resizes and rewrites them to the final budgets. Duplicate images and unused emission maps are removed; eligible small color textures can share an atlas. Tiled or unsupported texture setups must fit the limits themselves. Strip unrelated assets before exporting a package to reduce its download and expansion size. If a package exceeds the expansion budget, export just the character and its textures, or upload a self-contained GLB/VRM.

What a Unity package can contain​

Use an ordinary gzip-compressed Unity archive with GUID directories and pathname, asset, asset.meta and optional preview.png entries. Asset paths must be normal Assets/... paths. Links, traversal paths, duplicate entries, extended tar headers and nested archives are rejected. Files are never extracted using their supplied pathnames.

For binary FBX packages:

  1. Include one assembled character mesh/armature model, not multiple outfit or accessory FBX files.
  2. Include its static PNG, JPEG or WebP textures as separate package assets. Embedded FBX images and external filesystem paths are not loaded.
  3. Use unique texture basenames and unique material names. The converter can match an FBX texture reference to a package texture by basename, or a supported Unity material to a texture by its GUID.
  4. Keep source textures within 16,777,216 pixels in total. They are fully decoded, reduced proportionally to the final pixel/dimension budget, and rewritten as PNG before Blender receives them. Animated images are rejected.
  5. Text Unity .mat files may supply their material name, _MainTex / _BaseMap texture GUID and _Color / _BaseColor RGBA values. For binary .mat files, the converter uses a unique local texture GUID hint, the FBX's supported material data or a uniquely named package texture. Name the texture after the material: Body.mat matches Body.png or an older FBX export such as Body_00_00_00.jpg. Ambiguous matches are rejected. Binary material objects are never instantiated; shader settings are discarded. Untextured materials retain a plain color.
  6. Materials are rebuilt using the platform's standard rendering. Custom shader source, shader graphs, shader plugins, normal-map setups, transparency tricks and other Unity material features are not imported by this FBX path.

For a packaged GLB or VRM, the model must already contain its images and binary data. Loose package textures do not fill missing external GLB references. The same strict GLB validation and final budgets apply as for a direct upload.

Assembled Unity prefabs backed by text Mesh .asset files are also supported. The converter reads only a fixed set of transforms, skin geometry, bone weights, bind poses and material references. Packages containing multiple standalone FBX/GLB models still require an assembled export.

Package scripts, plugins, shaders, scenes, controllers and SDK components are ignored; no Unity editor setup code is run. Export the assembled character with its intended clothing, dimensions and rig already applied. If your package requires an editor setup step, ask its author for an assembled GLB/VRM export.

Humanoid preparation in Blender​

Use your trusted Blender installation and your own scene. Keep the character upright, with its feet near the floor and a consistent scale. Blender uses Z-up; its glTF exporter converts to Y-up. The runtime fits the character to Betworld's standard body height. Extremely flat, enormous, zero-height or malformed skeleton/mesh bounds are rejected.

The skinned mesh must belong to the active scene and have one unambiguous set of these required humanoid bones:

Body partCanonical node name
Hipscasino_pelvis
Spinecasino_spine1
Headcasino_head
Upper armscasino_upperarml, casino_upperarmr
Forearmscasino_forearml, casino_forearmr
Handscasino_handl, casino_handr
Thighscasino_thighl, casino_thighr
Calvescasino_calfl, casino_calfr
Feetcasino_footl, casino_footr

Standard VRM humanoid metadata, common Mixamo bone names and common humanoid aliases are normalized to this vocabulary. This includes older FBX names such as L_UpperArm, R_Forearm, L_Thigh, Head1 and Neck1. A Spine → Spine1 → Spine2 chain maps its lower and middle joints to the spine and chest controls. Optional named chest, neck, toe and eye nodes can survive. Duplicate required bone mappings or missing required bones fail validation. Weight the mesh to its rig; merely naming unconnected objects is insufficient. Do not use more than four bone influences per vertex.

Bounded sparse accessors in source VRMs are expanded into dense data with range, index and allocation checks. Unsupported compressed geometry extensions are rejected. Compatible skin tables and unused vertices are compacted; duplicate joint influences from older exporters are merged and normalized before strict output validation. VRM mouth and blink presets are retained; unused authoring expressions and imported animation clips are removed.

VRM 0.x models are turned to match the game's forward direction; VRM 1.0 models already use it. Models that depend on VRM bone constraints are rejected with an export instruction. Bake those constraints into an ordinary humanoid rig before uploading; the importer does not run their limb drivers.

Betworld drives movement and emotes through the humanoid rig. Preview walking, arm raises, crouching and emotes; adjust shoulder weights and joint placement in your source model where needed. Uploaded animation clips and Unity animator setup are omitted.

Walking, running, jumping, crouching, swinging, sitting and the emote catalogue use Betworld's animations. The result depends on your avatar's joint placement and skin weights. Extra finger joints retain their imported pose unless they have a supported animation mapping; VRChat gesture controllers are not transferred. Mouth movement while speaking requires a recognized mouth shape such as vrc.v_aa, jawOpen or mouthOpen. A model without those shapes still supports body movement, but its mouth remains static.

Recognized facial names such as vrc.v_aa, vrc.v_oh, vrc.v_sil, vrc.blink_left and vrc.blink_right can survive conversion. Facial deformation must stay within the character bounds. Export your character without hats, helmets or other headwear.

After you upload​

Clients display up to 12 custom-avatar instances using four distinct models on desktop, or six instances using two distinct models with touch controls. Additional custom avatars use the default character so a crowded room does not keep loading more texture sets. This limit is separate from your avatar's individual file and geometry budgets.

The upload panel shows transfer progress, elapsed conversion time and a cancel button. Requests have bounded deadlines, so a stalled request returns an error.

The importer checks the archive, converts supported model and texture data, then validates the resulting humanoid GLB in a second fresh sandbox. Only a successful result replaces your current custom avatar. Failed conversions discard their temporary files and preserve your previous avatar and selection.

Files upload directly through Cloudflare, which runs the converter and validator in separate disposable VMs. Temporary inputs and validated models use private R2 storage; only validated output is downloadable. The game server handles account authorization and model references, without receiving avatar file bytes. Large or unsupported avatars can still be rejected by the limits above.

Read the returned error before retrying. An admitted retry uses another upload attempt. For geometry or rig errors, correct the source model; for unsupported package setup, use an assembled GLB/VRM export.

HTTP reference for integrations​

Avatar upload uses the player's normal authenticated website session. World MCP credentials do not authorize avatar uploads. World prop/game-skin uploads remain static GLB workflows with their own limits; they do not accept Unity packages.

POST https://betworld.gg/api/avatars/upload

  • Body: the original file bytes, not JSON, base64 or multipart form data.
  • Content-Type: application/vnd.unity for .unitypackage.
  • Content-Type: model/gltf-binary for .glb and .vrm.
  • No HTTP Content-Encoding; a Unity package's own bounded gzip archive is decoded inside the sandbox.
  • Existing authentication, same-origin and registration checks apply.
  • Success: JSON containing player, final byte size and, for Unity packages, a compatibility notice.
  • Errors include 401 unauthenticated, 403 registration/origin restriction, 413 oversized, 415 unsupported type/encoding, 422 invalid conversion, 429 quota exceeded and 503 converter unavailable.

GET /api/avatars/ returns the current model, maxBytes: 30000000, outputMaxBytes: 4194304 and uploadsPerHour: 6.

Do not automatically retry failed imports: each admitted retry can consume another attempt. Show the returned reason and help the creator correct their original asset. Prefer a direct self-contained GLB/VRM when the Unity package depends on unsupported setup.