NPC Fluid Layers

Estimated reading time: 3 minutes

Overview

The NPC fluid layer system lets mod authors render bodily fluid effects on NPC Sidebar dynamic mannequins, including drip animations and static residue. The system manages fluid data via NPCFluids and automatically applies the corresponding fluid layers in the sidebar.


Fluid Parts

NPCFluids supports the following body parts:

PartDescriptionDrip AnimationStatic Residue
vaginaVaginaYesNo
anusAnusYesNo
mouthMouthYesNo
chestChestNoYes
faceFaceNoYes
feetFeetNoYes
leftarmLeft armNoYes
rightarmRight armNoYes
neckNeckNoYes
thighThighNoYes
tummyTummyNoYes

Each part's fluid value ranges from 0 to 5:

  • 0 = No fluid
  • 1 = Slight
  • 2 = Light
  • 3 = Moderate
  • 4 = Heavy
  • 5 = Very heavy

NPCFluids API

NPCFluids is a singleton object for managing all NPC fluid data.

Get Fluid Data

import NPCFluids from '../modules/NamedNPCAddon/NPCFluids';

// Get NPC fluid data; initializes if absent
const fluids = NPCFluids.get('Elara');
console.log(fluids.face);   // 0
console.log(fluids.chest);  // 0

Set Fluid Value

// Set a single part's fluid value
NPCFluids.set('Elara', 'face', 3);

Add / Reduce Fluid Value

// Increase fluid value (default +1)
NPCFluids.add('Elara', 'chest', 2);

// Decrease fluid value (default -1)
NPCFluids.reduce('Elara', 'chest', 1);

Clear Fluids

// Clear a single part
NPCFluids.clear('Elara', 'face');

// Clear all parts
NPCFluids.clear('Elara');

Global Decay

// Decrease all parts for all NPCs by the given value
NPCFluids.decay(1);

Fluid layers are pre-registered NPC Sidebar layers. They require no extra configuration in boot.json. As long as an NPC uses dynamic model mode, fluid layers are applied automatically.

Layer List

Drip Animation Layers

Layer IDAnimation NameMasked
nnpc_drip_vaginalVaginalCumDripYes
nnpc_drip_analAnalCumDripYes
nnpc_drip_mouthMouthCumDripYes

Drip animations select a speed variant based on the fluid value (1–5):

ValueSpeed
1Start
2VerySlow
3Slow
4Fast
5VeryFast

Static Residue Layers

Layer IDImage PathVisibility Condition
nnpc_cum_chestimg/body/cum/chest-{n}.pngFluid value > 0
nnpc_cum_faceimg/body/cum/face-{n}.pngFluid value > 0 and face uncovered
nnpc_cum_feetimg/body/cum/feet-{n}.pngFluid value > 0
nnpc_cum_leftarmimg/body/cum/left-arm-{n}.pngLeft arm visible
nnpc_cum_rightarmimg/body/cum/right-arm-{n}.pngRight arm visible and not in hold
nnpc_cum_neckimg/body/cum/neck-{n}.pngFluid value > 0
nnpc_cum_thighimg/body/cum/thighs-{n}.pngFluid value > 0
nnpc_cum_tummyimg/body/cum/tummy-{n}.pngFluid value > 0

Where {n} is the fluid level number (1–5).


Layer Config Structure

Fluid layer rendering callbacks are generated by factory functions in fluids_layers.ts, following the same layer config structure as the NPC Sidebar:

interface FluidLayerConfig {
  srcfn(options): string;       // Image path; empty string hides the layer
  showfn(options): boolean;     // Whether to show the layer
  zfn(options): number;         // Z-axis layer order
  masksrcfn(options): string;   // Mask image path (for close-up view)
  dxfn(options): number;        // X-axis offset
  dyfn(options): number;        // Y-axis offset
  animation?: string;           // Static layer animation name (fixed to 'idle')
  animationfn?(options): string; // Dynamic drip animation name (drip layers only)
}

Visibility Rules

  • Face (face): Must not be covered by mask or face_covering clothing type
  • Mouth (mouth): Must not be face-covered
  • Left arm (leftarm): Arm must not be in none or cover pose
  • Right arm (rightarm): Arm must not be in none, cover, or hold pose

Image Asset Paths

Fluid images are located in the BeautySelectorAddon image directory:

img/body/cum/
├── chest-1.png ... chest-4.png
├── face-1.png ... face-3.png
├── feet-1.png ... feet-2.png
├── left-arm-1.png ... left-arm-2.png
├── right-arm-1.png ... right-arm-2.png
├── neck-1.png ... neck-3.png
├── thighs-1.png ... thighs-5.png
├── tummy-1.png ... tummy-5.png
├── vaginal-*.png   (drip animation frames)
├── anal-*.png      (drip animation frames)
└── mouth-*.png     (drip animation frames)