Geometry (from an FBX)

avatar stats model.fbx # geometry: triangles, meshes, material slots, bones avatar stats path/to/UnityProject # components, per avatar found in the project avatar stats path/to/UnityProject --json

analyze_fbx measures triangles, meshes, material slots, and bones directly from the FBX geometry.

Components (from a project)

analyze_project measures per-avatar components: PhysBones, colliders, contacts, particles, lights, renderers, constraints. Most are matched by stable Unity class id; the VRChat dynamics and constraint components are MonoBehaviours whose script GUID changes across SDK versions, so they're recognized structurally by their distinctive serialized fields (collisionTags ⇒ Contact, bonesAsSpheres/insideBounds ⇒ PhysBone collider, endpointPosition/multiChildType ⇒ PhysBone, a Sources list with a TargetTransform ⇒ VRChat constraint). A project path additionally resolves:

  • Triangles — renderer m_Mesh guid → source FBX via the .meta index (distinct files summed once; unresolved meshes flagged).
  • Bones — distinct m_Bones transforms.
  • Texture memory for PC and Android — renderer → material → texture chain; per-texture VRAM estimated from image-header dimensions + the .meta TextureImporter per-platform format (DXT/BC vs ASTC/ETC2). An estimate, since the imported GPU format isn't knowable offline.
  • PhysBone affected-transform & collision-check counts — walking the hierarchy under each PhysBone's rootTransform (descendants minus ignoreTransforms, plus an endpoint per chain tip, × assigned colliders).
  • Total particles — per ParticleSystem, VRChat's own ceiling min(maxParticles, ceil(rate × lifetime)), summed; MinMaxCurves are read by their constant term (bursts and sub-emitters approximated, so burst-heavy effects read low).
  • Mesh-particle polygons — each Mesh-render-mode ParticleSystemRenderer (paired to its system by GameObject) resolves its mesh to a source FBX and multiplies its triangles by the system's live-particle estimate. Trail and collision flags are read off TrailModule/CollisionModule enabled.
  • Constraints — Unity built-in constraint class ids 320–325 + VRChat constraint MonoBehaviours; depth = longest constraint→source chain via a memoized, cycle-safe walk (depth reported only when every source slot resolves).
Everything either source can reproduce from the files is measured — the project view's not_evaluated list is empty by default. An individual metric adds a note there only when its inputs were incomplete (an unparseable particle module, a mesh that resolves to a non-FBX source, an unresolvable constraint chain), marking the value as a lower bound rather than silently dropping it.

The threshold tables

Encoded as data on Metric::limits(Platform) (rules as data, not constants), sourced from VRChat's Avatar Performance Ranking System. Each cell is the inclusive upper bound for that tier; anything past Poor is Very Poor.

PC (Windows)

MetricExcellentGoodMediumPoor
Triangles32,00070,00070,00070,000
Skinned Meshes12816
Basic Meshes481624
Material Slots481632
Bones75150256400
PhysBone Components481632
PhysBone Colliders481632
PhysBone Affected Transforms1664128256
PhysBone Collision Check Count32128256512
Contacts8162432
Particle Systems04816
Total Particles03001,0002,500
Mesh Particle Polygons †02,00020,00050,000
Particle Trails0001
Particle Collision0001
Constraints100250300350
Constraint Depth205080100
Lights0001
Audio Sources1488
Trail Renderers1248
Line Renderers1248
Cloths0111
Physics Colliders0188
Physics Rigidbodies0188
Animators141632

Android / Quest (stricter)

MetricExcellentGoodMediumPoor
Triangles7,50010,00015,00020,000
Skinned Meshes1122
Basic Meshes1122
Material Slots1124
Bones7590150150
PhysBone Components0468
PhysBone Colliders04816
PhysBone Affected Transforms0163264
PhysBone Collision Check Count0163264
Contacts24816
Particle Systems0002
Total Particles000200
Mesh Particle Polygons †002,00020,000
Particle Trails0001
Particle Collision0001
Constraints3060120150
Constraint Depth5153550
Trail Renderers0001
Line Renderers0001
Animators1112

Lights, Audio Sources, Cloths, and the physics colliders/rigidbodies are not ranked on Android (those components are stripped on mobile). † The Mesh Particle Polygons bounds are the repo's own triangle-style ramp — VRChat folds mesh-particle polygons into its particle budget rather than publishing a standalone table.