World & rooms

Shop mannequins

Live display figures dressed in what the shop sells, from .ulmannequin files: forms, skins, poses, outfits and the display pieces they replace.

The mannequins in a clothes shop wear what the shop actually sells. A shop grammar places its display pieces as usual (a figure on its feet, a torso on legs, a lingerie window, a dress form, a counter bust); the room's dressing then puts a live figure on each of them, dressed in a coordinated outfit drawn from the venue's clothes stock. Click one to buy the whole outfit or try it on.

modder

Your mod's garments show up on the mannequins of every shop that sells them: nothing to add. A mod can also add its own figures (a dress form, a torso, a hand), skins, poses and outfit recipes in a .ulmannequin file.

How it works

  1. The dressing file Rooms/Dressing/mannequins.uldressing has a rule with a MANNEQUIN table (see Room dressing). Its ON names the display pieces it may replace.
  2. For each such piece, the first pieces entry (below) whose match fits the piece's name says which forms may stand there, which of the piece's materials to hide, and where the figure stands.
  3. The game draws, seeded by the building (the same figures on every visit): a form (of the sex the piece shows: _Male in its name), an outfit recipe, garments for it from the venue's stock, a skin and a pose.
  4. The figure is put up, dressed, posed once, and then never updated again until its outfit changes.

The baked figure stays when the venue sells no clothes (no .ulshop with a Clothing: line at its tag), when no pieces entry matches, when no complete outfit can be found, or when the room already has MAX live figures.

Garments go on the figures exactly as on people (same skeleton, same leader-posed garment meshes), at their base fit: the forms are the morphless figure the garments were made on.

A mannequin file

