Making your own slider set
Write the sliders you want in a text file, load it in Punk//Body Studio, and shape bodies with it like the built-in set. This page covers the file format, the Inspector tab that helps you measure the body, and a small set from start to finish. New to the app? Start with the user guide.
Overview
A slider set is a plain text file with the extension .punks, written in TOML. It says which bodies it is for and, for each of them, which sliders the Body tab shows and how each slider moves the body. PunkBody (Default), the set that comes with the app, is one; yours appear next to it in the slider set list whenever they cover the body you have loaded.
A slider set can:
- move the vertices of a body mesh: scale, turn or shift a part of the body, push its surface in or out, round it out onto a sphere, or apply offsets sculpted in another tool;
- give each kind of body (female V, male V, each NPC body) its own sliders;
- group sliders, describe them in a tooltip, blend a group into the body around it with a Smoothing slider, and drive V's nipple overlays.
It can't:
- change textures, the skin or materials, or add and remove vertices;
- move the skeleton, so it can't make a body really taller (see Leg Length in the default set for what a mesh can do);
- shape garments directly. It doesn't have to: when you build, the Wardrobe refit fits V's clothes to the shaped body, and the physics is sized from it.
Sets you make are yours. Share them however you like (see Sharing your set).
Quick start
- Make a new text file named, for example,
hips_and_glutes.punks, and paste the worked example into it. (The app's install folder also has examples, inconfigs\examples.) - Put it where the app reads slider sets:
%APPDATA%\cp-slider\config\configs(paste that into the address bar of a File Explorer window; create theconfigsfolder if it isn't there). Or use File > Import Sliders, which checks the file and copies it into that folder for you. - Load female V's body. Pick Hips and Glutes in the slider set list on the Body tab and move the sliders.
- Edit the file in that folder with any text editor, save it, and press the reload button next to the slider set list. The app reads every set again and puts the loaded body's sliders back to their defaults, so you see your change from a clean start.
!. A set that loads but doesn't fit the body says so in the status line. Error messages lists what each one means.hips_and_glutes_2.punks, and you get two sets with one name. Edit the copy in %APPDATA%\cp-slider\config\configs instead.The app also reads sets from a configs folder next to its program, which holds the default set. Leave that folder alone: updates replace it.
Coordinates and submeshes
Every position in a slider set is in the game's own space, on the body as the game has it (before any slider moves it):
- Units are metres.
0.01is one centimetre. Female V's neck is about 1.5 m up. - X runs across the body: +X is the body's own right, −X its left.
x = 0is the centre line. - Y runs front to back: +Y is forward (the toes and the breasts), −Y is the back.
- Z is up:
z = 0is the floor under the feet.
You don't have to guess numbers: the Inspector tab shows the position of any point you click.
Submeshes
A body mesh comes in pieces called submeshes, numbered from 0. The game's player and NPC bodies are cut into 8 horizontal bands, submeshes 0 to 7, with the vertices along every cut doubled: one copy in each band. On female V's body:
| Submesh | Covers | Height (z, m) |
|---|---|---|
| 0 | chest and upper back | 1.226 – 1.509 |
| 1 | the top of the chest, shoulders and the neck | 1.421 – 1.531 |
| 2 | waist and belly | 1.045 – 1.270 |
| 3 | pelvis, hips and the top of the glutes | 0.917 – 1.109 |
| 4 | thighs and the bottom of the glutes | 0.510 – 0.980 |
| 5 | knees | 0.277 – 0.528 |
| 6 | calves and shins | 0.074 – 0.286 |
| 7 | feet | 0.005 – 0.106 |
| 8 – 11 | player bodies only: the arms, which the app joins at the shoulders (upper arm, forearm with the elbow, hands, wrist port) |
The other bodies use the same bands at slightly different heights. NPC bodies carry their arms and hands in the body mesh as submeshes 8 to 10 (8 to 11 on the boxer and massive bodies). Click a point with the Inspector to see which submesh it is in.
The [config] table
Every file starts with it:
[config]
name = "Hips and Glutes"
format_version = 2
author = "Your Name"
description = "Hip Width and Glute Size for female V, with smoothing."
| Field | Value | What it does |
|---|---|---|
name | text, required | The set's name in the slider set list. Projects remember the set by its file, and by this name if the file has moved. |
format_version | number, required | Write 2. Files from older versions (1, one body with its sliders at the top level) still load. |
author | text, optional | Who made it. |
description | text, optional | What it is for. |
Then come one or more profiles. TOML tips: # starts a comment; write paths with backslashes in single quotes ('base\characters\...'), since in double quotes every backslash must be doubled; and a [[profile.region]] or [[profile.slider]] belongs to the last [[profile]] above it.
Profiles
A profile is the sliders for one kind of body. Each [[profile]] lists the body meshes it is for, then its regions and sliders.
[[profile]]
name = "Player body (feminine)"
depot_paths = [
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full.mesh',
]
vertex_counts = [1011, 257, 367, 514, 988, 260, 396, 848, 939, 942, 8192, 648]
fixed_submeshes = [8, 9, 10, 11]
keep_sides = true
| Field | Value | What it does |
|---|---|---|
name | text, required | Unique within the set. |
depot_paths | list of paths, at least one | The game paths of the bodies this profile is for (see Targeting bodies). Bodies listed together must have the same submeshes, like female V's three breast sizes. The app uses the first profile whose list holds the loaded body. |
vertex_counts | list of numbers, default none | How many vertices each submesh should have. If a game patch or another mod changed the body, the set then refuses to load on it rather than move the wrong vertices. Leave it out to skip the check. For a player body, include the arms (12 numbers, as in the default set). |
fixed_submeshes | list of submesh numbers, default none | Submeshes no slider moves (except sliders with moves_fixed). The edge where the rest of the body meets them is pinned like a seam. List the arms here: [8, 9, 10, 11] on the player bodies, [8, 9, 10] on most NPC bodies. |
seam_falloff | metres, default 0.02 | How far from the seams every slider fades out. 0 turns the fade off. |
keep_sides | true/false, default false | No point may cross the centre line (x = 0) from the side it starts on: where the two halves meet (cleavage, inner thighs, between the glutes) they press together instead of passing through each other. Points closer than 3 mm to the centre line are free. |
output_path | a game path, optional | Advanced: writes the shaped body under this path instead of over the game's body, for mods that load it through ArchiveXL. The app writes the file there but does nothing to make the game use it. Only for a profile with one depot path. Leave it out. |
Regions
A region is a named, reusable set of vertices on one submesh, each with a weight from 0 to 1: how strongly an operation moves it. Soft edges (weights that fade out) are what make a change blend into the body.
[[profile.region]]
id = "glute_r_s3"
submesh = 3
select = "sphere"
center = [0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
| Field | Value | What it does |
|---|---|---|
id | text, required | Unique within the profile. Operations name it. |
submesh | number, required | The submesh it picks vertices from. |
select | required | The shape: sphere, box, capsule, indices or all, with that shape's fields below. |
| select | Fields | Weight |
|---|---|---|
sphere | center = [x, y, z], radius (> 0), falloff (default 0, at most radius) | 1 within radius − falloff of the centre, fading smoothly to 0 at radius. The soft edge is inside the radius. |
box | min = [x, y, z], max = [x, y, z] (each of min no larger than max), falloff (default 0) | 1 inside the box, fading smoothly to 0 at falloff outside its faces. Unlike the sphere, the soft edge is outside. |
capsule | a = [x, y, z], b = [x, y, z], radius (> 0), falloff (default 0, at most radius) | Like a sphere stretched along the line from a to b, with rounded ends: good for a limb along its bone. |
indices | indices = [..] (vertex numbers in the submesh), weights = [..] (optional, one per index, default 1) | Exactly those vertices. Weights of 0 or less leave a vertex out. Works only on the exact mesh it was made for. |
all | none | Every vertex of the submesh, weight 1. |
Regions are always measured on the body as the game has it, never on the shape other sliders make. An operation can also carry its own selection instead of naming a region: put select and the shape's fields on the operation itself, with submesh (default 0). It can't have both.
Sliders
[[profile.slider]]
id = "hip_width"
label = "Hip Width"
description = "Makes the hips wider or narrower."
group = "Hips"
min = -1.0
max = 1.0
| Field | Value | What it does |
|---|---|---|
id | text, required | Unique within the profile. Projects save slider values by id, so changing an id loses the values saved for it. |
label | text, required | The slider's name on the Body tab. |
description | text, optional | Shown when you hover over the slider. |
group | text, optional | The section of the Body tab it appears in. Sliders without a group go in General. Sections appear in the order of their first slider, each with a button that puts its sliders back to their defaults. |
min, max | numbers, default 0 and 1 | The slider's range; min must be less than max. Values are kept inside it. |
default | number, default 0 | Where the slider starts, and where a double-click or the group's reset button puts it back. Must be inside the range. |
rest | number, default 0 | The value at which the slider changes nothing. Must be inside the range. |
key | one or more [[profile.slider.key]] | What the slider does: see Keys. Every slider needs at least one, except smoothing and effect sliders, which have none. |
Further fields make special sliders: smooth (Smoothing sliders), with and relative (dependent sliders), effect (nipple sliders) and moves_fixed (arm sliders).
A slider moved off its default is marked in yellow with > before its name.
default and rest the same (both 0, unless you have a reason). The app counts a body as changed when a slider is off its default, and only changed bodies have their body files written into the mod. A default away from rest shapes the body in the preview, but a build of that body at its defaults writes nothing.Keys and blending
A key is a shape at one slider value: a list of operations that move the body. The value rest counts as a key that moves nothing.
[[profile.slider.key]]
at = 1.0
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s3"
pivot = [0.0, -0.03, 1.02]
scale = [1.12, 1.0, 1.0]
| Field | Value | What it does |
|---|---|---|
at | number, required | The slider value of this shape. Inside the slider's range, different from every other key's and from rest. |
op | one or more [[profile.slider.key.op]], required | The operations. Their moves add up. |
seam_falloff | metres, optional | This key fades out over this distance from the seams instead of the profile's (see Seams). |
with_at | number | Only for dependent sliders. |
How values between keys blend
When a set loads, every key is worked out once on the body, as how far each vertex moves. At any slider value the app takes the two keys on either side (counting rest) and blends them in a straight line. With rest = 0 and keys at -1 and 1, the value 0.5 gives half the shape of the key at 1, and −0.25 a quarter of the key at −1.
- Beyond the last key nothing more happens. Above the highest key the slider gives that key's shape exactly; it doesn't carry on. Put a key at
minand one atmax(unless one of them isrest), or the end of the slider does nothing. - Curves: a key in between shapes the response, for example a gentle start and a strong finish, or a different kind of change past a point (the default set's sliders grow through wider, softer regions past ±1).
- One side only: a slider from 0 to 1 with one key at 1 is a classic blend shape.
- Sliders add up. Two sliders that move the same vertex add their moves, like blend shapes.
- Turns blend as straight lines, so a large
rotate_degshrinks a little halfway. Keep turns small, or add keys in between.
Operations
An operation ([[profile.slider.key.op]]) moves the vertices of one region; kind says how. Every move is scaled by each vertex's region weight. Transform, inflate and spherize name a region or carry their own selection; delta lists vertices itself.
transform: scale, turn and shift
Each vertex is scaled and turned about pivot, then shifted by translate. How far that moves it, times its weight, is its move.
| Field | Default | Meaning |
|---|---|---|
pivot | [0, 0, 0] | The point scaling and turning are about, in metres. Put it in the middle of the part: scaling about a point inside the hips widens them evenly on both sides. |
scale | [1, 1, 1] | Factor per axis: [1.12, 1, 1] is 12% wider, nothing else. |
rotate_deg | [0, 0, 0] | Degrees about X, then Y, then Z. |
translate | [0, 0, 0] | A shift in metres: [0, 0, 0.01] lifts 1 cm. |
along_z | none | A height profile, [[height, factor], ...] with rising heights: each vertex's weight is multiplied by the factor at its height (in a straight line between the pairs, the end values beyond them). Moves a band of the body that fades out above and below. |
kind = "transform"
region = "hips_s3"
pivot = [0.0, -0.03, 1.02]
scale = [1.12, 1.0, 1.0]
along_z = [[0.9, 0.0], [1.0, 1.0], [1.1, 0.0]]
inflate: push the surface in or out
Pushes each vertex along the surface's outward direction (its normal) by distance times its weight. Good for fuller or slimmer parts, and for the whole body at once. The direction is averaged over the vertex's neighbours, across submesh cuts, so both copies of a doubled vertex move together.
| Field | Default | Meaning |
|---|---|---|
distance | required | Metres outward; negative pushes in. |
along_z | none | A height profile, as for transform: the push is multiplied by the factor at the vertex's height. |
hold_center | false | When swelling, never push a point sideways towards the centre line: surfaces that face each other across it (between the glutes and the thighs, under the breasts) close up instead of passing through. Thinning is not limited. |
axes | [1, 1, 1] | Weights on the push direction's X, Y and Z: [1, 0.2, 0] widens mostly sideways; [0, 1, 0] only moves points forward or back. |
facing | none | A direction, [x, y, z]: only push where the surface faces that way. [0, -1, 0] is the back of the body. |
facing_angle | 60 | Degrees from facing that get the full push; the push fades to nothing over the next 30 degrees. 0 to 180. |
sharp | false | Fine detail (muscle definition): left out of the group's Smoothing, which would even it out. |
kind = "inflate"
region = "glute_r_s3"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
spherize: round out onto a sphere
Every vertex inside a sphere (or, with stretch, an ellipsoid) moves straight out from its centre onto its surface, times its weight; vertices outside it don't move. This makes round, full shapes (a pregnant belly) that a transform of a flatter surface can't. Keep center well inside the body: right next to it, the directions out of it change sharply.
| Field | Default | Meaning |
|---|---|---|
center | required | The sphere's centre, metres. |
radius | required | Metres, more than 0. |
stretch | [1, 1, 1] | Multiplies radius per axis, for an ellipsoid. Each more than 0. |
amount | 1 | Multiplies the push. -1 takes the same push away, to express a change from one shape to another in a later key. |
blend | 0 | 0 to 1: rounds the crease where the sphere meets the body, as a fraction of its size. 0 is a hard edge. |
facing | none | Only push vertices on this side of the centre (full within facing_angle, fading over the next 30 degrees), so nothing behind moves. |
facing_angle | 60 | Degrees, 0 to 180. |
pull | false | Also pull vertices outside the sphere in onto it (within the region), so the region takes the sphere's form instead of only being filled out to it. |
kind = "spherize"
region = "belly_s2"
center = [0.0, 0.0, 1.08]
radius = 0.13
stretch = [1.0, 1.2, 1.0]
facing = [0.0, 1.0, 0.0]
blend = 0.3
delta: sculpted offsets
Moves listed vertices by listed amounts: the way to bring in a shape sculpted in another tool.
| Field | Default | Meaning |
|---|---|---|
submesh | 0 | The submesh the indices are in. |
indices | none | Vertex numbers. |
offsets | none | [[dx, dy, dz], ...] in metres, one per index. |
file | none | A binary .cpsd file with the offsets, as a path relative to the set's file (no .. or drive letters). |
kind = "delta"
submesh = 0
indices = [12, 13, 14]
offsets = [[0.0, 0.01, 0.0], [0.0, 0.02, 0.0], [0.0, 0.01, 0.0]]
Give inline indices and offsets, a file, or both (they add up). A .cpsd file is little-endian: the bytes CPSD, a u32 version (1), a u32 count, then per vertex a u32 submesh, a u32 index and three f32 offsets. Import and Export copy delta files along with the set. Like index regions, deltas only fit the exact mesh they were made for.
Seams
The body mesh ends where separate meshes take over: the neck, where the head starts, and the arm holes, where the arms start (on NPC bodies, the edge where the torso meets the arms and hands in fixed_submeshes). If a slider moved those edges, the game would show a gap there. So every key's moves fade out towards them:
- A seam is an open edge of the body, counted after joining the submeshes at their cuts, plus the border with any
fixed_submeshes. - Every move is multiplied by a fade that is 0 on a seam and rises smoothly to full strength at the profile's
seam_falloff(default 2 cm) from it. Seam points never move, whatever the regions cover. - A key with its own
seam_falloffuses that distance instead. A big push near a seam with the default 2 cm fade stands up as a wall next to the pinned edge; a wider fade (the default set uses 3.5 to 10 cm on its biggest keys) spreads it out. - Smoothing and the automatic fold repair never move seam points either.
- An imported body has no arms joined, so its arm holes are seams too and stay where they are.
[[profile.slider.key]]
at = 3.0
seam_falloff = 0.06
Still keep your regions away from the neck and the arm holes where you can: a shape that fades out within a few centimetres of the neck looks pinched.
Smoothing sliders
A smoothing slider has no keys. It evens out the combined change of the other sliders in its group across the surface, blending the edges where their regions meet.
[[profile.slider]]
id = "hips_smoothing"
label = "Smoothing"
description = "Blends the Hips sliders into the body around them. 0 is off."
group = "Hips"
min = 0.0
max = 4.0
default = 1.0
smooth = { iterations = 120 }
smooth = { iterations = N }: N passes at the slider'smax, 1 to 500. Its value scales that: halfway is N/2 passes,minis off.minmust be 0 or more.method:"laplacian"(the default) moves each point's change halfway towards its neighbours' on every pass. It blends edges well but flattens big shapes."taubin"(smooth = { iterations = 30, method = "taubin" }) takes out facets and creases but keeps the overall shape and size, for shapes that are smooth already.- It needs a
group, and a group can have only one. It can't have keys,withorrelative. - Inflate operations with
sharp = trueare left out and added as they are. - How far a point moves out and how it slides along the surface are smoothed separately, so round shapes stay round.
- The default set's groups each start with one: 0 to 4, starting at 1, 120 passes at 4. Past 2, large shapes start to lose their form.
Special sliders
Dependent sliders: with, with_at, relative
A slider can change what another slider made, for example lift the belly that a Pregnant slider makes (the example below lifts it by up to 2 cm when Pregnant is at 1). Give it with = "<the other slider's id>", and every key a with_at: the other slider's value that key is for. The keys form a grid, and the app blends across both sliders' values. Where the other slider is at its rest the dependent slider does nothing, unless you put a key there.
[[profile.slider]]
id = "pregnant_height"
label = "Pregnant Height"
group = "Pregnancy"
min = 0.0
max = 1.0
with = "pregnant"
[[profile.slider.key]]
at = 1.0
with_at = 1.0
[[profile.slider.key.op]]
kind = "transform"
region = "belly_s2"
translate = [0.0, 0.0, 0.02]
- The other slider must be a plain slider: not itself, not smoothing, not an effect slider, and not dependent itself. Every
with_atmust be inside its range. relative = trueworks each key out on the shape the other slider makes atwith_at, not on the unshaped body, so its operations act on that shape (the default set's Breast Roundness rounds the breast Breast Size made). The other slider must come earlier in the profile. Regions are still measured on the unshaped body.
Nipple sliders: effect
effect = "nipple_size" or effect = "nipple_protrusion" makes a slider that moves nothing on the body. It shapes V's nipple overlays instead, the separate meshes the game draws the nipples on with nudity on; the preview draws them, and a build writes them. Its value minus rest is the effect: Size shows the painted areola and nipple 20% larger per step up and 10% smaller per step down; Protrusion raises the nipple 1.5 mm per step. An effect slider has no keys, smoothing or with, and does nothing on bodies without overlays (NPC bodies).
[[profile.slider]]
id = "nipple_size"
label = "Nipple Size"
group = "Chest"
min = -2.0
max = 4.0
effect = "nipple_size"
Arm sliders: moves_fixed
moves_fixed = true lets a slider move the profile's fixed_submeshes too. For that slider the fixed submeshes are joined to the body, so where they meet (the player's arm holes) is no seam and both sides move together; only the outer edges, like the neck, stay pinned. This is how the default set's Arms sliders shape the arms and shoulders as one. On a body without the joined arms (an imported one), moves_fixed sliders are hidden, along with regions and operations on the arm submeshes.
Names the app looks at
- Group
Chest: Sync breast-size variants copies every slider between female V's three bodies except this group, so each breast size keeps its own chest. Sync copies by sliderid, so give the same slider the same id in each body's profile.moves_fixedsliders are always copied: the three share one set of arms. - Regions whose id starts with
chest_l,chest_r,glute_lorglute_rare the areas the Physics tab's preview jiggles (left breast, right breast, left and right glute). Without them the preview uses spheres around the skeleton's chest and buttock joints. The jiggle in the built mod comes from the skeleton, not from these.
Error messages
When a set fails to load, the line under the slider set list says why, in the form invalid config: profile `Player body (feminine)`: slider `hip_width`: min must be < max. The usual ones:
| Message | Meaning |
|---|---|
| parse error in <file>: … | Not valid TOML, a required field is missing (missing field `distance`; a key without any operation says missing field `op`), a value has the wrong type, or an unknown kind, or select in a region. The message gives the line and column. |
| unsupported config format version N | format_version isn't 1 or 2. |
| a config needs at least one [[profile]] | No profile. |
| duplicate profile name / duplicate region id / duplicate slider id | Names and ids must be unique (profiles in the set, regions and sliders in their profile). |
| profile `…` has no depot_paths | depot_paths is empty. |
| `…` is not a depot path | A depot path or output_path has .., a drive letter, an empty part or characters a file name can't have. |
| output_path needs a single depot path | output_path on a profile with several bodies. |
| seam_falloff must be a number >= 0 | On the profile, or (with the key's value) on a key. |
| need radius > 0 and 0 <= falloff <= radius | A sphere or capsule whose falloff is negative or larger than its radius. |
| box min must be <= max and falloff >= 0 | A box with min above max on some axis. |
| weights length must match indices | An indices selection with a different number of weights. |
| a selection has a NaN or infinite number / an op has a NaN or infinite number | TOML allows nan and inf; a set may not use them. |
| min must be < max | The slider's range is empty or backwards. |
| default … outside [min, max] / rest … outside [min, max] | Move default or rest into the range. |
| slider `…` has no keyframes | A shape slider needs at least one key. |
| keyframes (including rest) must have distinct `at` values | Two keys at the same value, or a key at rest. |
| key at N outside range | A key's at is outside min…max. |
| unknown region `…` | An operation names a region the profile doesn't have (check the spelling). |
| … needs a region or a selection / … has both region and inline selection | A transform, inflate or spherize needs exactly one of them. The first also comes when the operation's own selection has an unknown select or misses one of its shape's fields (a sphere without radius, for example). |
| along_z heights must increase | Sort the along_z pairs by height; no height twice. |
| facing must not be zero and facing_angle must be 0..180 | facing = [0, 0, 0] has no direction. |
| spherize radius and stretch must be > 0 / spherize blend must be 0..1 | As it says. |
| delta indices/offsets length mismatch / delta op needs inline data or a file / delta file … must be a plain relative path next to the config | Problems with a delta operation. |
| a smoothing slider needs a group to smooth / has no keyframes / needs min >= 0 and 1..=500 iterations / cannot use `with` or `relative`; group `…` already has a smoothing slider | See Smoothing sliders. |
| an effect slider has no keyframes, smoothing or `with` | See Nipple sliders. |
| `with` names unknown slider / must name a plain slider other than itself / every key needs a `with_at` inside …'s range / with `relative`, … must come before it / `relative` needs `with` / `with_at` needs `with` | See Dependent sliders. |
These come when the set is used on a body, in the status line as Config does not fit this body: …:
| Message | Meaning |
|---|---|
| config expects vertex counts […] but mesh has […] | The body isn't the one vertex_counts describes: a game patch or another mod changed it, or the counts are wrong. For a player body, list the arms' counts too. |
| slider `…`: submesh N does not exist | A region or operation names a submesh the body hasn't got. |
| vertex N out of range for submesh M | An index or delta names a vertex the submesh hasn't got. |
| this config uses vertex indices (region `…`) / deltas (slider `…`), which only fits the mesh it was made for | On an imported body: index regions and deltas can't carry over to another mesh. Use spheres, boxes, capsules or all. |
| invalid delta file … | A .cpsd file is damaged or not one. |
fallof = 0.05, is skipped without a message, and the real field keeps its default. If a change seems to do nothing, check the spelling.Using the Inspector
The Inspector tab, next to Body and Wardrobe, is for measuring the body while you write a set. Everything it shows is in the same game space the file uses.
Picking a vertex
- Click the body to pick the vertex nearest to where you click. The tab shows its Submesh (number and name), Vertex number, Base pos (where it is on the unshaped body: the number to use in a set) and Morphed (where your sliders put it now). The preview marks it and shows
PICK SM3 #210 (x, y, z). - Picking works on the shaped body, but always reports the unshaped position, since that is what sets use.
- COPY POSITION copies the base position as
[x, y, z]; COPY INDEX copies the vertex number. - Click a few points to measure a part: the middle of a glute, the top and bottom of the hips, how far the body reaches to the side.
Selecting vertices
Shift+click adds a vertex to the selection, or takes it out again. COPY AS REGION copies them as an indices region named <region id>_verts, as long as they are all in one submesh. CLEAR forgets them. Index regions only work on the exact mesh they were picked on.
The region tool
- Pick a vertex. The region is centred on it, on its submesh (a new pick, or CENTER ON PICK, moves it).
- Choose Sphere (a radius and a falloff inside it) or Box (half its size on each axis, and a falloff outside it), and set the sizes. With Show weights on, the body is shaded yellow by how strongly the region would move each vertex, and AFFECTS N VERTICES counts them.
- Mirror X adds a copy on the other side of the centre line, named
<id>_mirror. - Type the Region id, then COPY REGION TOML and paste the
[[profile.region]]text into your file.
The tool shows and copies the region for the picked vertex's submesh only. If the shape reaches into the next band, paste it again with that band's submesh and a new id (the worked example names them _s2, _s3, _s4). Capsules, and the shapes of operations such as a spherize sphere, are written by hand; the region tool's sphere is a handy way to find their centre and size.
Checking a slider's effect
- Save the file and press the reload button on the Body tab.
- Move the slider. Switch the preview to mesh shading to see the triangles: look for creases, spikes and tears along the band borders.
- Back on the Inspector, pick a vertex: Morphed against Base pos says how far the slider moved it.
- Try each slider at its
minandmax, with the group's Smoothing at 0 and at its maximum, and on every body the profile covers.
Targeting bodies
A profile is used for a body when its depot_paths holds that body's game path. Paths are compared ignoring upper and lower case, and / counts as \. The set shows in the slider set list for every body one of its profiles covers.
| Body | Depot path |
|---|---|
| Player body (feminine) | base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full.mesh |
| … big breasts | base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full_breast_big.mesh |
| … small breasts | base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full_breast_small.mesh |
| Player body (masculine) | base\characters\common\player_base_bodies\player_man_average\t0_000_pma_base__full.mesh |
| NPC woman (average) | base\characters\common\base_bodies\woman_average\t0_000_wa_base__full.mesh |
| NPC woman (average, big breasts) | base\characters\common\base_bodies\woman_average\t0_000_wa_base__full_breast_big.mesh |
| NPC woman (alternate) | base\characters\common\base_bodies\woman_average\t0_002_wa_prostitute__full.mesh |
| NPC woman (alternate, slim) | base\characters\common\base_bodies\woman_average\t0_002_wa_prostitute__full_slim.mesh |
| NPC woman (big) | base\characters\common\base_bodies\man_big\t0_000_wba_base__full.mesh |
| NPC man (average) | base\characters\common\base_bodies\man_average\t0_000_ma_base__full.mesh |
| NPC man (average, alternate) | base\characters\common\base_bodies\man_average\t0_000_maf_base__full.mesh |
| NPC man (muscular) | base\characters\common\base_bodies\man_average\t0_002_ma_muscular__full.mesh |
| NPC man (old) | base\characters\common\base_bodies\man_average\t0_000_mao_base__full.mesh |
| NPC man (big) | base\characters\common\base_bodies\man_big\t0_000_mb_base__full.mesh |
| NPC man (big, heavy) | base\characters\common\base_bodies\man_big\t0_000_mba_base__full.mesh |
| NPC man (sumo) | base\characters\common\base_bodies\man_big\t0_000_mba_base__sumo_full.mesh |
| NPC man (boxer) | base\characters\common\base_bodies\man_big\t0_003_mb_boxer__full.mesh |
| NPC man (fat) | base\characters\common\base_bodies\man_fat\t0_000_mf_base__full.mesh |
| NPC man (massive) | base\characters\common\base_bodies\man_massive\t0_000_mm_base__full_head.mesh |
- Female V has three bodies, one per character-creator breast size. They have the same submeshes and vertex counts, so one profile can list all three (as the worked example does), or each can have its own profile with regions placed on its own shape (as the default set does for the chest). Use the same slider ids in all three so Sync breast-size variants can copy them.
- Male V has one body; its vertex counts differ from female V's, so it needs a profile of its own.
- NPC bodies: one profile per body. Changing an NPC body changes every NPC who wears it. Their arms and hands are part of the body mesh: list them in
fixed_submeshes([8, 9, 10], or[8, 9, 10, 11]on the boxer and massive bodies; the massive body's head is in it too). The default set's vertex counts are a good guide to each body's submeshes. - Imported bodies (a body mod such as VTK Vanilla HD or a Hyst body, added with File > Import Body) use the profile of the game body they replace, but their mesh is different: VTK Vanilla HD's female body has about 91,000 vertices against the game's 4,641. So the set is fitted by position: spheres, boxes, capsules and
allcarry over,vertex_countsisn't checked, and sets with index regions or deltas are refused for them. The bodies checked so far keep the game's 8 bands at the same heights. Imported bodies don't get the player arms joined, somoves_fixedsliders, and regions and operations on submesh 8 and up, are left out.
Tips and pitfalls
- Keep the seams still. The fade from the seams is a safety net, not a design tool: keep your regions clear of the neck and the arm holes, and give big keys near them a wider
seam_falloff. - Cover every band a shape touches, with identical regions, or the body tears along the band border. Check the border in mesh shading.
- Avoid spikes at large values. A hard edge that is invisible at 1 becomes a ridge at 5. Use wider falloffs for big keys, add keys with wider, softer regions further out, fade transforms with
along_z, and give the group a Smoothing slider. - Test the extremes: every slider at its
minandmax, alone and together with its neighbours, with Smoothing off and full, on each body the profile covers. Walk the body on the Physics tab too. - Folds and flipped triangles. Where a big shape pushes skin past skin that stays (a lowered breast past the ribs below), triangles turn over into a slit. The app undoes such folds automatically by relaxing the moves around them, but that is a repair: a smaller push,
hold_center,keep_sidesor afacinglimit usually looks better. - Mind the units. Everything is in metres: a 2 cm push is
0.02, not2. - Performance. A key only stores the vertices it moves, so small regions are cheap. Regions with
allon every band, many keys and many Smoothing passes cost time on every slider move, and more on imported bodies with many times the vertices. - Keep names stable. Projects find a set by its file name (then by its
name) and remember values by sliderid. Renaming either leaves saved projects without their values. - Start from what works. The default set's file,
punkbody_default.punksin theconfigsfolder next to the program, shows every feature on the real bodies. It is long because it is generated by a script, not written by hand.
Sharing your set
File > Export > Sliders saves the selected set, with any delta files it uses, wherever you choose. Others add it with File > Import Sliders. A set is plain text, so you can also share the .punks file as it is. Slider sets you write are yours, and so is the choice of how to share them.
Worked example
A small set for female V: Hip Width (wider or narrower), Glute Size (fuller glutes) and a Smoothing slider for the two, in a group called Hips. It is checked on the game's three female bodies and on imported VTK Vanilla HD and Hyst Angel bodies: no slider moves a seam or tears a band border. Here it is piece by piece; the whole file follows.
The set and the profile
[config]
name = "Hips and Glutes"
format_version = 2
author = "Your Name"
description = "Hip Width and Glute Size for female V, with smoothing."
The name appears in the slider set list. Put your own name in author.
[[profile]]
name = "Player body (feminine)"
depot_paths = [
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full.mesh',
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full_breast_big.mesh',
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full_breast_small.mesh',
]
vertex_counts = [1011, 257, 367, 514, 988, 260, 396, 848, 939, 942, 8192, 648]
fixed_submeshes = [8, 9, 10, 11]
keep_sides = true
- One profile for all three of female V's bodies: they share their submeshes, and hips and glutes are the same on all three.
vertex_counts: the 8 body bands, then the 4 arm submeshes the app joins on. If a patch changes the body, the set says so instead of moving the wrong vertices.fixed_submeshes: the arms never move, and the arm holes stay pinned.keep_sides: the inner thighs and the glutes press together at the centre line instead of passing through each other.seam_falloffis left at its default (2 cm): the hips are far from the neck and arm holes.
The regions
[[profile.region]]
id = "hips_s2"
submesh = 2
select = "box"
min = [-0.25, -0.20, 0.97]
max = [0.25, 0.15, 1.08]
falloff = 0.08
- A box across the whole body, from 0.97 m to 1.08 m high, around the hips. It is wider and deeper than the body (±25 cm across, from 20 cm behind to 15 cm in front) so that it takes in all of it at those heights.
falloff = 0.08: the weight fades over 8 cm above and below the box (outside its faces), so the change blends into the waist and thighs. With the fade it reaches from 0.89 m to 1.16 m, which crosses bands 2, 3 and 4, so the same box is repeated aships_s3andhips_s4.
[[profile.region]]
id = "glute_r_s2"
submesh = 2
select = "sphere"
center = [0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
- A sphere inside the right glute (+X is V's right; −Y is behind), found by picking the middle of the glute in the Inspector and moving inwards. Full weight within 3 cm of the centre (
radius − falloff), fading to nothing at 10 cm. - It reaches bands 2, 3 and 4, so it is written three times; Mirror X gives the left side,
glute_l_*, atx = -0.075. That makes six glute regions. - The ids start with
glute_randglute_l, so the Physics tab's preview also jiggles exactly these areas.
The sliders
[[profile.slider]]
id = "hips_smoothing"
label = "Smoothing"
description = "Blends the Hips sliders into the body around them. 0 is off."
group = "Hips"
min = 0.0
max = 4.0
default = 1.0
smooth = { iterations = 120 }
Smoothing comes first, so it leads the Hips section. It starts at 1 (30 passes) and goes up to 4 (120 passes), like the default set's. Its default isn't 0, which is fine for a smoothing slider: on its own it changes nothing.
[[profile.slider]]
id = "hip_width"
label = "Hip Width"
description = "Makes the hips wider or narrower."
group = "Hips"
min = -1.0
max = 1.0
[[profile.slider.key]]
at = -1.0
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s2"
pivot = [0.0, -0.03, 1.02]
scale = [0.9, 1.0, 1.0]
- A two-sided slider:
defaultandrestare left at 0, with keys at both ends. - The key at −1 scales the hips to 90% across (
scaleX 0.9, Y and Z unchanged) about a pivot on the centre line, in the middle of the hips, so both sides move in evenly. The same operation follows forhips_s3andhips_s4. - The key at 1 does the same with
scale = [1.12, 1.0, 1.0]: 12% wider, about 2 cm on each side at full weight.
[[profile.slider]]
id = "glute_size"
label = "Glute Size"
description = "Fuller glutes."
group = "Hips"
min = 0.0
max = 1.0
[[profile.slider.key]]
at = 1.0
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_r_s2"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
- A one-sided slider from 0 to 1 with one key at 1: a classic blend shape.
inflatepushes the surface out by up to 1.5 cm (distance), times the region's weight: about 1 cm where the skin is, since the full-weight core sits inside the body.hold_centerkeeps the two glutes from pushing into each other;facing = [0.0, -1.0, 0.0]limits the push to surfaces that face backwards, so the front of the hips doesn't swell.- The same operation follows for the other five glute regions.
Trying it
Save the whole file below as hips_and_glutes.punks in %APPDATA%\cp-slider\config\configs, load any of female V's bodies and pick Hips and Glutes. Then make it yours: raise max to 3 and add a key at 3 with a bigger push and a wider falloff, or add a slider of your own.
The whole file
# The worked example from the slider set guide (Help > Documentation >
# Making your own slider set). Measured on the game's feminine player body.
[config]
name = "Hips and Glutes"
format_version = 2
author = "Your Name"
description = "Hip Width and Glute Size for female V, with smoothing."
[[profile]]
name = "Player body (feminine)"
depot_paths = [
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full.mesh',
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full_breast_big.mesh',
'base\characters\common\player_base_bodies\player_female_average\t0_000_pwa_base__full_breast_small.mesh',
]
vertex_counts = [1011, 257, 367, 514, 988, 260, 396, 848, 939, 942, 8192, 648]
fixed_submeshes = [8, 9, 10, 11]
keep_sides = true
# The hips cross three of the body's bands (submeshes 2, 3 and 4), so the
# same box is written once for each.
[[profile.region]]
id = "hips_s2"
submesh = 2
select = "box"
min = [-0.25, -0.20, 0.97]
max = [0.25, 0.15, 1.08]
falloff = 0.08
[[profile.region]]
id = "hips_s3"
submesh = 3
select = "box"
min = [-0.25, -0.20, 0.97]
max = [0.25, 0.15, 1.08]
falloff = 0.08
[[profile.region]]
id = "hips_s4"
submesh = 4
select = "box"
min = [-0.25, -0.20, 0.97]
max = [0.25, 0.15, 1.08]
falloff = 0.08
# One sphere per glute (+X is V's right), again once per band.
[[profile.region]]
id = "glute_r_s2"
submesh = 2
select = "sphere"
center = [0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
[[profile.region]]
id = "glute_r_s3"
submesh = 3
select = "sphere"
center = [0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
[[profile.region]]
id = "glute_r_s4"
submesh = 4
select = "sphere"
center = [0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
[[profile.region]]
id = "glute_l_s2"
submesh = 2
select = "sphere"
center = [-0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
[[profile.region]]
id = "glute_l_s3"
submesh = 3
select = "sphere"
center = [-0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
[[profile.region]]
id = "glute_l_s4"
submesh = 4
select = "sphere"
center = [-0.075, -0.1, 0.985]
radius = 0.1
falloff = 0.07
[[profile.slider]]
id = "hips_smoothing"
label = "Smoothing"
description = "Blends the Hips sliders into the body around them. 0 is off."
group = "Hips"
min = 0.0
max = 4.0
default = 1.0
smooth = { iterations = 120 }
[[profile.slider]]
id = "hip_width"
label = "Hip Width"
description = "Makes the hips wider or narrower."
group = "Hips"
min = -1.0
max = 1.0
[[profile.slider.key]]
at = -1.0
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s2"
pivot = [0.0, -0.03, 1.02]
scale = [0.9, 1.0, 1.0]
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s3"
pivot = [0.0, -0.03, 1.02]
scale = [0.9, 1.0, 1.0]
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s4"
pivot = [0.0, -0.03, 1.02]
scale = [0.9, 1.0, 1.0]
[[profile.slider.key]]
at = 1.0
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s2"
pivot = [0.0, -0.03, 1.02]
scale = [1.12, 1.0, 1.0]
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s3"
pivot = [0.0, -0.03, 1.02]
scale = [1.12, 1.0, 1.0]
[[profile.slider.key.op]]
kind = "transform"
region = "hips_s4"
pivot = [0.0, -0.03, 1.02]
scale = [1.12, 1.0, 1.0]
[[profile.slider]]
id = "glute_size"
label = "Glute Size"
description = "Fuller glutes."
group = "Hips"
min = 0.0
max = 1.0
[[profile.slider.key]]
at = 1.0
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_r_s2"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_r_s3"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_r_s4"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_l_s2"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_l_s3"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
[[profile.slider.key.op]]
kind = "inflate"
region = "glute_l_s4"
distance = 0.015
hold_center = true
facing = [0.0, -1.0, 0.0]
Punk//Body Studio v0.3.0 · Freeware: free to use and to share unmodified, free of charge (Help > About > Licence) · Not affiliated with CD PROJEKT RED. Cyberpunk 2077 is a trademark of CD PROJEKT S.A.