A Unity Editor tool that converts a VRChat SDK3 avatar into a ChilloutVR CCK 4 avatar — animator, menus, physics, contacts and face tracking — and hands you a clean starting point to finish by hand.
75+ avatars converted, uploaded and worn in ChilloutVR — by the author and by independent testers, on other people's models, not just tidy test cases. Heavy ones too: 400k-triangle avatars with 56 material slots, full VRCFury rigs, face tracking, the lot.
And tested in game, which is the only test that counts. An avatar that converts cleanly and validates green can still be wrong — a shader drawing into one eye, a chain moving unlike its original, a parameter reaching nobody. None of that shows in the editor. So each of these was confirmed in a live instance, by wearing it:
- contacts triggered by other players, with real proximity and zero sync cost
- stereo shaders rendering correctly in both eyes
- prefab constraints driving real bones — Avatar Limb Scaling working end to end
- PhysBone chains moving like their originals, derived from both solvers' source
- the "bicycle pose" fixed, confirmed on a tester's avatar
Bugs still turn up — every one above was found this way, by somebody putting an avatar on and looking. That's why the report exists and why reporting a bug gets a fix.
The banner runs VRChat's blue into ChilloutVR's orange, and the step markers sit along it — because that's the trip your avatar is making.
Contents: Comparison · Highlights · Requirements · Installation · Usage · What gets converted · Constraints · Physics · Contacts · Shaders · Parameter types · Face tracking · Store description · Setup mode · Known limitations · Troubleshooting · Reporting a bug · Credits
vrc3cvr is the reason this one exists — AvatarBridge started by studying it (see Credits). Use Narazaka's vrc3cvr (MIT) as the point of comparison: the original was archived in May 2023, and Narazaka's is the maintained CCK4-era fork. If you want a smaller, focused converter, it's a good tool and it is the one to compare against.
The two overlap less than the names suggest. What differs, from Narazaka's documentation as of mid-2026:
| AvatarBridge | vrc3cvr (Narazaka) | |
|---|---|---|
| Menus, parameters, gestures | ✅ | ✅ |
| PhysBones → DynamicBone | ✅ built in | via the external PhysBone-to-DynamicBone |
| PhysBones → MagicaCloth2, feel derived from both solvers' decompiled source | ✅ | — |
| Modular Avatar | ✅ baked automatically | ✅ via its own component + manual bake |
| VRCFury (toggles, linked clothing, merged armatures survive) | ✅ baked automatically | manual |
| VRCFury's sync workarounds removed instead of carried across broken | ✅ | — |
| Contacts | ChilloutVR's own contact components — real proximity, tags verbatim, no sync bits spent (experimental) | emulated with CVRPointer + trigger, which fire on collision rather than on proximity |
| Stereo shaders patched so effects stop drawing into one eye | ✅ | — |
| Gaze limits measured off your avatar's own poses; the viewpoint your avatar already shipped with | ✅ | — |
| Constraints that drive another transform (Avatar Limb Scaling et al.) | ✅ | — |
| Custom locomotion, fall, sit and flight animations carried into CVR's own locomotion | ✅ | — |
| A per-conversion report + diagnostics that know what ChilloutVR deletes on load | ✅ | — |
| A play-mode tester that drives the converted avatar the way the game does | ✅ | — |
| Store description generated and typed into the upload page | ✅ | — |
Every ✅ in the AvatarBridge column is documented on this page, and most are confirmed in game — see the banner above for what that means here. The right-hand column is read from vrc3cvr's own documentation, not from testing it; if anything there is wrong or has since changed, open an issue and it gets corrected.
AvatarBridge does the tedious ~90%. It does not make avatar setup brainless, and can't — the
two platforms differ and VRCFury setups vary endlessly. It assumes you know your way around
Unity: the Animator window, blend trees, the CVRAvatar component.
Every run writes a ConversionReport.md you're expected to read — act on each Warning,
Approximated and Skipped entry — alongside a Diagnostics.md you don't need to read at all
unless something's wrong, and should attach to any bug report. Every conversion should be tested
in ChilloutVR before you call it done. The editor can't show you gestures, contacts, synced parameters or physics
actually running.
-
VRCFury & Modular Avatar avatars work. Fury's own builder (or NDMF's bake) runs first, so toggles, linked clothing and merged armatures survive — and Fury's VRChat-only sync workarounds are removed rather than carried across.
-
PhysBones become real physics — MagicaCloth2 or DynamicBone, no external tool, with the chain's feel converted from the PhysBone's own numbers.
-
Prefabs that drive your bones keep working, including constraints that target a different transform — the way Avatar Limb Scaling and many others are built.
-
Readable output — clothing toggles come out as one
Toggle <name>layer each, on realboolparameters. -
Toggles that go both ways — VRChat's standard toggle leaves its "off" state empty and lets Write Defaults undo the change. Nothing carries that rule across, so those toggles used to switch on and stay on. The off direction is now real animation, reusing your avatar's own clip where it has one.
-
Your avatar's own locomotion crosses over — custom walking, crouching, crawling, falling and sitting animations are grafted into ChilloutVR's locomotion layer, matched by blend-tree position; emotes move into the one layer that can both pose the body and hand it back; a flight pose rides CVR's native flight. The game moves you, with your avatar's art.
-
Bloat removed — GoGo Loco and SPS/OGB/PCS stripped (one avatar went from 3088 to 240 of 3200 sync bits).
-
Face tracking, your way — native
CVRFaceTracking, a bundled rig with eye tracking wired up, or your avatar's own FT rig converted whole. ARKit and Unified Expressions meshes both work. -
ChilloutVR's native contacts — one-to-one, with real proximity and zero sync cost (contacts are per-client by design), using a system the CCK doesn't expose (experimental).
-
Shaders that lose an eye get fixed — CVR renders single-pass instanced where VRChat renders double-wide, so shaders that never opted in draw into one eye only.
-
Diagnostics that know ChilloutVR — the report names components CVR silently deletes on load, tracks the 3200-bit sync budget, and flags shaders the uploader will reject.
-
The output folder is the whole conversion — every clip and mask the controller references is copied into
RehomedAssetsand the controller repointed, so a conversion survives being moved to a project without the source avatar's folders. One tester's controller referenced 71 clips that lived only next to the source avatar; anywhere else they'd have played as stillness, with no error. (The CCK's own clips stay referenced — uploading requires the CCK, so they're always present.) -
A play-mode tester that drives avatars the way the game does — Tools → Avatar Bridge → CCK Animator Tester: gestures, stances, visemes, emotes, face tracking and the avatar's whole Advanced Settings menu, plus a live Animator-layers readout. VRChat's Gesture Manager can't do this — it needs the VRC descriptor, which conversion removes.
What it drives, and how faithfully
Locomotion is offered as the exclusive stances the game can actually produce — standing, crouching, prone, airborne, flying, sitting, swimming — with Upright coupled to stance the way VR height is. Menu controls are coerced by declared type exactly like the client, and the card follows the controller on the avatar's Animator: it refreshes when the controller or its parameter list changes, and greys any entry whose parameter the controller doesn't declare, because driving those would do nothing in game either.
Visemes and blink are held on the face mesh every frame, after the animator — the same place and order ChilloutVR writes them, so they beat any animation using the same blendshape here exactly as they will in game. An expression that fights the blink loses honestly, in the editor, before you upload.
The Face tracking section drives every eye and Unified Expressions parameter the controller declares, grouped by region, with each slider's range read from the rig's own blend trees — so bipolar shapes (JawX, SmileFrown, the tongue axes) get their full −1…1 travel instead of half. On an avatar converted to native
CVRFaceTrackingthere are no such parameters — the client writes blendshapes straight from the headset, with no animator in the loop — so the section shows a slider per mapped blendshape instead, writing the mesh the same way the client will.The Remote view card snaps every
#local parameter to its default — the value it holds forever on other players' clients, which never receive local parameters or parameter streams. A layer that starts cycling or lands in a different state after pressing it is doing exactly that in game for everyone but the wearer — the cause of "an animation loops rapidly for others but looks fine to me".The Animator layers readout is pinned to the bottom of the window so it stays visible while you drive the controls above it, and shows every layer's weight, avatar mask and currently playing clips — the same view ChilloutVR's in-game CCK Debugger gives, plus the mask column it can't show. Any layer sitting above the hand-pose layers that could overwrite your gestures is marked.
-
Animations that can't possibly work get named — a locked Poiyomi shader silently deletes any property that wasn't flagged animated, so the toggle plays perfectly and changes nothing, in VRChat as much as here. The report lists every one with the renderer it belongs to, so the fix is a minute in Poiyomi's inspector instead of a day in the animator.
-
Your avatar writes its own store listing — counted from what was actually built, sized to ChilloutVR's 256-character box, and typed straight into the upload page.
(No VRChat SDK installed? The tool still runs in Setup mode and prepares any humanoid for ChilloutVR.)
| What | Version | Notes |
|---|---|---|
| Creator Companion (or ALCOM) | current | how the project itself is made — see Installation |
| Unity | 2022.3.22f1 | the version VRChat and CCK 4 both use; install it through VCC |
| ChilloutVR CCK | 4.0.x | always required — it's what the tool builds for |
| VRChat Avatars SDK | SDK3, via VCC / VPM | required to convert; without it you get Setup mode. The legacy .unitypackage SDK cannot coexist with the CCK — see Troubleshooting |
| VRCFury / Modular Avatar | current | only if your avatars use them; added in VCC alongside the SDK |
| MagicaCloth2 | optional | recommended physics target |
| DynamicBone | optional | alternative; the free VRLabs stub is enough to convert |
Neither physics package is required — choose Convert PhysBones to → None and everything else still converts.
Everything on the VRChat side comes from the Creator Companion — including the project itself. The SDK ships only as a VPM package, and VPM packages install only into projects VCC manages, so a Unity project you make by hand has no supported way to get one. (ALCOM is a drop-in alternative and works the same way.)
If you already build avatars, you already have all of this — duplicate that project and skip to step 3. It has the SDK, VRCFury or Modular Avatar and your avatars in it, imported in the right order, which is most of this list already done.
⚠️ Import order matters. Let Unity finish compiling after each step. Importing out of order can corrupt VRCFury data or leave broken scripting defines. Duplicating an existing project sidesteps this — it was already built in order.
- A VCC project on Unity 2022.3.22f1 — duplicate your avatar project, or New Project → Avatars. Never convert in your real upload project.
- VRCFury / Modular Avatar, then your avatars — in VCC's Manage Packages, from the community repos you'll likely already have listed. Fury before the avatars that need it.
- ChilloutVR CCK 4 — the
.unitypackagefrom the ChilloutVR documentation. Not a VPM package; import it intoAssetslike any other. - A physics package (optional) — MagicaCloth2 or DynamicBone.
- AvatarBridge, last — the
.unitypackagefrom Releases. It must live underAssets, notPackages, or the optional MagicaCloth2 / DynamicBone integration won't resolve.
One extra recompile after importing is normal — that's AvatarBridge registering its scripting defines.
Tools → Avatar Bridge → VRChat to ChilloutVR Converter, then:
- Pick the avatar in your scene.
- Check the options — physics target, face tracking mode, height scaler. Defaults suit most avatars.
- Convert. Output lands in
Assets/AvatarBridgeOutput/<avatar>/— a sibling of the tool's folder, so deletingAssets/AvatarBridgeto update it never touches your conversions. Read the report, then test in game.
| VRChat | ChilloutVR | Notes |
|---|---|---|
| Avatar descriptor | CVRAvatar |
visemes, blink, eye look (gaze limits measured from the poses); the viewpoint your author already placed in VRChat, copied across unchanged, with the CCK's Auto placement (eye-bone midpoint) as the fallback; voice at the jaw bone, else measured. On a quadruped decoy rig both are re-measured on the bones you can actually see |
| Expression parameters + menus | Advanced Avatar Settings | named after the menu control's label |
| Clothing / prop toggles | one Toggle <name> layer each |
pulled out of VRCFury's merged blend trees; the "off" direction becomes real animation instead of relying on Write Defaults |
| Parameter types | real bool / int / float |
see below |
| Gestures | float threshold bands, the CCK's own idiom | analog fist blends in by trigger pressure, like VRChat |
| Animation clips + masks | copied into RehomedAssets, controller repointed |
the output folder alone is the whole conversion |
| Skinned mesh bounds | normalized — centre 0, extents ≥ the avatar's height | stops meshes vanishing at screen edges; larger authored boxes are kept |
| PhysBones + colliders | MagicaCloth2 or DynamicBone | see below |
| Contacts | native contacts, or CVRPointer / trigger |
see below |
| VRC Constraints | Unity constraints | including Target Transform — see below |
| VRCFury parameter compressor | removed | a VRChat sync workaround that breaks sync here |
| FinalIK components | kept as-is | |
| VRC tracking / locomotion control | BodyControl |
hands a limb from IK over to animation |
| Base / Action / Sitting locomotion animations | grafted into CVR's own Locomotion/Emotes layer |
custom walk/crouch/crawl/fall/sit clips, matched by blend-tree position, loop settings matched to the slot; VRChat proxy_* placeholders skipped — those live in the VRChat client, and CVR's animation set is their equivalent here |
| VRChat flight / copter systems | pose grafted onto CVR's LocFlying state |
ChilloutVR flies natively (keybind or double-jump where the world allows), so the VRChat system's speed logic isn't needed — the avatar's flight pose plays whenever the wearer actually flies |
| VRChat's scale parameters | AvatarHeight stream + derived arithmetic |
EyeHeightAsMeters fed live; ScaleFactor, ScaleFactorInverse, EyeHeightAsPercent, ScaleModified computed from it each cycle against the converted viewpoint height |
| Jaw-flap lip sync | visemeMode = JawBone / SingleBlendshape |
rig-driven, no wiring needed |
| VRC Head Chop | FPRExclusion |
|
| Avatar cameras / listeners | removed | a stray Camera crashes CVR's asset filter |
| Avatar audio sources | clamped to VRChat's limits — doppler 0, distance floors/caps | CVR feeds them to its spatializer unclamped; one minDistance 0 source on the wearer's body can mute the whole game's audio while worn |
PhysBone _IsGrabbed / _Angle |
GrabbyBones mod | optional mod, not bundled — see grabbing |
| Face-tracking blendshapes | native CVRFaceTracking, bundled rig, or your own rig converted |
see below |
| Menu Button controls | ordinary toggles | |
| Shaders without stereo support | patched copy in RehomedAssets |
optional — see below |
| VRCFury temp materials/shaders | rescued into RehomedAssets |
Fury deletes its temp folder on its next build |
GoGo Loco and SPS/OGB/TPS/PCS are stripped by default (both toggleable). CVR has its own locomotion, and the haptics stacks don't function there while eating most of the sync budget.
Animation that can't do anything is stripped too (Remove animation that can't do anything, on by default). A curve writing to a material property the renderer's shader doesn't have — the signature of a locked Poiyomi shader that baked it away — does nothing in ChilloutVR and did nothing in VRChat either. Those curves go, and anything left with no purpose goes with them: a clip animating nothing, a layer whose every clip is empty, then the parameter and the menu control that drove it. The result is an avatar without sliders that move and change nothing. Renderers whose materials an animation swaps are never touched — there the property may well exist on the material being swapped in — and only the conversion's own copies of the clips are edited, so the source avatar is untouched. Fix the materials in Poiyomi and convert again to get the real controls back; the report names everything removed either way.
Keeping GoGo is experimental, with hard limits. With Remove GoGo Loco unticked, GoGo fully
replaces ChilloutVR's locomotion the way it replaces VRChat's: the CCK's own Locomotion/Emotes
layer is removed and GoGo's Base/Poses/Action take over, driven by the game-fed velocity and
upright parameters — so Base, Additive and Action must be ticked under layer merging or the
avatar has no locomotion at all. The limits are architectural, not bugs to file: GoGo leans on
VRChat-only animator primitives with no ChilloutVR equivalent — locomotion locking
(VRCAnimatorLocomotionControl, so poses slide if you walk mid-pose) and pose-space viewpoint
shifts (VRCAnimatorTemporaryPoseSpace, so the camera stays at standing height in floor poses) —
and CVR's quick-menu emotes won't animate, since GoGo's own wheel replaces them. ChilloutVR
provides locomotion, emotes, AFK and flight natively; removing GoGo remains the recommended
path. The strip removes GoGo's Base/Additive/Action layers whole — a locomotion replacement
left half-alive overrides CVR's locomotion with dead animation, which is worse than either
extreme.
The VRCFury Parameter Compressor is removed. It beats VRChat's 256-parameter ceiling by marking your real parameters not synced and rotating mirrors through a couple of slots twice a second. ChilloutVR has 3200 bits and syncs straight from the animator, so carried across it costs a per-frame blend tree and — because the originals stay marked not-synced — the values reach nobody. Removing it puts every affected parameter back to syncing natively.
Anything VRCFury or Modular Avatar installs is baked first, so most prefabs convert without needing to be known about. Tested end to end and working in game:
| Prefab | Notes |
|---|---|
| Avatar Limb Scaling | sliders scale the real bones; needs the Target Transform handling below |
| GoGo Loco | stripped (CVR has its own locomotion, emotes, AFK and flight; GoGo relies on VRChat-only animator primitives and cannot function in CVR — see What gets converted) |
| VRCFaceTracking / ARKit rigs (Jerry's, Pawlygon…) | replaced by the chosen face-tracking mode — or converted whole with Keep the avatar's own rig (smoothing proxies go #-local, zero sync cost) |
If a prefab's feature comes through inert — the menu control appears, moves, and does nothing — that's worth reporting. Every case so far has been a fixable gap in AvatarBridge.
A VRC constraint can sit on one object and drive a different one, through its Target Transform field. Unity's constraints have no equivalent — they always affect the transform they're
attached to. AvatarBridge honours it by putting the Unity constraint on the target instead,
carrying the same sources.
That matters more than it sounds: prefabs routinely put constraints on proxy objects inside their own hierarchy and point them at your real bones. Dropping the redirection doesn't weaken such a prefab — it silently stops it working while everything still looks wired up.
A Target Transform pointing outside the avatar can't be honoured (it wouldn't survive an upload); the report says so plainly.
Rotation offsets are measured, not copied. Copying VRChat's RotationOffset field
trusts that both engines apply it in the same space, and that held until a constraint crossed two
very differently oriented bones — a car avatar's windshield pupils mirror its face eye bones through
rotation constraints, and the copied offset left them rotated 77° edge-on, invisible. VRC constraints
evaluate in the editor, so at conversion time the scene pose is VRChat's solver output; for an
active, full-weight, single-source rotation constraint the offset is now derived from that pose
directly, with no cross-engine assumption. Multi-source or inactive constraints still copy the field.
An unfollowable local-space constraint yields to its animation. VRChat constraints can solve in the source's local space; Unity's only solve in world space, and when the constrained bone can't be re-parented to bridge that (it skins the mesh), the converted constraint is wrong whenever the two parent chains move apart. If a clip in the controller also poses that bone, the wrong constraint overrides the right animation — constraints evaluate after animators. So in exactly that case the constraint is now disabled and the animation stands. The avatar that forced the choice: windshield pupils mirroring the face eye bones folded 77° edge-on the moment the body folded into a car, while the car animation had them keyed perfectly all along. What's lost is only the live follow — the pupils sit where the author posed them instead of tracking eye movement. Bones nothing animates keep the world-space follow, which is the behaviour the walking quadruped shipped with.
Solving in local space is repaired where it can be. VRChat's constraints can read the source's local rotation instead of its world one, and that's the default in the SDK's own inspector. Unity's constraints only ever solve in world space, and ChilloutVR ships no equivalent — its constraint types are Unity's own.
Most of the time this costs nothing: where the constrained object and its source hang off the same parent, that parent's rotation appears on both sides and cancels, so the two spaces agree exactly. It matters when the source sits in a different chain — and there the parents can be made to agree, by moving the constrained bone under the source's own parent. That isn't an approximation: it turns the one constraint Unity can't express into one it can, and it cascades, because once a chain's root pair matches every pair below it matches too. This is what makes quadrupeds work.
Moving a bone is only safe when nothing depends on where it is, so it happens only when the relay is rotation-only, no mesh skins to the bone, no animation addresses it (curves are matched by path, and a moved bone would silently stop being animated), and nothing involved is mirrored — a negative scale flips handedness, which no re-parenting can carry across. Every move is named in the report, and anything failing a check is left alone and reported instead.
Structure transfers exactly: which bone the chain hangs from, which colliders it collides with, which transforms to leave out, whether it started enabled.
So does the feel. Each chain's pull, spring and stiffness are converted into
MagicaCloth2's damping and angle restoration, and immobile into its inertia. Every adjustment is
named in the report alongside the PhysBone's original numbers.
How the conversion is derived, and why it took so long
For a dozen versions AvatarBridge refused to map these at all, on the stated grounds that PhysBones were per-bone rotational springs and MagicaCloth2 a particle position solver, so no arithmetic between them could mean anything.
That was wrong. The VRChat SDK ships VRC.Dynamics.dll unobfuscated, and
PhysBoneManager.PhysBoneJob.SolveChain integrates bone endpoints, reading rotations back out of
where they land — the same thing MagicaCloth2 does. The real obstacle was calibration: both apply
per-step coefficients at a fixed rate, PhysBone 60 Hz and MagicaCloth2 90 Hz, so a retention r on
one side is r^(60/90) on the other. Three multipliers had to be undone along the way —
MagicaCloth2 scales its restoration stiffness by 0.2 before the solver sees it and applies it
three times per step, and PhysBone's stiffness isn't an independent axis at all (the algebra
collapses it into a scale on the other two, and Simplified integration never reads it).
The check that it's right: push MagicaCloth2's own default restoration back through the mapping in reverse and you get a PhysBone pull of 0.168, against a default PhysBone's actual 0.160. Two authors who never spoke, five percent apart.
Four facts about the source carry over without any conversion, because they're categorical rather than numeric:
- No gravity stays none — presets ship their own, and one of them would make a chain fall for the first time in ChilloutVR
- Negative gravity points up
- Immobile becomes inertia influence, applied to both of MagicaCloth2's inertia values and — for the default All Motion type — an inertia anchor on the chain's parent bone. That anchor is what makes a chain stop swinging when your head turns, not only when you walk.
- Wind influence goes to zero, because VRChat has no wind at all. ChilloutVR worlds do, and MagicaCloth2 ships fully responsive to it, so a converted chain would otherwise pick up motion its author never tuned for.
Is Animatedsets Animation Pose Ratio to 1. MagicaCloth2 settles a chain back to the pose the avatar was built in; a PhysBone markedIs Animatedis one an animation moves. Left at the default the two fight and the cloth wins — a chest or ear slider that scales its own bones simply stops working, and the avatar quietly has a different shape from the original at identical menu settings. The source flag decides this, so it's applied rather than reported.
Stretch & squish, multi-child blending and angle limits are reported rather than converted, each naming the field to change if that chain wants it.
Using DynamicBone instead? None of this applies — PhysBones and DynamicBone are the same kind of simulation, so that path maps values 1:1.
⚠️ Physics can only be judged in game. Nothing steps a cloth solver in edit mode, and shaking the avatar root in play mode proves nothing — MagicaCloth2's speed limits make a chain follow rigidly the moment they're exceeded, so a fast shake looks still whatever the settings say.
| setting | default | what it does |
|---|---|---|
| Match a preset to each chain | on | Hair, tail, skirt, cape or accessory by bone name; otherwise a soft/middle/hard spring by how firmly the PhysBone held its rest pose |
| Fit the preset to the PhysBone | on | The four categorical facts above. Turn it off to get the preset exactly as its author wrote it |
| Derive physics from the PhysBone | on | Converts pull, spring and stiffness into damping and angle restoration, replacing the preset's feel. Turn it off to get the preset's feel back |
| Cap particle radius to bone spacing | on | A safety rail: MagicaCloth2's radius is the particle size, and particles wider than the gap between bones shove each other apart |
| Convert toe PhysBones | off | Toes are left out of the simulation entirely — both chains rooted at them and toe branches found part-way down a longer chain (a leg or skirt chain that runs through the feet), for MagicaCloth2 and DynamicBone alike. Simulated toes splay and swing while IK plants the foot, which reads as broken feet rather than as physics. Turn on if the toe physics are deliberate |
| Transfer angle limits | off | |
| Auto-assign nearby colliders | off | Gives each cloth the avatar's own colliders it could swing into. Improves on the original rather than copying it, so check before uploading |
| Add physics to toggled rigs that have none | off | A toggled style (usually add-on hair) carrying its own rig and mesh but no PhysBone was rigid in VRChat too; this synthesizes a MagicaCloth for it, preset by classification, wired to the style's toggle. Off because it invents physics the author never made |
ChilloutVR's contact system is a near-exact match for VRChat's — the same Sphere/Capsule shapes,
the same allowSelf / allowOthers / collision tags under the same names. It lives inside the
game client and the CCK ships no way to author it, so converters have always had to approximate it
with pointers and triggers.
AvatarBridge can author it directly. Turn on Use ChilloutVR's native contacts under Advanced and contacts convert one to one: real proximity, tags verbatim.
MagicaCloth2 has no grab. VRChat lets you take hold of a PhysBone and pull it, and plenty of avatars are built entirely around that — a pump handle, a leash, a lever, anything a stranger is meant to pull. Converted, those chains still hang and swing, but nobody can hold them.
GrabbyBones adds grabbing back,
and AvatarBridge already targets it: converted cloths are named after the PhysBone's parameter so
the mod's _IsGrabbed and _Angle drive your existing grab-reactive logic, and those parameters
are kept synced rather than made local. That's as far as any converter can go — grabbing is a
client mod, so only people who have installed it can grab anything on your avatar.
The failure this causes is silent and looks like something else. On one balloon avatar the pump handle carries a contact sender, and inflating works by someone grabbing the handle so that sender reaches its receiver. Convert it and every part checks out — cloth present, sender present, receiver present, tags matching — but the handle can't be grabbed, so it never moves and nothing fires. An afternoon went into blaming the contact tags. The report now lists every chain that was grabbable in VRChat and marks the ones carrying a contact, because those are the features that go completely inert without the mod.
A contact only fires when something sends a matching tag, and the two platforms name the same
body parts differently. Everyone in ChilloutVR carries pointers on their hands and index fingers
whatever avatar they wear — the client turns each CVRPointer into a contact sender tagged with its
type — but those types are LeftHand, RightHand, index, where VRChat says HandL, HandR,
FingerIndexL. Hand happens to be spelled the same on both, which is why some converted
contacts worked and others silently never fired.
Receivers listen for both, so a stranger's hand or finger sets them off:
| Your receiver listens for | Also listens for |
|---|---|
Hand |
grab |
HandL / HandR |
LeftHand / RightHand |
any FingerIndex* |
index |
The VRChat tags are kept, so converted avatars still trigger each other exactly as before.
Tags the author invented — pump, Balloon, a system's private name — reach nobody, because
nothing else in the game sends that word. Between two copies of the same avatar they work fine; to
everyone else those receivers are inert. That's usually deliberate, so nothing is changed, but the
report lists them so it isn't a surprise. Add a body-part tag to a receiver if you want strangers to
be able to set it off.
Contacts are per-client by design — the system is by NotAKidoS, a ChilloutVR developer, and this is confirmed in game: every client simulates every avatar's contacts itself.
⚠️ Experimental — this talks to a component internal to the game, not the CCK, so any ChilloutVR update can break it, possibly for good. Treat it as a bonus, not something the avatar depends on. (The window shows the same note while the option is on.)
AvatarBridge's generated declarations are verified field-for-field against the decompiled game client — the only layout that matters, since the client is what reads the uploaded avatar. The author's public repository is a diverged work-in-progress: don't import it into a conversion project while it disagrees with the game (its current layout drops fields the shipped client still reads, including the content-type flag that lets other players' hands trigger receivers). Its MIT-licensed custom inspector is adapted into the generated declarations, so contact components get proper foldouts and per-receiver-type help text in the editor.
How it works without CCK support. An uploaded asset bundle carries no script assemblies — only
a record of each component's assembly, namespace and class name, which every player's client
resolves against its own assemblies at load. The contact implementation already ships inside the
ChilloutVR client; it is the CCK that provides no way to author it. So AvatarBridge generates
matching declarations into AvatarBridge/Runtime on import — same identity, same field layout,
verified against the decompiled client — and the game's own implementation is what runs. Nothing
here reimplements contacts in Unity, and nothing is bundled into the avatar; the declarations are
removed automatically if a future CCK ships the real thing.
That is also why sync works out differently from the CVRPointer + trigger emulation other
converters use. Emulation needs the network to agree on collision events; here every client
already simulates every avatar's contacts locally, so detection costs no sync at all. Whether
the parameter a receiver drives replicates its value is that parameter's own sync declaration —
unchanged, and exactly as everywhere else.
✅ Confirmed in a live ChilloutVR instance: validation clean, avatar uploaded, contacts triggered by other players, and CVR's own runtime gizmos drawing the components — proof the game's real implementation is running against declarations generated here.
Still off by default — chiefly because of the note above, beyond just breadth of testing. Turn it on deliberately and test in game; the conversion falls back to the legacy path by itself if anything is wrong.
⚠️ If a conversion leaves brokenContact_*components behind, delete them and reopen the scene before converting again. Unity manufactures a placeholder script for a dangling component reference, and that placeholder then captures every new component of the same class — one bad conversion quietly poisons the next. AvatarBridge detects this and refuses rather than producing another broken avatar; Tools → Avatar Bridge → Diagnose native contacts shows what Unity is holding.
ChilloutVR renders single-pass instanced; VRChat renders double-wide single-pass. Both SDKs force their own mode unconditionally.
Under double-wide a shader gets both eyes without asking. Under instancing it has to declare that it knows which eye it's drawing — so a shader that never opted in looked perfectly fine in VRChat and draws into one eye only here. Nobody did anything wrong; it's a conversion problem, which makes it worth fixing here.
Fixing one by hand
Four macros, each with one home — copy the shader first, it's usually someone else's asset:
| macro | goes in |
|---|---|
UNITY_VERTEX_INPUT_INSTANCE_ID |
the vertex input struct (appdata) |
UNITY_VERTEX_OUTPUT_STEREO |
the interpolator struct (v2f) |
UNITY_SETUP_INSTANCE_ID(v); |
top of the vertex function, after the output struct is declared |
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); |
same place, right after it |
Add UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); at the top of the fragment function too if it
samples anything screen-space. Only realistic on a plainly written shader: surface shaders have no
vertex stage to edit, and locked or generated shaders aren't worth attempting.
Turn on Patch non-SPI shaders for VR in Advanced. For each affected shader it writes a patched
copy into RehomedAssets, adds the stereo macros, and points this avatar's materials at the copy.
- Your original shader and material are never modified — both are copied, so other avatars sharing them are unaffected. (Those shaders usually aren't yours.)
- A copy that doesn't compile is thrown away, so the worst case is a line in the report rather than wrong pixels.
- Screen-grab effects are fixed too. A
GrabPasstexture is a texture array under instancing — one slice per eye — so lens, refraction and heat-haze shaders that read it withtex2Dshow one eye the other eye's view no matter how many macros they have. Those reads are rewritten to the screen-space macros, same as_CameraDepthTexture. - Shaders needing more than the derivable fixes get a recipe — written by hand once, kept in AvatarBridge's recipe list, and applied to your copy on every later conversion. Each recipe is pinned to a fingerprint of the exact shader version it was written for: an updated or edited shader doesn't match and is refused rather than guessed at. Nothing is redistributed — the recipe is the edit, not the shader, and your original file is never touched. Hit one that has no recipe yet? Open an issue and it can be added for everyone.
- Not everything can be patched. Surface shaders have no vertex stage to edit, and structs in a shared include can't always be edited from one file. Those are listed for hand-fixing instead.
- Every shader gets a verdict in the report — patched, couldn't be patched, or already
speaks single-pass instanced and was left untouched. Locked and generated shaders (Poiyomi
lock-in and SPS live at
Hidden/Locked/…) are read and checked like any other; modern Poiyomi declares the full macro set, so these normally land in the already-correct list rather than needing anything. - There's nothing to undo. The macros are mode-agnostic — real instancing code under CVR, nothing under VRChat or on desktop. The patched copy stays correct everywhere.
✅ Confirmed in game: a soft-particle effect the CCK flagged as non-SPI was patched, validated, uploaded, and renders correctly in both eyes.
Still off by default, on one avatar's evidence. Compilation is all that can be checked automatically — whether it looks right is a judgement no editor script can make, so turn it on deliberately and check the effect in both eyes.
Passing the CCK's check isn't the same as being correct. It looks for four macros; a shader can have all four and still be broken, because both the depth texture and any
GrabPassare texture arrays under instancing — a soft-particle shader reading_CameraDepthTexturethroughsampler2D/tex2Dproj, or a glass/refraction shader reading its grab texture throughtex2D, takes the wrong slice however many macros are present. AvatarBridge rewrites both.
VRCFury bakes every menu parameter as a float, whatever it really is. Harmless in VRChat; not
here, because ChilloutVR writes a menu value using the entry's own declared type — write a Bool
into a Float parameter and nothing happens. That's the most common cause of "the toggle does nothing
in game".
So each parameter is retyped from what the avatar's logic says it is: the menu control it drives
(Toggle → bool, Dropdown → int, Slider → float), or for parameters with no control, how the
animator compares it. Anything read as a quantity — blend tree, motion time, or written by a
clip — stays float, and is named in the report so you can see the tool declined rather than
missed it.
Pick one in the Face tracking dropdown. The two set-up modes remove whatever FT rig the avatar shipped with — animator layers, parameters and objects — so nothing is left fighting over the same blendshapes. On a typical VRCFT avatar that's a couple of layers and a few hundred parameters.
- Native CVR Component — sets up
CVRFaceTrackingand maps the shapes. Self-contained, but the built-in solver is a bit stiff. - Unity Animator Blendtrees (DSR) — injects DragonSkyRunner's CVR Eye & Face Tracking rig (bundled), repaths every clip onto your actual eye bones and face mesh, and reconciles its shape vocabulary against whatever your mesh has — by name, casing, ARKit ↔ Unified Expressions aliases, and combined/split rules. An ARKit avatar works without renaming anything. Smoother and more expressive.
- Keep the avatar's own rig — nothing is stripped, and this is not a do-it-yourself option:
the existing rig (Jerry's Templates, Pawlygon, OSCmooth setups…) converts with the rest of
the animator. Smoothing proxies VRChat never synced automatically become
#-local — which costs zero sync bits, so a full smoothed rig fits ChilloutVR's 3200-bit budget comfortably — and the FT parameters that were synced keep syncing. The pick for avatars whose shipped rig is the point.
Every mode needs a tracking source at runtime — true of any CVR face-tracking avatar. Run VRCFaceTracking and set CVR's Eye Tracking and Mouth Tracking modules to OSC.
ChilloutVR's upload page wants a description, and most listings never get one. AvatarBridge writes a starting point out of what the conversion actually produced:
← your own words go here
Vap
8 toggles · 9 sliders · 9 physics chains (MagicaCloth 2) · blink and lip sync
Converted from VRChat with AvatarBridge
github.com/MrTactical/AvatarBridge
Two buttons on the report:
- Fill CCK description — types it into the Content Manager's Description box. Open the CCK Control Panel on the Builder tab with your avatar selected first. It won't touch the box if you've already written something there.
- Copy description — puts it on the clipboard to place yourself.
Either way it's saved as Description.txt beside the report.
Every line is counted from the finished avatar, so no two are alike — and each claim is checked against what was built, not what you asked for. Face tracking is only mentioned if the component is really there; the height slider only if its control reached the menu. This text goes into a public listing under your name, so a line it can't verify is a line it doesn't print.
It's also built to fit: ChilloutVR's box holds 256 characters, and ~90 of those are left free for your own words. The generated part is meant to be the footer of your description, not the whole of it.
Without the VRChat SDK there's no VRChat data to read — a VRChat avatar's components won't even
deserialize — so conversion isn't possible. Instead the tool prepares any humanoid for
ChilloutVR: CVRAvatar with viewpoint and voice position, viseme and blink detection, face
tracking, and the height scaler. Useful for a Booth model or an original avatar.
Why there's no VRChat SDK stub
A GUID-matching stub (like the DynamicBone one) could recover simple components, but it could never run VRCFury or NDMF — those are real code needing the real SDK — so Fury avatars would silently convert to empty shells. Unity also deserializes by field name and silently defaults what it can't match, so every SDK update would quietly change the output. The DynamicBone stub exists to work around a paywall; the VRChat SDK is free, and VCC installs it with the project.
Quadruped support is real but partial, and how much you get depends on how yours was built. Unity has no quadruped rig — every quad on VRChat is a humanoid skeleton driving an animal-shaped one by some trick, and which trick decides what survives conversion. Three have been converted and dissected here; they behave completely differently.
All three share one symptom, which is the fastest way to recognise the family: none of their
humanoid bones move any geometry. The conversion reports that outright, and Diagnostics.md gives
you the number (Mapped bones … that deform mesh: 0 (0%)) plus every mapped bone's full path. It
matters because ChilloutVR hangs the viewpoint, the voice position and first-person head hiding off
humanoid bones — so on all three they follow a skeleton nobody can see, pass every internal check
against it, and still land half a metre from the avatar's face.
| How it's built | Tell-tale | What you get |
|---|---|---|
| Constraint relay — hidden biped, VRC constraints copying it onto the animal | bones named *Human, ~60 VRC constraints |
Walks in game. Locomotion, poses, limb locks, viewpoint, first-person head all working. Hind legs land reflected — see below |
| Unity-constraint rig (e.g. AnyTaur) — same idea, Unity's own constraints | RotationConstraint throughout, no VRC constraints |
Best case. Nothing to translate, so none of the constraint walls apply at all |
FinalIK proxy — humanoid mapped into a VRIK proxy skeleton |
mapped bones sit under .../VRIK/PROXY_* |
Least working. The visible body is posed by IK and relays that can't convert |
The one thing worth knowing before you start: a quad built on Unity constraints converts almost untouched, because VRChat's constraint features are what don't survive — local-space solving and the negative-scale correction. If you're choosing or commissioning a quad base for ChilloutVR, that is the single biggest predictor of how well it will land.
The viewpoint and voice get rescued when they land off the body. Rather than trying to recognise a fourth rig design, this asks the one question no skeleton can lie about: is the marker further from every bone that deforms mesh than this rig's own proportions allow? If so it isn't on the avatar, however well it measured, and it's re-placed from the eye markers that are on the body. A marker already on the body is never touched, so avatars that are correct — including the other two quadrupeds — can't be disturbed. Naming only nominates candidates; geometry decides.
A constraint-relay quadruped walks in game — confirmed by wearing one, which is the only test that counts. Getting there took several separate fixes, and the walls below are still standing.
"Base / locomotion" is safe to leave on, quadruped or not. Merged [Base] layers are masked
off the humanoid rig — they can only replace ChilloutVR's locomotion, never add to it — so
ChilloutVR alone drives the decoy biped and the relays carry it onto the animal, while any custom
locomotion clips are grafted
into CVR's own layer.
Most quadrupeds are a hidden humanoid rig. The model carries a second, invisible biped skeleton
— bones named like HipsHuman, thighHuman.L, HeadHuman — and Unity's humanoid map points only
at those. Nothing the engine solves ever touches a bone that deforms the mesh. Constraints then
relay that decoy onto the real skeleton, bone by bone: the torso rides the biped hips, the neck
chain is the biped spine, the front legs are the biped's legs. It's an elegant trick and it needs
no FinalIK at all, so ChilloutVR has nothing to delete.
Most of that converts. On the avatar this was worked out from, 51 of 59 relays needed nothing at all. Two things break the rest, and the report names both:
- Relays that solve in local space — typically the hind legs copying the humanoid legs' articulation, so one walk cycle moves four legs. Where the copied bone can be moved under the same parent as the bone it copies, that is repaired exactly; where it can't, it's reported.
- Mirrored bones. A hind rig is usually the front rig mirrored — which is why its relays cross left to right — and a mirrored bone carries a negative scale. VRChat's solver corrects a constraint result for that; Unity's constraints have no such step and ChilloutVR ships no type that does, so those relays land reflected. Nothing on this side can fix it: Unity's constraint computes and writes its own rotation with no hook in between. Un-mirroring the bones and re-rigging is the only cure, and that's a job for your 3D package.
- PhysBones on a relayed bone. A constraint writes that bone every frame; a cloth solver integrates it from its own last state. Together they feed each other until the transform goes NaN, and the chain hangs broken with nothing to see in the animator. VRChat survives it because PhysBones re-read the constraint each frame; MagicaCloth2 and DynamicBone don't. Those chains are skipped now and listed in the report. Unity's own constraints count too — the loop is engine-level and doesn't care which component writes the rotation. An earlier version only looked for VRChat's, so a quadruped base built entirely on Unity constraints went straight past it with a tail cloth simulating three constraint-driven bones.
- Both markers on the decoy. ChilloutVR parents the viewpoint and voice position to the humanoid Head bone, which on these rigs is part of the decoy — so the camera ends up inside the animal's skull. Both are measured on the relayed bones instead; see the viewpoint troubleshooting.
- Toggles that switch a constraint on and off. This one isn't quadruped-specific, it
just bites hardest here. An animation curve carries the component type and the serialized
property name, and conversion changes both — a clip still saying
VRCParentConstraint.IsActiveplays as silence, with nothing to see in the animator. That's how limb locks, sit/lay-down/loaf poses and flight modes work on any constraint-driven avatar: release the relay so an animation can take the bones over. Curves are repointed at the Unity constraint now (IsActive→m_Active,GlobalWeight→m_Weight,Locked→m_IsLocked).FreezeToWorldhas no Unity or ChilloutVR equivalent and is dropped — a toggle relying on it will change the constraint but won't pin anything in world space. - First-person head hiding aimed at the decoy. ChilloutVR hides your own head by adding
an
FPRExclusionto the humanoid Head bone. That bone skins nothing here, so nothing was hidden and the view filled with the inside of the animal's head. One is added to the head you can see instead — your camera only; everyone else sees the whole avatar. Delete it if you'd rather not.
LOCAL_INVERSE_CNST_UpperLeg_L ← HOOMAN_UpperLeg_L (local space, mirrored parent)
LOCAL_INVERSE_CNST_LowerLeg_L ← HOOMAN_LowerLeg_L
LOCAL_INVERSE_CNST_Foot_L ← HOOMAN_Foot_L
If your quad has a "biped" mode, try it — it usually stops using the mirrored hind rig entirely and is often the configuration that converts cleanly.
Honest summary: this is limited support, not full support. One rig style walks; one converts
almost perfectly; one mostly doesn't. Nothing here is a silent failure — the report and
Diagnostics.md name which family you have, which bones fail, and why — but a quadruped still needs
testing in game before you trust it, and some will need author-side changes no converter can make.
A minority are FinalIK quadrupeds, and those have a second, unrelated problem:
What's known about those, from reading ChilloutVR's own code
GrounderVRIKis deleted on load. CVR whitelists components per-avatar and destroys the rest silently — worlds get 57 FinalIK types, avatars 13.VRIK,LookAtIK,TwistRelaxer,GrounderIK,GrounderBipedIK,CCDIK,FABRIK,AimIKandLimbIKsurvive;GrounderVRIK,GrounderQuadruped,GrounderFBBIK,ArmIK,LegIKandFingerRigdon't. The report names these.GrounderIKis not a substitute. It drives separate per-leg IK components;GrounderVRIKfeeds position offsets into VRIK's own solver from inside its update callbacks. Swapping them gives no grounding at all, and CVR has no native foot placement to fall back on.- ChilloutVR always installs its own
VRIK, auto-detecting references from the humanoid rig. On a quadruped rigged as humanoid that's a biped solve over a quad rig, and nothing a converter does can prevent it. Best current guess at the root cause; not proven.
Tracking control does convert correctly, so the groundwork is there if this is picked up again. Bipeds are unaffected by any of it.
- Blendshape-based gaze — bone-based eye look converts (gaze limits measured from the VRChat poses), but VRChat avatars whose eyes move by blendshape only get a report entry. (Blink and blendshape face tracking are handled.)
- PhysBone posing, stretch & squish and their
_Stretch/_Squish/_IsPosedparameters - VRC state behaviours other than Parameter Driver and Tracking Control (which becomes
BodyControl) — removed and counted - Synced animator layers and ONSP audio
- Content tags — set CVR's Advanced Tagging (NSFW, loud audio…) yourself before uploading
- VRChat-only rendering — SPS/TPS deformation and anything needing VRChat's own shader systems. Meshes and materials survive; the effect doesn't.
- Action-layer emotes and features. Only Gesture and FX convert by default — Base, Additive and Action are off, because CVR drives locomotion and emotes itself. Ticking Action on merges the layer at weight 0, the weight VRChat itself gives it (VRChat raises the Action playable only while an emote plays; ChilloutVR has no playable layers to raise, and at weight 1 its idle state would hold your body in rest pose above locomotion). The layer's full-body poses are transplanted into ChilloutVR's own locomotion layer instead — the one place a pose can both assert and hand back — armed once per condition-rise, exactly like VRChat's emote flow; see the menu-control entry for the mechanics. The one exception is a kept GoGo Loco — GoGo drives Action itself, so with Remove GoGo Loco unticked the layer is merged live at weight 1 instead.
- Constant contact receivers reset to 0 when any pointer exits — CVR triggers don't count occupants.
- Stacked PhysBones (several chains on one bone that VRChat toggles between) all convert, but only one is left driving the chain — two solvers on the same bones jitter rather than blend. Nothing is deleted, so switching variant is one checkbox; the report names the one kept.
- Toggled physics follows its toggle. Hair swaps and outfit toggles that activated the original PhysBone's object (or animated the component on/off) are re-wired to switch the generated MagicaCloth/DynamicBone too — a chain belonging to a style that was inactive at conversion time wakes up when its style does. Only activations are mirrored: an add-on style grafted onto another style's simulated bones must not have that chain switched off with the base style's mesh, so a hidden style's cloth may keep simulating (invisible, harmless). The report counts the re-wired curves.
- Dropdowns sometimes keep
(unused)entries. CVR selects options by position, so gaps need padding. Normally removed by renumbering, but that's unsafe when the value is used as a quantity or passed to a driver — the report says which applied. - Parameter-packing optimisers (
MemOpt_*and similar) leave odd-looking menu entries.⚠️ Don't delete them — they're what carries your toggles to other players. (Syncing comes from the animator declaration; the menu entry decides whether the value is remembered in your avatar profile between loads.) - Shaders aren't translated. Poiyomi etc. work as-is, and VRCFury-baked materials are rescued out of Fury's temp folder so they don't render pink.
- Merged layers can fight CVR's locomotion — see the bicycle pose.
Symptoms that have actually come up. Read ConversionReport.md first — most of these name
themselves in it.
The project has the legacy .unitypackage VRChat SDK installed (an Assets/VRCSDK folder)
instead of the Creator Companion / VPM one. The old SDK ships an ImageDownloader class in the
global namespace; C# resolves names through enclosing namespaces — global included — before
using directives, so it shadows the CCK's own ImageDownloader and the CCK stops compiling.
That takes the whole editor assembly down, AvatarBridge included, before any of it runs.
Install the SDK through the Creator Companion (or ALCOM) instead — the VPM packages keep VRChat's types in their own assemblies, where they can't shadow anything. This collision exists between the CCK and the legacy SDK with no AvatarBridge in the project at all, and the legacy SDK is deprecated by VRChat anyway.
Some Poiyomi versions ship ChilloutVR helper scripts that reference the CCK directly, inside
Poiyomi's own ThryExternal assembly. The CCK sets CVR_CCK_EXISTS project-wide, which
activates those scripts — but an assembly-definition assembly can never reference
Assembly-CSharp, where the Assets-installed CCK's types live, so they cannot compile no matter
what you do. (Other Poiyomi versions use reflection there and are fine.)
Fix: delete the two files — …/ThryEditor/External/Editor/AbiAutoAnchor.cs and
AbiAutoLock.cs. They are optional CCK upload conveniences (auto-anchor override, auto-lock on
upload); nothing in conversion or the CCK's own upload needs them. A Poiyomi update may bring
them back — delete again, or update to a version whose ABI scripts start with using System;
(reflection-based) instead of using ABI….
The "bicycle pose". Reconvert on a current release — merged layers are always masked off the humanoid rig (it used to be an Advanced option, confirmed in game and now mandatory).
VRChat keeps FX on its own playable layer, so an FX layer there physically can't write humanoid muscles. ChilloutVR runs one controller, so nothing stops a merged layer doing exactly that and fighting locomotion for the body every frame. The masking restores VRChat's separation; layers that animate the body on purpose are left alone, and object toggles, blendshapes and material animation are untouched. If you see this pose on a 2.62.0+ conversion, report it — the report names every layer that could write muscles.
Reconvert on a current release. A chain whose bones are also driven by a constraint is no longer simulated, and the report says which and why.
A constraint writes its bone's rotation every frame from somewhere else; a cloth solver integrates
that bone from its own previous state. Run both on one bone and each is fed the other's output —
the integration diverges, and within seconds the transform is NaN. NaN never recovers and
spreads down the hierarchy, so the chain hangs in a pose nothing explains, identically at rest, in
play mode and in game. MagicaCloth's own Scene-view gizmo can throw a NullReferenceException from
inside Burst while sorting those points, which is the same problem seen from a different angle.
VRChat tolerates the overlap because PhysBones re-read the constraint's result each frame. MagicaCloth2 and DynamicBone don't, and nothing here can reorder them. The constraint fully determines that bone's rotation anyway, so the physics had nothing to add — remove the constraint if you want the chain simulated instead.
Expected — Unity can't preview cloth. Nothing steps the solver in edit mode, and in play mode the avatar is standing still while in game it walks, turns and head-tracks constantly. Shaking the root is not a valid test: MagicaCloth2's speed limits make a chain follow rigidly the moment they're exceeded, so a fast shake looks still whatever the settings say. Judge physics in game.
Update to the current release and try again — the known causes are all repaired, from every direction: converting, selecting the avatar, entering play mode, and uploading.
Unity's playable-graph builder segfaults instead of logging on three kinds of controller damage, and the CCK's uploader builds that graph too, so an avatar in this state couldn't even be uploaded. All three are repaired during conversion and counted in the report:
-
A motion slot with nothing in it — an empty animator state, or a blend tree child whose asset is gone. Every empty slot gets a placeholder clip; nothing is lost (the slot animated nothing) and every blend threshold stays where the author put it.
-
A blend tree parameter field naming nothing. Unity binds every such field when it builds a graph — including the ones a Direct tree never reads and the Y axis a 1D tree ignores — and
Blend,ValueandSmooth Amountare Unity's own defaults left behind on trees that stopped using them, so they arrive on plenty of avatars through no fault of yours. Worst is a field that's blank. Each is renamed to a single#-prefixed name (deliberately not declared as a parameter — declaring them brings the crash back, twice measured); those fields were being read as garbage or not at all, so nothing about the avatar changes. -
A controller referencing assets that resolve to nothing. The controller is checked before it's assigned — assignment alone triggers a full graph build — and one that would crash is not assigned. The broken references usually come from a VRCFury or Modular Avatar bake that errored partway: build a test copy of the source avatar and fix what errors there, then convert again.
A missing prefab in the scene does not count, and used to. Unity names the placeholder
SFX (Missing Prefab with guid: …), that name lands in every animation path targeting the object, and the check read the GUID out of the name as though it were a reference — so an avatar with one broken prefab under an SPS socket lost its whole controller. Only real references are counted now; a missing prefab is still worth fixing, but it no longer costs you the Animator.
If your avatar's controller has none of these, the Animator is wired up exactly as before.
Reconvert on a current release. Two historical causes, both long repaired:
- Reconverting used to replace the saved controller by copying raw bytes over the file — which
keeps the GUID but destroys the native object and every sub-asset, leaving everything that
still held them (the Animator window, tester tools, anything alive with domain reload off)
holding corpses; pressing Play then re-awoke Animators against them (
Assertion failed: 'MecanimDataWasBuilt()', then a SIGSEGV inGenerateGraph). Reconverting now mutates the existing controller in place, like a hand edit: same file, same GUID, same native object. - The placeholder clip for empty states used to have no curves at all, and Mecanim sizes its
binding array from the curve count — the source of
'mem->m_ConstantClipValueCount >= 0'assertions, menu controls swapping places, and white skin under Unity's "Enter Play Mode Options". The placeholder now animates one inert value on a dedicatedAvatarBridge_EmptySlotobject, so the conversion no longer cares about that editor setting.
If you see either symptom on a current conversion, "Enter Play Mode Options" (Edit → Project Settings → Editor) deserves the first look — turning it off and reopening the scene clears the stale-state class of crash immediately, and the report warns whenever it's on.
Only affects conversions made before 2.59.0, which were written inside the tool's own folder
(Assets/AvatarBridge/Output) — so deleting that folder to update the .unitypackage erased them
with it. Check the Windows Recycle Bin first: Unity trashes deleted assets rather than
destroying them, and restoring the folder relinks everything, because the .meta files carry the
GUIDs the scene points at. Otherwise reconvert — the source avatars were never touched.
Output has landed in the sibling Assets/AvatarBridgeOutput since 2.59.0, where the update flow
can't reach it, and anything left in the old location is moved there automatically with its GUIDs
intact.
Reconvert on 3.4.7 or later, with the avatar scaler on.
A ParentConstraint holds its target a fixed distance from its source, and that distance is in
metres — Unity rotates it by the source bone but never scales it. So with the height slider the
body moved and the offset didn't: shrink and the prop hung off you, grow and it sank inside you. One
cowboy hat sat 13–18 cm out.
From 3.4.7 each offset is handed to the hierarchy instead. A small empty named
AvatarBridge_ScaleRelay_<prop> is parented to the source bone at exactly the point the offset was
already producing, and the constraint is re-pointed at it with a zero offset. Being a real child, it
inherits the avatar's scale, so the gap grows and shrinks with you. Nothing moves at the default
size, and no animation, layer or curve is involved.
Four cases are deliberately left as they were, and the report names each one:
| Left alone | Why |
|---|---|
| Offsets an animation drives | Zeroing an offset a curve is driving would hand the prop to an animation that no longer matches it |
| Sources inside a cloth or dynamic-bone chain | A new child of a simulated bone becomes a new particle and changes how the chain moves |
| Sources outside the avatar | An offset from a world anchor is meant to be in metres |
| Unlocked constraints | Unity re-derives their offsets from the live transform and would write the old one straight back |
For those, nudge the offset by hand for the size you actually use, or leave the slider near default.
A material or shader the avatar points at no longer exists. Almost always VRCFury's temp folder, which Fury deletes on its next build — so this typically appears after a later bake, on an avatar that converted fine. Convert again on the current version; if it persists, that's worth an issue.
Different from magenta and worth reporting separately. The material survived but its textures didn't — the same VRCFury temp problem one level deeper. Convert again on the current version.
Reconvert on a current release.
Before 2.71.0, a merged FX layer carrying finger curves was narrowed to a hands-only mask instead of
being blocked. Merged layers sit above ChilloutVR's LeftHand/RightHand layers, so on
Override at full weight they overwrote the pose the gesture had just played — even material-swap
layers with no finger animation of their own, purely by writing defaults into channels the mask let
through. The signature is unmistakable and maddening: the in-game CCK Debugger reports LeftHand — Layer Weight: 1.00, Playing Clips: 1.00 Thumbs Up while your fingers sit in their rest pose. The
animator is correct; something above it is winning. Those curves never moved a finger in VRChat
either — its FX playable layer can't drive humanoid muscles — so they're blocked with the rest now,
and a final audit strips fingers from any mask left above the hand layers.
Also worth knowing, and not a conversion problem: on Index-type controllers ChilloutVR only registers gestures at all while Skeletal Input or Infer Gestures from Finger Tracking is enabled in its settings. With both off, no avatar gestures work, stock or converted.
Two older causes, both fixed long before that
Before 2.62.0, gesture conditions selected poses via the integer GestureLeftIdx/RightIdx
parameters — which ChilloutVR's own stock avatar animator never uses, and which the game doesn't
reliably feed. Fingers worked in the editor tester (which drives them directly) and froze in game.
Conversions condition on the GestureLeft/GestureRight floats with the CCK's own threshold bands
now, the same client path every stock avatar runs.
Before 2.61.0, the controller referenced its clips wherever the source avatar kept them; in a
project without those folders every missing clip resolves to None and plays as stillness, with no
error anywhere. "Works on the author's PC, frozen on someone else's" is that one's signature. Every
referenced clip and mask is copied into the output's RehomedAssets now.
Before 3.5.13, reconverting the same avatar added another copy of every rescued asset
rather than replacing the last one — Angry.anim, Angry 1.anim, Angry 2.anim, on and on. The
controller used the newest and the rest were orphans nobody referenced: one test avatar had
reached 22 copies of a single clip and 554 .anim files in one output folder. Names are now
reused between runs, so the folder stays the size of one conversion. Delete the output folder
once and convert again to clear what earlier versions left behind.
Reconvert on a current release.
The viewpoint comes from your avatar's VRChat descriptor — the position its author placed by eye and shipped, copied across unchanged. The CCK's Auto button instead reads the humanoid eye bones, and on rigs where those bones aren't where the eyes are it is confidently wrong: one robot avatar's eye mapping sat 6 cm off-centre and 9 cm behind its face, while the author's own value matched the hand-corrected position exactly on X and to half a millimetre on Z. Auto is still used when the descriptor has no viewpoint set, and the report says which was used and how far apart they were.
Eye bones are found by name when the rig doesn't map them, and that search knows Blender's
.L/.R suffix (eye.L, eye.R) as well as LeftEye-style names — Blender exports that
suffix by default, so it covers most anthro avatars. It also looks anywhere on the avatar, not
only under the head bone: rigs park eye bones outside the head all the time when something
else needs to drive them, and one taur base keeps its pair in a cloned spine chain under a node
named Head.children.go.here. A match is only accepted if it lands within the same distance of the
head that this rig's proportions already allow, so a stray bone elsewhere on the body is refused.
Without this the viewpoint fell through to a blind head-offset estimate and sat 14 cm low, on the
muzzle.
Unless the authored value is provably in the wrong place. A viewpoint isn't a matter of taste — it's where your eyes go — so if it lands further from the head bone than the rig's own proportions allow and Auto lands within them, Auto wins and the report says so. One taur base shipped its viewpoint at the avatar's hips, 0.6 m from its head; the old rule copied it faithfully and then warned about the value it had just chosen.
The conversion checks its own answer — it re-draws each position the way the CCK's inspector will and measures it against the head bone — so the report tells you when a placement is wrong instead of leaving it for the first person who hears your voice coming from ten metres away. Putting the avatar at the top of the scene hierarchy before converting avoids the scale cases entirely, and the CVRAvatar inspector's own Auto buttons are always a safe manual fix.
On a quadruped, neither the author's viewpoint nor Auto is looking at your avatar. Those rigs are a hidden humanoid decoy, and ChilloutVR hangs both markers off the humanoid Head bone — which is part of the decoy, not part of the animal. On the dragon this was found on, the shipped viewpoint sat 0.57 m from the dragon's eyes, inside its skull: looking up was fine, looking down filled the screen with the inside of its own mouth. Auto was no better — it reads the decoy's eye bones and lands half a metre out too.
The relay constraints say where the real bones are, so the conversion follows them: a constraint whose source is the humanoid head or an eye bone is driving that bone's visible counterpart, and both markers are measured there instead.
This only fires when your avatar relays both humanoid EYE bones, and that requirement is doing real work. A taur base kept tripping earlier versions: its constraint sourced from the humanoid head drives a hip clone, because that's its head-puppet feature — the head as an input that swings the body, not a bone being reproduced somewhere visible. The result was a viewpoint placed at the avatar's hips. Nothing about the rig separated the two cases (that base has a genuine stand-in skeleton too), and nor did distance — the dragon's real head sits 0.46 m from its humanoid head, the taur's hip clone 0.50 m. Relayed eyes do: an eye bone exists to aim eyeballs, so a constraint driven from one is reproducing a face, and a puppet input never has them.
A decoy rig that maps no eye bones therefore keeps the author's own viewpoint. An unhelpful viewpoint beats one confidently placed at your hips.
It still can't be perfect, because the markers ride the humanoid Head bone whatever happens — so check them with the gizmo and drag either one if you want it elsewhere.
Three older causes, all fixed
- A viewpoint above the eyes. The author's VRChat viewpoint is preferred over the CCK's Auto placement, and it's overridden only when the rig itself proves it wrong. That check measured against the hips — and hips get mis-mapped as readily as jaws: one avatar pointed them at the armature root on the floor, which stretched the tolerance to 0.89 m and would have accepted a viewpoint anywhere in its upper half. Its authored value sat 10 cm above the eye bones, on the brow. A viewpoint is now also rejected when it sits above the eye midpoint by more than the avatar's own interpupillary distance — a yardstick that comes from the two bones being compared, so no other slot has to be mapped correctly, and that scales with the avatar (about 6 cm on a human, far outside where anyone places a viewpoint deliberately). Below the eyes is deliberately left alone: down a muzzle or inside a helmet is a real choice.
- A "jaw" bone that isn't a jaw. The humanoid Jaw slot is optional and nothing
validates it, so riggers fill it with whatever was nearest — one avatar mapped it to a bone called
fronthair1, 21 cm above the head bone and a centimetre above the viewpoint, and the voice duly came out of the top of its head. A mapped Jaw is now checked before it's believed: it must sit below the eyes (a jaw hinges under them — the head bone is a bad reference, since a jaw is legitimately level with the base of the skull) and within a quarter of the rig's own hips-to-head span of the head bone. Failing either, the jaw is ignored and the voice is measured from an open-mouth viseme instead — the vertices that shape moves are the mouth — falling back to the head bone only if there's no viseme either. The rejected bone is named in the report and flagged inDiagnostics.md. Nothing is retargeted — that would move geometry — so fix it in the model's Rig tab if you want jaw-flap animation as well. A bone's local axes are whatever the rigger chose — on one robot avatar the head bone's forward pointed at the sky, so "6 cm in front of the head" placed the voice 6 cm above the eyes. Offsets use the avatar root's orientation now, the one transform whose forward is really forward. - Scaled bones. With no jaw bone the voice position sits a few centimetres in front of the head, and that offset used to be applied through the head bone's own transform — which multiplies it by the bone's scale. Rigs derived from Second Life routinely carry ~100× bone scales, turning a 6 cm nudge into 6 m. The offset is sized from the avatar's own hips-to-head span and applied by rotation only now, so bone scale can't reach it. The viewpoint was never affected: it's a midpoint between two eye-bone positions, with no offset to inflate.
- Scaled parents. ChilloutVR stores both positions as an offset carrying the avatar's
own
localScale— what the CCK's inspector reads and writes. Earlier conversions used the avatar's world scale, identical until the avatar sits under a parent with a scale on it, at which point they diverge by the parent's factor.
Whatever the cause, the CVRAvatar inspector's own Auto buttons place both exactly where the conversion aims to, so they're always a safe manual fix.
If the report says "animated material property(ies) don't exist on the shader they target", this is it, and it is not the conversion: the same animation does nothing in VRChat either.
Two report lines cover the other version of this — a clip whose curves address objects that aren't on the avatar — and they are split apart, because they mean opposite things:
- "animate paths that were ALREADY missing in VRChat" is not a problem. Every dead path is now checked against the avatar as it arrived, and these weren't there either — so the curves were silent in VRChat exactly as they will be here, and nothing was lost. Usually the clip belongs to a feature that variant isn't configured for. It used to be reported as a warning, which made healthy conversions look alarming: one quadruped base tripped it 44 times, all harmless.
- "LOST paths that existed before conversion" is the real one. Those objects were on the avatar when it arrived and aren't now, so the feature worked in VRChat and won't here. A stripped system (GoGo, SPS) taking objects a clip still references is the usual innocent cause — turn that strip off and convert again to check. Anything else is worth reporting as a bug.
Clips that switch a constraint on and off get the same treatment, because the same three outcomes mean three different things:
- "repointed at the Unity constraints" — working. The type and property names change during
conversion, and these followed. Some also had to follow their constraint to a different object,
because a VRC constraint using
Target Transformis rebuilt on the thing it drives. - "drove a constraint that was never built" — check your bake, not the conversion. The object is on the avatar but has no constraint and never did, so there was nothing to convert. VRCFury and Modular Avatar generate constraints during the bake, and a bake that errors partway generates some sets and not others — one quadruped had its ear, tongue, wrist and toe constraints built and its finger set missing, leaving 140 curves addressing things that never existed. Build a test copy of the source avatar on its own and confirm it completes without errors.
- "drove a constraint on an object that is now GONE" — the object itself vanished during conversion. A stripped system is the innocent cause; anything else is a bug worth reporting.
Locked (optimised) Poiyomi/Thry shaders bake any property that wasn't flagged animated at lock
time into the shader as a fixed value and delete the property. Writing to it afterwards goes
nowhere. Flagging it later sets _<Name>Animated on the material, but that changes nothing until
the material is unlocked and locked again — so a material can claim a property is animated while
its shader genuinely has no such property.
Fix it in Poiyomi's own material inspector, and only there: unlock the material, right-click the property, mark it animated, then lock again. Flags are per material, so if only some of the avatar's materials carry one, only those respond.
It has to be Poiyomi's UI because marking a property animated also enables the shader section it belongs to. Poiyomi is modular: a disabled section is compiled out of the locked shader completely, and no flag on a property inside it will bring it back. AvatarBridge briefly shipped a command that automated the unlock/flag/re-lock, and it was withdrawn in 2.83.0 for exactly this — it set the flags correctly and the properties still didn't appear, because their sections were off, while the rebuild changed how the avatar looked. Only Poiyomi knows which section each property needs.
Some of them will never work again, and the report says which. It splits the list in two:
| the report says | what it means |
|---|---|
| Worth fixing | Nothing has flagged the property yet. Unlock → mark animated → lock, then convert again. |
| Probably not fixable | The material already carries the animated flag and the property still isn't in the shader. Someone has done that fix and it didn't take — the section is off, or the animation predates the installed Poiyomi. Re-locking again changes nothing. |
The second group is worth knowing about before you spend an evening on it. Those controls are removed from the converted avatar by default rather than shipped as menu entries that do nothing.
Everything upstream looks healthy while this is happening, which is what makes it expensive — the parameter syncs, the layer sits at weight 1, the clip plays, and both the CCK Debugger and the tester's own Animator layers readout confirm it. The report names the property and the renderer so you don't have to work back from the animator.
Reconvert on a current release.
VRChat's usual toggle is two animator states: one holding the clip that changes something, and one holding nothing at all, whose job is to put it back. That empty state works because VRChat's Write Defaults writes each property's captured default — the off direction is an implicit rule rather than animation. Converted, there is nothing in the off state to undo the change, so the toggle switches on and stays on. Every toggle on such an avatar behaves the same way, because they're all built the same way.
Conversions now give that off state a real animation. If your avatar already has a clip that does the job it uses yours — the "on" half of a pair that was simply never wired into the empty state. Only when there's nothing suitable is one generated, by measuring the property off your avatar: whatever it is at conversion time — the object active, the blendshape at rest, the material as authored — becomes an explicit curve. Either way the toggle restores by animating, which behaves the same on any platform. The report says which layers reused an existing clip and which got a new one.
Three things worth knowing:
-
Whatever is true at conversion time is what "off" now means. If a toggle should rest in its other position, set the avatar up that way before converting.
-
Where several layers animate one thing, only the lowest restores it. A dress toggle and a shirt toggle that both move the shirt is the usual case: if the dress layer restored the shirt it would assert it from above and the shirt could never come off; if neither did, it could never go back on. The lower layer owns it, the higher stays silent, and both toggles work. The report counts what was left to a lower layer.
-
Only two-state toggles are filled. VRChat's idiom is exactly one empty "off" state and one state holding the clip, and that shape is the only one where a snapshot of your avatar belongs in the empty half. Bigger layers are machines whose empty states are structural — a chest slider's
Reset/Pause, a local/remote gate — and filling those changes how the avatar looks: one snapshot pinned seven chest blendshapes to zero and flattened the model the moment the layer rested there. Those layers are now left exactly as VRChat had them, and the report names each one. -
Not every empty state is an off state. Some exist to choose — the local/remote gate VRChat avatars put at the top of a layer, whose transitions split on
IsLocalso the wearer's controls drive one branch and a synced dropdown drives the other. The layer only passes through it, so handing it values makes it hold them for as long as it sits there — and if the gate's condition never resolves, forever. Those are now recognised by their transitions covering every value of a parameter, and left empty. The report counts them.Before this rule a hat-grab layer's gate was given the "hat on the head" animation, which asserted the hat visible from above its own toggle.
Reconvert on 3.5.8 or later — enabling "Base / locomotion" can no longer cause this.
Merged into one ChilloutVR controller, a [Base] layer lands above the client's own
Locomotion/Emotes layer on Override at full weight. From there it can't add to CVR's locomotion,
only replace it — and CVR's layer is where the movement sliders and every stance button are answered,
so letting it through costs you all of them. One avatar's [Base] layer turned out to be a
calibration utility (states literally named measure me, Preview, reinitialize); unmasked at
weight 1 it simply held the body still.
[Base] layers are now masked off the humanoid rig, exactly like merged FX layers. Everything else
in them still converts — object toggles, blendshapes, materials, parameters, additive motion — and
CVR's locomotion stays authoritative.
And the animations themselves survive: custom walking, crouching, crawling, falling and
sitting clips are grafted into ChilloutVR's own locomotion layer, matched by their position in
the movement blend trees — a clip at the forward-run position lands at CVR's forward-run position,
whatever it's named. The structure stays ChilloutVR's, so movement and stances always answer; the
art becomes the avatar's. Each grafted movement cycle's loop setting is matched to the slot it
fills (a cycle authored without looping would otherwise play once and freeze), while jump and
fall grafts play once, as their exit-time transitions always said. A flight pose lands on
CVR's LocFlying state: ChilloutVR flies natively, so a VRChat copter or flight system needs
none of its speed machinery here, just its pose where the client will show it — and that pose is
scored, not name-matched: a state you can sit in, judged by looping clip and idle/hover naming
rather than by the first name containing "fly". Pose-style stance states (single-clip
Standing/Crouching/Lying) are left alone: they are VR tracking poses, and one seated as a desktop
crouch idle sinks the wearer into the floor.
One discovery made all of this precise: most VRChat avatars don't ship walking animations at
all — their trees reference proxy_* placeholder clips that the VRChat client replaces at
runtime. The real walk was never in the avatar, so there's nothing to carry; ChilloutVR's own
animation set is this platform's version of those placeholders, and the report says which of the
two cases your avatar is.
Genuine locomotion replacements can't be rescued this way, and it's worth knowing why: they lean on runtime layer-weight control, which ChilloutVR has no equivalent for, so they don't run here whether masked or not. Nothing is lost by blocking them. If you want one driving your body anyway, clear its Mask in the Animator window — and expect the stances to stop responding.
Reconvert on 3.5.8 or later. Unity's AnyState transitions default to "Can Transition To Self", which with ordinary conditions means the destination state re-enters every frame the conditions hold, restarting its animation each time. Nearly every avatar carries dozens of these and VRChat never shows it, because the states involved are mostly empty there — restarting nothing looks like nothing. Conversion has to fill empty states (they crash Unity's graph builder), and a filled state restarted every frame strobes its clip.
The "only other people see it" shape is the same mechanism plus networking: remote copies of your
avatar hold every # local parameter at its default forever (local parameters never sync, and
parameter streams are stripped from remote copies), so a re-entry condition your live values keep
false can sit permanently true on everyone else's client. The conversion now disables the self
re-entry flag on merged AnyState transitions — but only where the restart carries no meaning.
A state with a real animated clip keeps the flag and the pinned-at-first-frame
look its author shipped with. A state with an exit-time transition out keeps it too, because
there the restart is load-bearing: every re-entry resets the clock so the timed exit never fires —
that is the entire mechanism holding the state, and one avatar's every clothing toggle was built
exactly this way (AnyState-with-self in, exit-time out); clearing the flag set them all cycling
on/off at clip length. Transitions conditioned on a Trigger always keep the flag, as firing once
per pulse is the intended use. What still loses the flag is the case the fix exists for: a
still-holding state with no timed exit, restarted every frame — the filler-filled gate states that
strobed for remote viewers. The Remote view card in the CCK Animator Tester reproduces the remote valuation
locally if you want to verify an avatar before uploading.
Root motion is also stripped from animations that travel: VRChat flight and vehicle systems move the player by animating the body, because VRChat allows nothing else. ChilloutVR moves the player itself and hangs the first-person camera on the head bone — the same baked movement here shoves the wearer around with no input, so it is removed. The test is whether the clip's root ends where it started: a backflip's flip is root rotation and a dance sways the whole body, both returning home, and those keep their curves — stripping them broke the animations while removing nothing a player could feel. A clip that ends displaced is a mover, and looped, a vehicle; those have each root curve flattened to its starting value — held, never deleted, because the same curve carries the body's baseline height and deleting it sank the wearer waist-deep into the floor. Locomotion-tree grafts are always flattened — there the capsule owns every metre.
Reconvert on 3.5.5 or later. Emotes live in menus that hold their value, and VRChat's Action graph is built for that: after a play-once emote it parks in a state whose only way back requires the value to return to zero, so an emote fires on the rise of its condition, once. The converted pose states are re-armed from the locomotion resting state instead — and arming on a level replays the emote every time the pose hands back, forever, as long as the menu holds the value. Conversion reproduces the rise-only behaviour: a local ready flag gates every arming transition, dropped the moment a pose is armed and raised again when its conditions have gone false or the armed value has changed — so switching straight from one emote to the next plays the new one, no trip through None required, and re-selecting an emote replays it. Hold-style emotes (dances, AFK poses) are unaffected; they loop until deselected, as their own exit conditions have always said.
Check the report for that control's name. Three known causes, all fixed, all worth naming if you still hit them: a prefab whose constraints drive your bones from proxy objects (see above); a slider whose neutral is 0.5 being declared 0; or a feature living in the Action layer.
That last one is worth understanding, because it looks exactly like a dead parameter. VRChat's Action layer is its emote player: VRChat keeps it at weight 0 and raises it only while an emote runs, so its waiting state can hold a full-body clip and harm nothing. ChilloutVR has no playable layers to raise it, so conversions rest it at 0 too — otherwise that waiting state asserts a stand-still pose over your locomotion and you walk on the spot.
Some avatars put a feature there anyway. One transforming robot kept its entire vehicle mode in an
Action layer gated on its own CarMode/TransformMode parameters: every parameter converted, the
menu toggled them correctly, and nothing happened, because the layer holding the animation could
never reach any weight.
An Action layer whose transitions wait on the avatar's own parameters — anything outside VRChat's
VRCEmote/AFK/state built-ins — is now merged at weight 1, with its waiting state emptied and
Write Defaults turned off so it contributes nothing until something drives it. That's the same net
effect as VRChat's weight 0, and then it animates at full weight. VRChat fades that weight in over
about half a second and ChilloutVR can't, so expect the change to snap rather than ease.
The feature stays disarmed until one of its own parameters actually changes, and this matters more than it sounds. VRChat's Action layer is silent at weight 0, so the conditions inside it are free to be permanently true — plenty are. Copied into ChilloutVR's always-on locomotion layer, a condition like that would fire the moment the avatar loaded: two inflation rigs did exactly that, one flickering between its pose and idle forever, the other walking up its stages at load and parking in a pose its owner never chose. The arming now snapshots the values the avatar woke up with and only engages once one of them moves, so the feature waits for you rather than for the avatar to exist.
The full-body poses move into ChilloutVR's own locomotion layer — the one place on this platform a pose can both assert and let go. VRChat raises the Action playable's weight at runtime while a sequence plays; ChilloutVR has no runtime weight control, and a separate layer has no way to yield — inert states with Write Defaults off hold the last written muscles (the avatar freezes mid-pose; observed directly), Write Defaults on asserts rest pose over locomotion. Five versions of state surgery hit that wall. Inside the locomotion layer it doesn't exist: when the pose states aren't active, locomotion's own states are, still writing muscles every frame — handing back is yielding.
What moves is the live window — the states between the behaviour that raises the Action weight and the one that fades it, read from VRChat's own behaviours before they're stripped; exactly the states VRChat ever showed. The avatar's arming conditions (parameters, gestures) carry over as the entry conditions, and the original layer stays merged at weight 0 so its parameter drivers keep firing on schedule. Not carried over: VRChat's tracking control (IK cut-off during sequences) and its half-second weight fades — entering and leaving the pose blends over a fixed quarter second. When no live window can be identified, the layer stays at weight 0 and the report says exactly what that costs.
Reconvert on a current release. ChilloutVR syncs straight from the animator, so a synced parameter with no menu
control still needs somewhere to live — conversions create one. That guess is wrong when the avatar
writes the parameter itself from a parameter driver: the new control then sits in your menu fighting
the animator, right next to the control that really works. One transforming avatar shipped a Car Mode
entry (the author's, driving TransformMode) directly above a CarMode one (ours, driving what the
Action layer sets for itself).
Invented controls are now withdrawn once the merged animator shows a driver writing that parameter. Only controls this tool added are eligible — anything the author put in the menu stays. The parameter is untouched and still syncs.
Reconvert on a current release. An avatar that blinks from its own animator (VRCFury and
similar, usually driving vrc.Blink) can't keep that system through conversion: its "eyes open"
states are empty in VRChat, relying on Write Defaults to reopen the lids, and empty states can't
survive conversion — they crash Unity's graph builder and get a filler clip, at which point the
first blink closes the eyes for good. It can't share the eyes with the native blink either — two
systems, one pair of eyelids.
The animator blink system only exists because VRChat has no built-in blink. ChilloutVR does. So the conversion finds the animator layer whose only job is blinking — every curve a blendshape, the only shape it ever raises matches "blink", no objects, no materials — lets that layer name the shape, removes it, wires ChilloutVR's native Eye Blink, and zeroes the shape's live weight in case the old system left the eyes mid-blink. If no layer can be safely identified, nothing is removed, native blink stays off, and the report says so.
One subtlety: ChilloutVR writes its blink weight onto the mesh every frame, after the animator
— whatever shape it's given, the client owns outright, and an expression animating the same shape
would silently stop closing the eyes. If the removed layer's shape is also used by surviving
expression clips, the native blink is moved to a free shape family instead — a Blink L /
Blink R pair or a spare combined shape nothing animates — so the blink and the expressions both
work. If no free shape exists, the blink keeps the contested shape and the report warns which
expressions lose.
Expected, and not caused by converting — see shaders that only draw into one eye.
The VRChat Avatars SDK isn't installed. Without it a VRChat avatar's components can't be read at all, so only Setup mode is offered.
Not AvatarBridge — that's the CCK. ChilloutVR's API refused to allocate a content slot, usually
because of the account's private upload limit. The real message is in Player.log or the Unity
console just above the exception.
Normal. That's AvatarBridge registering its scripting defines.
Hit Report an issue in the AvatarBridge window — it opens a pre-filled GitHub issue with your versions and detected packages already in it.
Two things make a report solvable immediately:
-
Attach
ConversionReport.mdandDiagnostics.mdfromAssets/AvatarBridgeOutput/<avatar>/. Nearly every bug fixed so far was diagnosed from the report;Diagnostics.mdcarries the measurements behind it — package versions, every setting used, the rig's shape, where the head and eye bones actually sit against the viewpoint, the constraint census, and which asset references resolve to nothing. It's all facts and no advice, so it diffs cleanly between two conversions. Nothing in either file leaves your machine unless you send it. -
Attach the right log:
Symptom Log Conversion errors, or wrong result in Unity Unity console text or Editor.logAvatar misbehaves or won't load in ChilloutVR %USERPROFILE%\AppData\LocalLow\ChilloutVR\ChilloutVR\Player.logA clean Unity log says nothing about an in-game failure — that's exactly how the "Error robot" bug was found.
Please re-run on the latest release first. Logs contain your project's file paths (and CVR logs your display name) — skim and redact if you'd rather not post them.
Quick questions can go to mrtactical on Discord. Anything reproducible is better as a
GitHub issue — those get tracked, linked to a fix and closed with a release.
- Gesture tables, CVR core parameters and several conversion patterns were studied from vrc3cvr (MIT), maintained by Narazaka, and from the original by imagitama (MIT, archived 2023) it forks. AvatarBridge is MIT too, deliberately: anything here that's useful to vrc3cvr is theirs to take.
- Gesture mapping and the Parameter Stream approach follow the official ChilloutVR references.
- The DynamicBone gravity split mirrors PhysBone-to-DynamicBone.
- MagicaCloth2 usage follows the official runtime construction docs; chain presets are MagicaCloth2's own.
- VRCFury avatars are baked by VRCFury's own builder — no Fury code is bundled and there's no hard dependency.
- The CVR VRCFT face-tracking rig is DragonSkyRunner's
CVR Eye & Face Tracking,
bundled under
Assets/AvatarBridge/FaceTrackingand redistributed with the author's permission. All rights remain theirs; if you reuse it, credit them. (Their upstream repo carries no explicit license file — aLICENSEthere would make the redistribution terms unambiguous.) - GrabbyBones is an optional third-party mod AvatarBridge targets but does not bundle.
- The avatar scaler's constant-speed smoothing is built on JustSleightly's Controller Templates; those clips are bundled under fresh GUIDs to avoid clashing with the original package. Credit for the technique remains theirs.
MIT — see LICENSE.md.