<mod>/Mannequins/*.ulmannequin, JSON. Every mod's files are read in load order; an entry whose id comes again replaces the earlier one (a pieces entry: its match).

json{
	"forms": [
		{ "id": "female", "gender": "Female", "mesh": "Mannequins/mannequin_f.glb" },
		{ "id": "female_bust", "gender": "Female", "mesh": "Mannequins/mannequin_f_bust.glb",
		  "slots": ["Neck", "Collar"], "outfits": ["necklace"], "poses": ["still"], "skins": ["velvet_black"] }
	],
	"skins": [
		{ "id": "chrome", "color": [0.85, 0.86, 0.88], "roughness": 0.14, "specular": 0.5, "metallic": 1.0 }
	],
	"skin_by_piece": [ { "match": "*_Chrome*", "skin": "chrome" } ],
	"poses": [
		{ "id": "arms_down", "weight": 2,
		  "bones": { "lShldrBend": [0, 42, 0], "rShldrBend": [0, -42, 0] } }
	],
	"outfits": [
		{ "id": "casual", "weight": 3, "pieces": [
			{ "category": "Top", "types": ["tee", "tank", "shirt"] },
			{ "category": "Bottom", "types": ["pants", "shorts", "skirt"] },
			{ "category": "Shoes", "types": ["sneaker", "flat"] },
			{ "category": "Outerwear", "chance": 0.3 } ] }
	],
	"pieces": [
		{ "match": "Display_Mannequin_Figure_*", "forms": ["female", "male"] },
		{ "match": "Display_Bust_Black", "forms": ["female_bust"], "hide": ["Body"], "anchor": "neckLower", "offset": [0, 0, 27], "scale": 0.75 }
	]
}

Forms

Field Meaning
id The form's name.
gender Female or Male: which garments it wears and which people's skeleton it uses.
mesh The body, a .glb (or .fbx) under a mod's Meshes/. It must be skinned to the Genesis 8 skeleton of that sex, with the exact G8 bone names, in the base shape (no morphs): garments go on it without any fitting.
slots The clothing slots it can show (Top, TopUnder, Bottom, BottomUnder, Foot, FootUnder, Outerwear, Torso, Neck, Ear, Wrist, Finger, Waist, Collar...). A garment with any other slot is never drawn for it: no trousers under a torso cut at the thighs. Empty: every slot.
outfits The outfit recipes it uses. Empty: every recipe with a weight above 0.
poses The poses it takes. Empty: every pose that names no forms.
skins The skins it may be rolled. Empty: any.

Shipped forms (ul_Base/Meshes/Mannequins/, made by Tools/Mannequin/export_mannequin.py):

Form
female, male The whole figure, headless (a closed neck cap)
female_head, male_head The whole figure with a smooth featureless head
female_armless, male_armless The whole figure without arms (the torso-on-legs and lingerie figures)
female_torso, male_torso A lingerie torso form: neck to just below the crotch, arms cut at the upper arm
female_bra A bra form: neck to under the bust
female_legs, male_legs Hips and legs: panties, tights, stockings, socks
female_bust, female_bust_head, male_bust Jewellery busts: neck, shoulders, upper chest (with a head for earrings)
female_hand, male_hand A display hand, upright: rings, bracelets, watches

Jewellery is worn the same way as clothes (.ulcloth garments in the Neck, Ear, Wrist and Finger slots), so busts and hands are dressed like the full figures.

Skins

A skin is a material, not pictures: color (linear RGB), roughness, specular, metallic, sheen (velvet). Shipped: white, grey, black, chrome, velvet_black, velvet_cream. skin_by_piece keeps a figure the colour its piece was made in (*_Black* stays black); a pieces entry's skin fixes it outright. Otherwise the skin is rolled among the form's skins.

Poses

bones turns bones from the figure's rest pose: [x, y, z] degrees about the figure's own axes, x pointing to the figure's left, y to its back, z up, applied x first, then y, then z; each bone about its own joint, parents before children, so a turned upper arm carries the forearm with it. After the turn the figure is lowered or raised so its lowest foot stands where it stood ("ground": false to keep it where the bones put it: a hand, a bust). forms limits a pose to those forms. weight is how often it is drawn.

These are the axes of Blender's world with the figure facing -Y, so a pose can be tried on the body in Blender first: blender -b -P Tools/Mannequin/preview_poses.py -- <body.glb> <file.ulmannequin> <out.png> [pose ids] renders each pose front and side, exactly as the game applies it.

Shipped: arms_down, hand_on_hip, three_quarter, walking_stride, contrapposto; still (the partial forms) and hand_upright.

Outfits

A recipe is a list of pieces, each drawn from the stock that the form can show:

Field Meaning
category The garment's category (Top, Bottom, Dress, Outerwear, Underwear, Shoes, Socks, Headwear, Accessory).
types Optional: the garment's Type: (tee, skirt, heel, bra, panty, stocking...).
slots Optional: a slot the garment must occupy (["Neck"] for a necklace).
chance Below 1: the piece is optional and only drawn that often. A required piece that the stock cannot supply makes the game try another recipe.

A recipe may also say max_sexiness (no piece scored above it: a full figure in a clothes shop wears clothes, not a bra and hot pants) and spread (default 1). The pieces of one outfit never share a slot, and stay within spread of the first piece's Sexiness: so a figure reads as one look. Shipped recipes: dress, casual, smart, coat (the full figures; an outer layer only over nothing, since a shirt under a jacket pokes through it on a figure that never moves), lingerie (the lingerie figures and window), and torso_top, lingerie_set, bra, legwear, necklace, earrings, hand_jewellery for the partial forms (weight 0: only where a form or piece names them).

Pieces

Field Meaning
match The catalogue piece's name, wildcards allowed, | between alternatives ("Display_DressForm_Linen|Display_DressForm_Red"). Later files win.
forms The forms that may stand there.
hide The piece's materials to hide (its baked figure), keeping the rest (a window's glass, a dress form's stand). Omitted: the whole piece is hidden.
offset [x, y, z] cm in the piece's frame (x towards its back, the figure faces -x; z up) where the figure's feet, or its anchor, stand.
anchor A bone placed at offset instead of the feet (neckLower for a bust on a stem, lHand for a hand).
scale The figure's size (a counter bust is 0.6 to 0.75).
yaw Degrees added to the figure's turn.
skin, outfits, poses Narrow the form's own for this piece ("outfits": ["lingerie"] in the lingerie window).

The dressing rule

lua-- Rooms/Dressing/mannequins.uldressing
return {
	NAME = "mannequins",
	GRAMMARS = { "shop_clothes", "shop_fashion", "shop_luxury", "shop_department", "shop_sports", "shop_outdoor", "sex_shop" },
	RULES = {
		{ ID = "mannequin_live", ON = { "Display/Mannequin", "Display/Showcase", "Display/DressForm", "Display/Bust" },
		  MANNEQUIN = { STOCK = "shop", MAX = 6, FREEZE = "static" } },
	},
}
MANNEQUIN field Meaning
STOCK "shop": the venue's own clothes .ulshop files (the only source for now).
MAX Live figures per room at most (default 6); the others keep their baked figure.
FREEZE "static" (default): posed once, then the body and each garment are baked into static meshes (one per garment, so a sold-out piece can still come off). true: posed once and left as skinned meshes that are never updated. false keeps it evaluating every frame, only useful to measure the difference.
FORMS, SKINS, POSES, OUTFITS Optional lists of ids that narrow the .ulmannequin choices for this rule.

In the game

Clicking a mannequin opens its menu: Buy this outfit (the price of every piece together) buys each garment through the till like a shelf item, and Try it on opens the shop's fitting rails with the outfit already on the player (offered when the figure is of the player's sex). When a limited garment's last one is sold, the mannequins of that building take it off, as the shelves lose their last box; it is back when the shop restocks.