• Hi Guest!

    We are extremely excited to announce the release of our first Beta for VaM2, the next generation of Virt-A-Mate which is currently in development.
    To participate in the Beta, a subscription to the Entertainer or Creator Tier is required. Once subscribed, download instructions can be found here.

    Click here for information and guides regarding the VaM2 beta. Join our Discord server for more announcements and community discussion about VaM2.
ExpressionRouter

Plugins + Scripts ExpressionRouter

Download [0.09 MB]

VamEssentials

Well-known member
Joined
Sep 8, 2023
Messages
224
Reactions
1,588
VamEssentials submitted a new resource:

ExpressionRouter - Create, Organize, and Animate Facial Expressions with Real Time Blending & Randomization Options

🧠 ExpressionRouter — Advanced Facial Expression Control for Virt-a-Mate

ExpressionRouter is a powerful plugin for Virt-a-Mate that lets you create, animate, and organize facial expressions with precision and control.
Built on a flexible multi-tab system, it supports real-time blending, smooth transitions, randomization, and preset loading — all with deep per-layer customization.

---

🌟 Key Features
Per-Tab Random Playback + Global Random...

Read more about this resource...
 
I see one big problem with all those plugins. Usage becomes so problematic and there's so many parameters that nobody actually use it... There should be some easy modes.
 
all my goat plugin devs are working on a feature that i need??? this must be fate. can't wait to try.
 
I see one big problem with all those plugins. Usage becomes so problematic and there's so many parameters that nobody actually use it... There should be some easy modes.

Start with 1 Morph
The main thing to know is on Tab 1 Group 1 box, you can add just 1 morph, start with something simple like a smile then check active. You will see results right away as it moves your morph slider from 0 to .70. Intensity Min and Max are just like the sliders on the morph tab, when you slide a smile from 0 to .70 or to 1 for example. I set a really wide range on the sliders of -1 to 2 because there are some morphs that go that far in range. But you can mostly stick with default settings until you see how it works. Time is how fast it does it and blending will be more for transitions. You really don't want to go below .70 in speed in most situations because it's based on seconds and becomes way too fast and jittery. But there may be some instances where it may work. I didn't set a hard limit on anything in case someone found a use for it, but just start with default settings for testing.

Try 2 Morphs
The main thing to know, is it's not recommended to have the same exact morph in Group 1 and Group 2 or you could have some jitteryness, unless you have a larger group in each. But you could do something on the tongue tab like Tongue Length in Group 1 to have the tongue stick out, and Tongue Curl in Group 2, and the tongue will stick out and curl for example.

Add More Layers/Tabs
Once you see you can use just one morph per tab just in Group 1 (smile), or have 2 per tab with 1 in Group 1 and 1 in Group 2 (tongue sticking out and curling), or have a large mix rotating, you can setup a combination that works and just keep adjusting/adding layers.

One thing you could do is add VamEssentials Orgasm Morphs to a tab. I put all open on Group 1 (25 count), and all closed and rolled on group 2 (50 count)...

Then on the Tongue tab add all the Tongue morphs you have, except Tongue Length, and you now have idle tongue movement. On the lips tab for a female model, try adding "CurvyLips" morph for more natural lip flexing. You can also have the brows and nose flex, or add your own slow relaxed blink idle animation. It just depends on how far you want to go with it.

The concept on how it works is none of these morphs are loaded in until you check active. So every time it Reset/Stops it's just going back to your starting morphs or neutral morph position as if they were never applied and clears them out essentially.

Presets
If you get a combination you like, you can save it as a Preset per tab or save the entire collection of tabs as a Mood.

Triggers
These presets can then be triggered via buttons or Timeline with LoadPresetFromPath or LoadMoodFromPath. Or you can toggle specific tabs on and off with triggers that effect the Active button to Send True [x] checked or [ ] unchecked for off.

Random
Checking Random cycles through tab 1-10 that have morphs. If you only use 3 tabs, it skips blank tabs with no morphs and will just randomly switch between your tabs with morphs on tabs 1-10. The rest of the tabs to the right of 10 are not a part of the Random group. They have to be manually turned on or off or essentially function like an always on or on when you want them tabs. So you can have some randomness with some consistent movement whenever you need it. It just gives another layer/combination. The best way I think to test Random is to add a bunch of morphs on the Tongue tab, excluding Tongue Length at first, and turn it on. Like Tongue Roll/Raise/etc. You will then have idle tongue movement during all your expressions and your model will look more alive/realistic. Or add lip curving so the lips occasionally flex some.
 
