Examples
Example: Sample Companion Pack
A data-only pack — a motion set with a tail wag, an avatar model, and two ready-made characters.
Example plugin · 1 motion set · 1 model · 2 characters · no code, no permissions
This pack ships everything companion mode can take from a plugin, with no index.ts at all: nothing runs in the
sandbox, and the Browse page shows no permissions and nothing it can reach.
Layout
readme.md
companion-motions/sample-moves/
motions.json
idle-neutral.vrma talk-idle.vrma listen.vrma think.vrma wave.vrma laugh.vrma
tail-wag.glb
companion-models/sample-seed/
model.json seed-san.vrm thumbnail.png
companion-characters/sample-seed-character/character.json
companion-characters/sample-belle-character/character.json
Four keys — sample-moves, sample-seed, sample-seed-character, sample-belle-character — all different,
because keys are unique across the whole package (a character can't share its model's key). The readme uses
version: 1.1.
The motion set
motions.json gives every base role one body clip, plus one gesture and one reaction, plus an extra-parts
gesture:
| Clip | Role | Format | Notes |
|---|---|---|---|
idle |
idle |
VRMA | required — every set needs at least one idle |
talk-idle |
talkIdle |
VRMA | the loop while speaking |
listen |
listen |
VRMA | a nod while the user talks |
think |
think |
VRMA | hand to chin while the agent works |
wave |
gesture |
VRMA | cues: ["happy", "excited"], strokeSeconds: 0.6 |
laugh |
reaction |
VRMA | cues: ["laughing", "chuckling"] — plays on a [laughing] line |
tail-wag |
partsGesture |
GLB | clip: "Tail_Wag" — a tail-only animation |
{
"key": "tail-wag",
"file": "tail-wag.glb",
"clip": "Tail_Wag",
"role": "partsGesture",
"name": "Tail wag",
"description": "Wags her tail — happy."
}
What this shows:
- VRMA clips need nothing else — no
clip, norig; they always drive the humanoid body. - The tail wag is a plain GLB with only tail bones. It needs
clip(the animation's name inside the file) but norig, because it moves named extra bones, not the body. At publish the server reads which bones it animates; at play time it's only offered to avatars that actually have those bones. cuesandstrokeSecondslet the companion land the wave on a happy sentence at the right beat.
The model
{
"name": "Sample Seed-san",
"description": "A copy of the built-in Seed-san model, offered as a plugin companion model for testing.",
"avatar": "seed-san.vrm",
"thumbnail": "thumbnail.png",
"defaultMotions": { "key": "sample-moves" }
}
A VRM avatar with its own thumbnail, defaulting to the pack's own motion set by key. When a user builds a
companion on it, the avatar is copied into their account — it survives an uninstall.
Two characters, two patterns
Sample Seed — everything from the pack:
{
"name": "Sample Seed",
"vibe": "A test character with a plugin look and plugin motions.",
"model": { "key": "sample-seed" },
"motions": { "key": "sample-moves" },
"soul": "You are Sample Seed, a cheerful test companion. You keep answers short and friendly.",
"instructions": "You talk with the person out loud. Keep replies to a sentence or two and avoid lists.",
"voice": {
"description": "A bright, friendly young voice.",
"suggestions": [
{ "provider": "fish-audio", "voiceId": "8ef4a238714b45718ce04243307c57a7", "voiceName": "Sample voice" },
{ "provider": "elevenlabs", "voiceId": "21m00Tcm4TlvDq8ikWAM", "voiceName": "Rachel", "model": "eleven_v3" }
]
}
}
Sample Belle — built-in look and motions, only a new personality and voice:
{
"name": "Sample Belle",
"vibe": "A test character on the built-in Belle look, with a voice only Deepgram offers.",
"model": { "builtIn": "belle" },
"motions": { "builtIn": "neutral-professional" },
"soul": "You are Sample Belle, a calm and precise test companion who keeps people on track.",
"instructions": "You talk with the person out loud. Be brief and clear.",
"voice": {
"description": "A calm, clear woman's voice.",
"suggestions": [
{ "provider": "deepgram", "voiceId": "aura-2-thalia-en", "voiceName": "Thalia" }
]
}
}
- Voice suggestions are ordered. Sample Seed's companion uses fish.audio if the account has it, else ElevenLabs. An account with neither gets captions only, with a notice offering to add a voice provider — which is exactly what Sample Belle shows on an account without Deepgram.
- A character is a look + motions + suggested agent. In the Companions gallery (tagged Plugin · Sample Companion Pack), Talk creates a new agent with the suggested soul and instructions; Talk as… adds the face to an existing agent.
- The instructions are written for speech — short, no lists — because a companion's replies are spoken.
Publishing it
A pack with binary files is published as a zip (Publish from a .zip file instead, or
POST /plugins/{id}/versions/zip). Every binary must be referenced by one of the JSON files, or the publish is
refused naming it.
The fastest way to build your own: create a motion set in Companions → Motions and use Export as plugin package — it writes this layout for you, with bone names already correct. See Companion packs.