Button Inventory

Button Inventory is a button panel you can add to your avatar for enabling and disabling game objects by finger touch.

This package uses stop action animation, a technique for animating on particle death, invented for VRChat by RetroGEO. Cibbi's broken subemitter script is used to simplify the workflow.

The Button Inventory prefab has an animator component, a Pointer, a Menu, and state objects.

The Pointer is a fixed joint with an animator component and particle systems inside. The animator manages the lifecycle of the particles.

The Menu is a fixed joint with several animators, cube meshes, and colliders inside. The animators control whether the menu is open or closed, the cube meshes are to represent the button locations, and the colliders are set to kill the particles inside the Pointer.

When a particle system in the Pointer dies to a button collider of the Menu, it will send a signal with particle death subemission to a corresponding state object particle system.

A state object is a system of animators and particles which respond to subemission to enable or disable a child object, called "Set". Your objects are meant to be nested inside the Set object.

Download Button Inventory


Click to expand

Import the button inventory package

Enter the folder located at Assets/lindesu/Button Inventory

Place the Button Inventory.prefab in your scene hierarchy, at the base of your avatar.

Installing prefab

Setting up the Pointer

Click to expand

Open your avatar's armature, and find the ending bone of the finger you want to use for touching.

Select finger bone

Open the Button Inventory object, and move the pointer_rigidbody object so it is a child of your selected finger's ending bone. The prefab will break and that's okay.

Moving pointer_rigidbody

After moving the pointer_rigidbody in the hierarchy, reset the transforms of pointer_rigidbody.

Reset pointer_rigidbody transforms

We now need to get the transforms of your finger, which can be done in a few steps.

Move the pointer_rigidbody back into the Button Inventory and copy the transforms.

Copy finger transforms

Use the ctrl-z shortcut(Undo) to revert pointer_rigidbody to it's place in your armature.

Undo moving pointer_rigidbody

Select the Pointer object and paste the copied transforms.

Paste transforms on Pointer

Reset the scale of Pointer.

Reset Pointer scale

Setting up the Menu

Click to expand Find a bone in the armature that the menu should follow. In this guide, I am using my Left wrist bone.

Select menu bone

Move the menu_rigidbody object so it is a child of your selected bone.

Moving menu_rigidbody

Reset the transforms of menu_rigidbody.

Reset menu_rigidbody transforms

Set the position and rotation transforms of the Menu object so the buttons appear where you need them.

Positioning Menu

Rotating Menu

Adding objects to the inventory

Click to expand Open up the hierarchy of a state object. Place your game objects under the Set object.

Opening state object

If you need to, you can the state object to be a child of any object. In this case, the appropriate object is under my right wrist bone, in the armature. (optional: reset the transforms of the state object after moving it so you have predictable offsets)

Moving state object

To check the appearance of your objects, you can enter play mode and enable Set. I recommend using play mode because it is possible to mess up the default configuration of the state object hierarchy.

Play mode test

Gesture overrides

Click to expand When Fingerpoint and Handopen are used together in game, after .5 seconds, the inventory will be unhidden. The inventory will remain open as long as Handopen is being held. Fingerpoint can be released at any time. You can only press a button while using Fingerpoint. The animation files for Fingerpoint and Handopen are located at Assets/lindesu/Button Inventory. Install them to the corresponding slots in your override controller.

Installing overrides

Duplicating state objects

Click to expand This is optional and not necessary for every install.

Sometimes you need to enable more than one Set object at the same time, and in different places in the hierarchy. To do this, you can duplicate a state object(ctrl+D) and move it to another location in the hierarchy. You then attach the new duplicate state to the Pointer particles.

(As a tip, pay attention to your transforms since you will be copying an object and moving it around in the scene. Just make sure your object shows up where you need it. Remember to test the appearance of your objects in play mode.)

Duplicating a state object

You now should use Cibbi's broken subemitter setup script to pair the new duplicate state to the Pointer particles.

Locate the script under tools > Cibbi tools. Enable BrokenSubEmitterSetup.


Open up the Pointer, find the particle which corresponds to your state, and set it as the main particle.

Set main particle

Select the stop_action_particle object of your duplicate state, and then hit the apply button. This attaches the death of the enable_particle to produce the enable of Set.

Apply the enable

In the Pointer, set enable_particle_reset as the main particle, and apply the duplicate's Set object. This attaches the death of the enable_particle_reset to produce the disable of Set.

Apply the disable

You can check your work by selecting an enable_particle and looking at what it subemits.

Checking subemission

Changing enable_particle behavior

Click to expand This is optional and not necessary for every install.

You can reverse the behavior of the enable_particle, and the enable_particle_reset, so that the enable_particle disables it's corresponding state, and the enable_particle_reset enables it. This is so that if you have a state enabled by default, you can use a particular button to disable it, and the reset button will return it back to default on.

Enable the Set object so it's on by default.

Clear out the subemitters of the enable_particle. Use BrokenSubEmitterSetup(tools > Cibbi tools) to have the enable_particle subemit Set(the disable).

Clear out the subemitters of the enable_particle_reset. Use BrokenSubEmitterSetup to have the enable_particle_reset to subemit all of the Set objects, except for the one that corresponds to your default on state.

Use BrokenSubEmitterSetup to have enable_reset_particle subemit the stop_action_particle(the enable) of your default on state.

You can also have the enable of one state disable another state, if you are trying to make the states exclusive to eachother, but you have to be careful in one aspect. You should not have more than one enable_particle, which includes the enable_particle_reset, subemit the same thing. If enable_particle_0 subemits the Set of state 1(enabling state 0 disables state 1), the enable_particle_reset, or any other enable_particle, should NOT subemit that same Set. If more than one enable particle subemits the same thing, you will get a flood of log errors that will lag you in game and fill your logs with gigabytes of data. This is covered more in the "What you shouldn't do" section.

To work around this, we can add a child object to the hierarchy of Set, which can be used as a disable, and have the enable_particle subemit that instead. That way, the enable_particles do not have to share any subemitters.

Duplicate(ctrl+D) the Set object of the state you wish to have a secondary disable mechanism.

Edit the animation of enable_set to include the duplicate.

Have the enable_particle subemit this duplicate Set object.

If you need an enable_particle to enable more than one state at the same time, they should be part of the same state, and you can follow the directions in the "Duplicating state objects" section.

Removing extra states

Click to expand This is optional and not necessary for every install.

Customizing menu appearance

Click to expand This is optional and not necessary for every install.

Making a custom and visually interactive menu can be advanced, with too many options to cover in this guide. This section will cover simple changes.

The buttons in the Menu are just cube meshes with colliders as children. If you want to do custom effects for the button panel, you can search for "button" in your hierarchy, multi-select the buttons, and disable the mesh renderer. The button colliders will still be active, and you can render something separate to represent the button locations. You can also scale the buttons to resize the colliders nested inside.

What you shouldn't do

Click to expand


Visit my discord and ask questions if you are confused or trying to do something not covered by this guide.

Thank you!