Last edited:
Start with 1 Morph
The main thing to know is on Tab 1 Group 1 box, you can add just 1 morph, start with something simple like a smile then check active. You will see results right away as it moves your morph slider from 0 to .70. Intensity Min and Max are just like the sliders on the morph tab, when you slide a smile from 0 to .70 or to 1 for example. I set a really wide range on the sliders of -1 to 2 because there are some morphs that go that far in range. But you can mostly stick with default settings until you see how it works. Time is how fast it does it and blending will be more for transitions. You really don't want to go below .70 in speed in most situations because it's based on seconds and becomes way too fast and jittery. But there may be some instances where it may work. I didn't set a hard limit on anything in case someone found a use for it, but just start with default settings for testing.

Try 2 Morphs
The main thing to know, is it's not recommended to have the same exact morph in Group 1 and Group 2 or you could have some jitteryness, unless you have a larger group in each. But you could do something on the tongue tab like Tongue Length in Group 1 to have the tongue stick out, and Tongue Curl in Group 2, and the tongue will stick out and curl for example.

Add More Layers/Tabs
Once you see you can use just one morph per tab just in Group 1 (smile), or have 2 per tab with 1 in Group 1 and 1 in Group 2 (tongue sticking out and curling), or have a large mix rotating, you can setup a combination that works and just keep adjusting/adding layers.

One thing you could do is add VamEssentials Orgasm Morphs to a tab. I put all open on Group 1 (25 count), and all closed and rolled on group 2 (50 count)...

Then on the Tongue tab add all the Tongue morphs you have, except Tongue Length, and you now have idle tongue movement. On the lips tab for a female model, try adding "CurvyLips" morph for more natural lip flexing. You can also have the brows and nose flex, or add your own slow relaxed blink idle animation. It just depends on how far you want to go with it.

The concept on how it works is none of these morphs are loaded in until you check active. So every time it Reset/Stops it's just going back to your starting morphs or neutral morph position as if they were never applied and clears them out essentially.

Presets
If you get a combination you like, you can save it as a Preset per tab or save the entire collection of tabs as a Mood.

Triggers
These presets can then be triggered via buttons or Timeline with LoadPresetFromPath or LoadMoodFromPath. Or you can toggle specific tabs on and off with triggers that effect the Active button to Send True [x] checked or [ ] unchecked for off.

Random
Checking Random cycles through tab 1-10 that have morphs. If you only use 3 tabs, it skips blank tabs with no morphs and will just randomly switch between your tabs with morphs on tabs 1-10. The rest of the tabs to the right of 10 are not a part of the Random group. They have to be manually turned on or off or essentially function like an always on or on when you want them tabs. So you can have some randomness with some consistent movement whenever you need it. It just gives another layer/combination. The best way I think to test Random is to add a bunch of morphs on the Tongue tab, excluding Tongue Length at first, and turn it on. Like Tongue Roll/Raise/etc. You will then have idle tongue movement during all your expressions and your model will look more alive/realistic. Or add lip curving so the lips occasionally flex some.
I think would be nice and useful if you can include some preset/mood examples too
 
I think would be nice and useful if you can include some preset/mood examples too

I will update DirtyTalkPlayer with an Expression Player soon. In the meantime, here is a Mood you can use to test it out if needed. They are attached at the bottom of this post. Just right click save link as on attachments.

It is preloaded with...
Tab 1: Orgasm Morphs Open Closed (25/25 Count)
Tab 2: Orgasm Morphs Open Rolled (25/25 Count)
Tab 3: Orgasm Morphs Open Closed Rolled (25/50 Count)

Some Idle Animation Morphs on Brows, Lashes, Eyes, Mouth, Lips, Tongue. Try turning just one on and off to see difference by just clicking active on that tab. Then can combine them to see difference with either Tab 1, 2 or 3.

So what I have is just Tab 3 active checked and Brows, Lashes, Eyes, Mouth, Lips, Tongue also checked with it.

Moods are saved in these folders...
VAM\Saves\ExpressionRouter\Moods\Female
VAM\Saves\ExpressionRouter\Moods\Male

Since my Orgasm Morphs are available for Female and Male/Futa and use the same names for the morphs, you can use this file for female or male and it will work. So you can add it to both folders if you want. Just put both jpg and json files in a Moods folder.

After added to either or both folders, click on Load Mood button to load it in. You can resave it with another image to override image to your model if you prefer for female/male.

This uses Orgasm Morphs...

A lot of it is me just testing it out myself as well to see what works. You can get interesting results with just small movements or even small negative movements. You just sort of try it out on one tab at a time, adjusting sliders to see if you get a smooth result that works. Then go to next tab and add another layer and see what you can come up with.

When loading it on a scene, if it already uses expression morphs from the scene or another plugin, or has a model with a starting pose that isn't more neutral, you may have to dial back the Intensity Max some for something like Eyes or not use the extra Eye idle motion. Just test it to see what works for your scene.

Sometimes it can crash because you're pushing it through a lot of morphs and you may have to restart/reload it or restart VAM. So just save your Mood progress if you're really pushing it through morphs to try out. Not all morphs work, so you have to test it to see which ones are compatible. I added some basic filters for region and keywords but nothing advanced to filter out compatibility testing. So you do have to check to see what is compatible.

If someone comes up with a great Mood setting, they can feel free to share them here for others to try out. Or maybe we'll see some scenes using it and you can save their Moods/Presets that way too. :)
 

Attachments

  • VamEssentials - Orgasm Morphs.jpg
    VamEssentials - Orgasm Morphs.jpg
    40.2 KB · Views: 0
  • VamEssentials - Orgasm Morphs.json
    13.7 KB · Views: 0
Last edited:
Could you make it lerp out of the current mood when one is selected via UI or trigger? Time min max (picking a random value in between) would be nice too, I'm trying to make micro movements on the dedicated lips tab and it looks too regular.
 
Last edited:
Sorry but I am not able to understand the meaning of groups. Specifically:
  1. What does it mean if I add two expressions (say E1 and E2) to G1. Are they gonna apply in sequence (E1 -> E2)? Or is one of them going to be applied randomly?
  2. What does it mean if I add E1 to G1 and E2 to G2? I see that there is configuration for blending between them so I gather that it is meant to go back and forth between them but I am not sure about the order.
 
Could you make it lerp out of the current mood when one is selected via UI or trigger? Time min max (picking a random value in between) would be nice too, I'm trying to make micro movements on the dedicated lips tab and it looks too regular.

Here are a few ideas you could try...
  • Before you load a preset or mood, you could trigger Active [ ] for a hard drop off.
  • Or before you load a preset or mood, you could trigger StopReset or StopAll for a smoother drop off. Then time your next trigger to load on another instance to get your timing how you want. So while one is ending your other is starting on another instance possibly. You can do a lot more advanced randomization with timeline triggers and using multiple instances if needed.
  • Putting a single same morph in Group 1 and Group 2 will give micro jitters at certain low time slider settings you can fine tune.
  • Although the Lips tab is filter restricted for Lips, or setup to be dedicated for that for convenience, if you save a Lips preset on it, you can load that preset on tab 1–10 and bypass the filters if you say want lots of Lip morphs on a single instance. It doesn't block it from working, just filters it out to avoid general problems. But you could test it that way as well.
  • Another possibility is to test intensity really low or even negative. Like for the female morph CurvyLips, I have it on just one tab, one group as:
    • G1 Time: 1
    • G1 Blend Speed: 2
    • G1 Intensity Min: -1
    • G1 Intensity Max: .10

You can test going in opposite direction and forward direction around 0 to generate micro movements possibly that way.

If that's not a good solution, let me know more about what you're doing and I can look into it further. Feel free to share a preset or mood if you like and I can look at it.
 
Last edited:
Sorry but I am not able to understand the meaning of groups. Specifically:
  1. What does it mean if I add two expressions (say E1 and E2) to G1. Are they gonna apply in sequence (E1 -> E2)? Or is one of them going to be applied randomly?
  2. What does it mean if I add E1 to G1 and E2 to G2? I see that there is configuration for blending between them so I gather that it is meant to go back and forth between them but I am not sure about the order.

Great question—happy to explain. The two groups (G1 and G2) let you build two independent expression sequences per tab, and they behave a little differently depending on how many expressions you put in each.

If you add E1 and E2 to Group 1 (G1):

They’ll play one at a time, randomly—not in sequence. For example:
  • It might pick E2, animate it in, hold it, fade it out.
  • Then pick E1 next, and repeat.
  • If "Random Mode" is off, it will still pick randomly within the group.
So: G1 = a pool of morphs, 1 plays at a time, chosen randomly.

If you put E1 in G1 and E2 in G2:

Now both groups run in parallel. That means:
  • G1 randomly cycles between morphs in G1.
  • G2 does the same with its own list.
  • Since G1 and G2 run independently, this allows for blended expressions, like:
    • subtle eye squint in G1
    • alternating lip puckers in G2

This setup gives you that layered, "micro-expression" look. You can tweak each group’s speed, hold time, blend range (Min/Max) independently.
 
Last edited:
Hi @VamEssentials

You should add to your comparison list:
- Automatically Loads Morphs that are not on person (preload morphs off)
I have this issue with ExpressionRandomizer, if you load a saved scene and you don't have preload morphs on for the expression morphs, ExpressionRandomizer won't add them and it doesn't work.
I have to edit the Scene .json with adding morphs manually (with 0 value) to get it to work properly.

Anyway, it works for this!! I am assuming it tries to find the morph name in all packages and finds the first one? I think it also worked for SilverExpressionTool

Thanks!
 
I'm loving the plugin so far, it's great to have an up-to-date and powerful expression plugin!

Something I noticed though is that if you have two Atoms and each has their own ExpressionRouter plugin, the next time you load the scene both Atoms will target the same Atom selected for the expressions.
i.e. Female & Male Atom each have their own ExpressionRouter -> Male's plugin targets Male, Female's plugin targets Female -> On scene reload both are now targeting Female.

I also just tried putting two instances of the plugin on an Empty object (one for Male, one for Female) but even then it still does the same thing on a scene reload.

I'm assuming this isn't intended unless I'm doing something wrong 😭
 
I'm loving the plugin so far, it's great to have an up-to-date and powerful expression plugin!

Something I noticed though is that if you have two Atoms and each has their own ExpressionRouter plugin, the next time you load the scene both Atoms will target the same Atom selected for the expressions.
i.e. Female & Male Atom each have their own ExpressionRouter -> Male's plugin targets Male, Female's plugin targets Female -> On scene reload both are now targeting Female.

I also just tried putting two instances of the plugin on an Empty object (one for Male, one for Female) but even then it still does the same thing on a scene reload.

I'm assuming this isn't intended unless I'm doing something wrong 😭

It tries to find first person in scene if newly loaded. It should just save it though to same person with your save file. Thanks for letting me know, I will look into it and do an update.
 
VamEssentials updated ExpressionRouter with a new update entry:

Version 2 Update

Update Note:
If you have Expression Router on a Male and on a Female and save the scene, it will now save properly for multiple instances.

If you save the scene with tabs marked active, it will also launch again with those active if you want to start with general idle animations or your favorite expressions starting on scene load.



Thanks to @Westonini for reporting this multi instance save scene issue so we can keep routing those Expressions.

Read the rest of this update entry...
 
Hi @VamEssentials

You should add to your comparison list:
- Automatically Loads Morphs that are not on person (preload morphs off)
I have this issue with ExpressionRandomizer, if you load a saved scene and you don't have preload morphs on for the expression morphs, ExpressionRandomizer won't add them and it doesn't work.
I have to edit the Scene .json with adding morphs manually (with 0 value) to get it to work properly.

Anyway, it works for this!! I am assuming it tries to find the morph name in all packages and finds the first one? I think it also worked for SilverExpressionTool

Thanks!

Thank you! That's a good one. I added it to the description on the main page. :)
 
So I used this a bit, and ultimately what makes it not work well is the transitions. There need to be more parameters that can be fine-tuned to make things look truly seamless. And the randomness should be able to be further adjusted - instead of just randomly going tab to tab, the randomness should also include ranges and frequencies. Sorry if this all sounds vague, I'm tired.
 
So I used this a bit, and ultimately what makes it not work well is the transitions. There need to be more parameters that can be fine-tuned to make things look truly seamless. And the randomness should be able to be further adjusted - instead of just randomly going tab to tab, the randomness should also include ranges and frequencies. Sorry if this all sounds vague, I'm tired.

If you have a scene file and/or mood file you can post with more info on what you're trying to do, I can look into it to see what may be possible currently in the plugin or via an added update.
 
Strangely, I don't find morphs.. not in favorites, nor in the tab; all morphs.
I use my - phoneme pack.


---
By the way; is it possible to completely abandon the system of selecting morphs based on favourites?
It's not convenient! You have to mark morphs and then remove them from list of favourites (if you dont remove them- list grows enormously:)).
--
Perhaps it is worth increasing the number of morphs displayed?
2025-04-05_225749.jpg

or remove the restriction altogether..
 
Last edited:
@VL_13
Sorry about that, I will get that fixed on the next update so they show up for you in Tab 1-10.

Here's an explanation of what happened if you want to know more...

The region you use in your var is: "!VL_13_phonemes"

This is located in your vmi files:
VL_13.Morph_Phonemes2.1\Custom\Atom\Person\Morphs\female\VL_13\phm\0phm_tongue_A.vmi
"region" : "!VL_13_phonemes", ← This is the region expression plugins filters on

each .vmi file should have only one region field, and its value must be a single string, like this:
"region": "expressions"

In ExpressionRouter, Tabs 1–10 filter morphs for "expressions", "head", "face", "pose controls" as allowed regions. And morphs are only allowed in Tabs 1–10 if their region name matches that list. What this does is help filter out a large catalogue of morphs down to what is more usable so you get less morphs that don't work.

But the Tongue, Mouth, Lips, etc. tabs do not have that restriction, so all morphs are shown there, regardless of region if they match the added keyword filters to find them. I removed those restrictions for those tabs and in place use keyword based restrictions so it focuses on those categories to let more through. So they currently do show up in those tabs. And if you save a preset on those tabs, you can then load them on any tab even if it filters it out from search it will still load them bypasing that.

In comparison, SilverExpressionTool filters morphs where the region contains "exp" and will match for "expressions", "expression", "exp", "mouth/exp" or "exp/mouth", (as long as "exp" appears somewhere in the region string). Examples that won’t match there are: "phonemes", "tongue", "speech", "mouth". So your morphs will also be excluded by default from SilverExpressionTool. So I have opened it up more to include expressions as well as head, face, pose controls.

The best solution if you want to not have issues with loading them, if you create more in the future, is to update your vmi to show the region as "expressions". You just open each vmi and change the region, repackage the var, and can then verify it's loading locally before updating to hub. That should then get it to also work in SilverExpressionTools for those using that.

I say all that just so know what's going on. I will add the region: "!VL_13_phonemes" so they show up in Tab 1-10 on the next update.

Let me know if you notice anything else while trying it out. Thanks for letting me know. :)
 
Last edited:
So, I think I've found the reason.:

2025-04-05_230457.jpg


if I "comment" on this line, will all the morphs be displayed?
upd;
*Alternatively, you could make this filtering - optional. 🙏
 
So, I think I've found the reason.:

View attachment 477427

if I "comment" on this line, will all the morphs be displayed?
upd;
*Alternatively, you could make this filtering - optional. 🙏

This is how it's added, but I can add it on update...

private List<string> allowedRegions = new List<string> {
"expressions", "head", "face", "pose controls",
"!vl_13_phonemes"
};
 
Your plugin has a more user-friendly interface:love:
That's what we've all been missing...
---
Here's what I used before:



If in the future we to combine some synergy functionality with your randomizer, it will turn "rules of game".:sneaky:
 
Your plugin has a more user-friendly interface:love:
That's what we've all been missing...
---
Here's what I used before:

View attachment 477430

If in the future we to combine some synergy functionality with your randomizer, it will turn "rules of game".:sneaky:

That's really impressive. :) I have not used that plugin before but it looks interesting.

If you get something setup with it connected to ExpessionRouter, send me a copy and I can check out how you use them together to better understand the workflow.
 
  • Or before you load a preset or mood, you could trigger StopReset or StopAll for a smoother drop off. Then time your next trigger to load on another instance to get your timing how you want. So while one is ending your other is starting on another instance possibly. You can do a lot more advanced randomization with timeline triggers and using multiple instances if needed.
Thanks for the suggestions. StopAll isn't being smooth for me... I can work around by setting intensity min and max to 0 then waiting for the next cycle. I still think this feature(Mood transitions) will be in a lot of peoples use cases. lerping morphs to 0 then loading the next mood would be a really nice feature.

While I'm here, being able to filter for poses only would help. Currently I'm going back and forth between the plugin and morph UI to ensure I don't add any non poses and mess up my look.
 
Back
Top Bottom