The Partner Pose Editor
VORPA duo pose is two separate animations played on two separate characters. RedM has no reliable synchronised scene natives on this build, so the second character is not bound to the first — it is placed, by a set of four numbers on the pose. Get those numbers slightly wrong and a couple dances a hand's width apart, or a bow lands behind someone's shoulder.
The pose editor is the tool for getting them right. It moves the partner on screen a step at a time, shows the four numbers as you change them, and writes them where every player will pick them up.
| Command | partneredit, from the F8 console |
| Needs | The selection screen, on a character that has a partner |
| Edits | attach = vector4(right, forward, up, heading) on one duo pose |
| Saves to | partner_poses.json, in the resource folder |
| Permission | ConfigSelector.Partner.editor — a VORP group or an ace |
Opening it
Open the character selection screen on a character that has a partner. The partner has to be visible beside them — the editor checks for the partner ped, not only the pairing.
Open the F8 console and type
partneredit.Close F8. The selection menu hides itself, keyboard focus leaves the page, and the editor's readout appears in the top left.
It opens on whichever duo pose that character is already showing, so you can cycle to the pose you want to fix with E before you start.
The command toggles
Typing partneredit again closes the editor, which is the way out if the keyboard will not cooperate. Backspace does the same thing.
The keys
They are read as controls and as raw Windows key codes, so they work whether or not a panel holds focus. While the editor is open every game control is disabled — nothing you press reaches the character, the menu or the game.
Moving the partner
| Key | Does | Step |
|---|---|---|
| Arrow keys | Move the partner, as seen on screen | 0.02 m |
PgUp / PgDn | Raise / lower the partner | 0.02 m |
Q / E | Turn the partner | 2.0 degrees |
Shift (hold) | Small steps | 0.005 m, 0.5 degrees |
Hold a key for 350 ms and it starts repeating every 60 ms, which covers a long move without hammering the key. Tapping is how you place the last centimetre.
The arrows are screen-relative, not character-relative
Right means right as you are looking at it, worked out from the rendered camera every time you press. So swinging the camera with A / D changes what the arrows do — and a side-on view is much better than a head-on one for judging how far apart two people are standing.
Moving the camera
| Key | Does | Rate |
|---|---|---|
A / D | Swing the camera around the middle of the pair | 60 degrees a second |
W / S | Closer / further | 1.5 m a second |
Shift (hold) | A quarter speed on both |
The camera orbits the midpoint between the two characters and keeps its tilt, so it stays aimed at the pair as it travels. Distance is clamped between 0.6 m and 12.0 m.
Poses, saving, closing
| Key | Does |
|---|---|
Z / X | Previous / next pose in this character's list |
Enter | Save this pose |
R | Undo to the last save |
Backspace | Close, dropping anything unsaved |
Z and X walk the whole list for the pairing type — all 8 lover poses or all 12 friend ones, unfiltered, including any marked as needing a prop. The list wraps at both ends.
R reverts the pose on screen to its last save. For a pose that has never been saved with the editor, that means back to the numbers in animations.lua.
A key you were already holding is ignored until you let go
The editor records which of its keys are down at the moment it opens and refuses them until they are released. If you held Enter to close the F8 console, Enter does nothing until you lift it.
The readout
Five lines in the top left, above the key hints:
PARTNER POSE EDITOR
Pose 6 / 12: Fancy bow (friend)
Right -0.003 Forward 2.260 Up 0.000 Turn 180.0
NOT SAVED - press Enter to saveRight, Forward, Up and Turn are the four components of attach, in that order and in the same units you would write in animations.lua. The fourth line is either a green Saved or an orange NOT SAVED, compared against what is actually on disk rather than against what you last pressed.
The pose restarts itself as you nudge
Moving a ped in RedM cancels whatever task it is running, so every nudge would stop the animation. The editor replays the pose 400 ms after your last keypress instead of on every step, and holds the camera still while it does — otherwise each replay would re-frame the shot under you. Picking a different pose with Z / X lets the framing through once.
What a save does
Enter sends the pose's kind, its label and the four numbers to the server. The server re-checks your permission, confirms the label exists in ConfigSelector.Partner.animations, range-checks the numbers, rounds the three distances to three decimals and the heading to one, wraps the heading into 0–360, and then does four things:
- Writes
partner_poses.jsonin the resource folder. The file does not ship; the first save creates it. - Sends the new numbers to every connected player at once. No restart, no resource reload.
- Takes precedence over the
attachinanimations.luafrom that moment on. This is the part worth reading the next section about. - Prints the pasteable line in your F8 console, so you can move the value into
animations.luaby hand if you would rather keep it in config:
[vorp_character:poseeditor] saved Fancy bow: attach = vector4(-0.003, 2.260, 0.000, 180.0)The server console gets its own line naming who saved what, which is the audit trail if two people are tuning poses on the same server:
[vorp_character:poseeditor] Hosea saved friend / Fancy bow -> -0.003, 2.260, 0.000, 180.0Each pose is saved separately. Z and X move you to the next pose without saving the one you were on, and the readout is the only thing telling you so.
When a save is refused
| Console message | Means |
|---|---|
you are not allowed to use the pose editor | Your group and ace both failed, re-checked on every save |
unknown pose | No pose with that label in the list for that kind |
bad numbers | One of the four values was not a number |
numbers out of range | Over 5 m right or forward, or 3 m up |
could not write partner_poses.json | The resource folder is not writable |
The range limits are a guard, not a working constraint — 0.02 m steps cannot reach 5 m in a session, so they only trip on a hand-edited file or a tampered client.
Precedence: partner_poses.json beats animations.lua
This is the single thing most likely to waste an afternoon. Once a duo pose has been saved with the editor, editing its attach in animations.lua changes nothing.
Here is why. One second after the resource starts, each client asks the server for the file and writes every saved value straight into the pose table in memory — setting attach and clearing sharedOrigin. From then on the pose behaves exactly as though those numbers had always been in animations.lua. Your edited file is still read at startup; it is overwritten a moment later for any pose the JSON names.
When at least one pose is replaced, your F8 console says so on connect:
[vorp_character:poseeditor] 3 duo pose(s) set with the pose editorThat line is how you tell whether the file is in play before you go looking for a bug in config.
The full order
Where the partner stands is resolved like this, highest first:
A matching entry in
partner_poses.json, found by pairing type and the pose'slabel.sharedOrigin = trueon the pose, which puts both characters on the same point with the same heading, for clips that carry their own baked movement.attachon the pose entry inanimations.lua.The flat form —
offsetX,offsetY,deltaZ,headingOffset— accepted as an alternative toattachon the same entry.ConfigSelector.Partner.attachfor that pairing type, the defaults beingvector4(0.0, 0.60, 0.0, 180.0)forloverandvector4(0.0, 1.05, 0.0, 180.0)forfriend.
A saved value also clears sharedOrigin, so the editor can pull a shared-origin pose apart. That is deliberate, and it is one-way — step 2 cannot win back.
The file
{
"lover": {
"Standing together": [-0.021, 0.767, 0.0, 168.0]
},
"friend": {
"Fancy bow": [-0.003, 2.26, 0.0, 180.0],
"Campfire": [1.0, 0.0, 0.0, 0.0]
}
}Two keys, lover and friend, each holding poses by label, each pose holding [right, forward, up, heading].
The label is the key, so renaming a pose orphans its saved numbers
Change label = "Fancy bow" to anything else in animations.lua and the saved entry no longer matches anything. It is skipped in silence — no warning, and the pose quietly falls back to whatever attach is written in config.
Going back to config
To hand a pose back to animations.lua, delete that pose's entry from partner_poses.json — or delete the whole file to hand back all of them — and restart the resource. Clients read the file once at startup, so a file change on its own does not reach anyone already connected.
The tidier route, if you want your poses in version control rather than in a JSON file the next update might not preserve, is the pasteable line each save prints: copy it into the pose's entry in animations.lua, then remove the pose from partner_poses.json. Same numbers, one source of truth.
Back the file up before an update
partner_poses.json lives inside the resource folder, which is the folder you replace when you update. It is on the same list as your config files — see Installation.
Height is sometimes the clip's fault, not the pose's
PgUp and PgDn write into that one pose's attach.z. That is the right fix when one pose sits a little low and everything else is fine.
It is the wrong fix when a particular clip floats everywhere it is used, because the clip was authored above its set's floor and brings that height with it. Those belong in ConfigSelector.Partner.clipOffsets, keyed by the exact clip name or by the dictionary, where a positive value lowers the ped:
clipOffsets = {
["KIT_EMOTE_GREET_FANCY_BOW_1"] = 0.128,
["MP_LOBBY_SCENARIO_06"] = 0.116,
}Those two ship. To find the number for a third, set ConfigSelector.Debug = true, show the pose, and read the console — it prints how far off the ground the partner settled and tells you to add it to clipOffsets. The correction then applies wherever that clip appears, instead of once per pose.
Scenario poses cannot have this problem
The engine places and grounds a scenario itself. If a duo pose keeps fighting you on height, the quickest answer is often a scenario pose from the same list — the reasoning is on Emote library.
Permissions
-- config_selector.lua
ConfigSelector.Partner.editor = {
enabled = true,
command = "partneredit",
groups = { "admin" },
ace = "command",
}| Key | Default | Does |
|---|---|---|
enabled | true | false and the command is never registered at all |
command | "partneredit" | The console command |
groups | { "admin" } | VORP groups allowed to use it |
ace | "command" | An ace that also passes. false for groups only |
Either check is enough. The VORP group comes from the character the player is using, read through vorp_core, so a player's access can change with the character they have loaded. See VORP framework for how groups are set.
The default ace is "command" because that is the blanket command ace txAdmin grants its admins — convenient, and it means the editor works out of the box for anyone who already administers the server from txAdmin. It is also broad. If you want to hand the editor to a builder who should not hold every command ace, name your own:
ace = "vorp_character.partneredit",add_ace group.builder vorp_character.partneredit allowBoth ends are checked
Permission is verified on the server when the editor opens and again on every save, along with the pose name and the numbers. A client that skips the open check still cannot write anything.
Troubleshooting
It says you are not allowed
[vorp_character:poseeditor] you are not allowed to use the pose editorIs your character's group one of
Partner.editor.groups? The default list isadminonly.If you are relying on the ace, is there an
add_principalputting you in the group that holds it? This is the usual answer.Does the ace name in
server.cfgmatchPartner.editor.ace?Did you switch characters? The group is read from the character in use.
partneredit is an unknown command
The command is only registered when editor.enabled is true and editor.command is set. Check both, then check you are looking at the right name — command is yours to rename, and a renamed command means the old one genuinely does not exist.
If neither is it, the resource did not start. The server console on start will say why.
The editor will not open
| Console message | Means |
|---|---|
open the character selector first | You are in the world, not on the selection screen |
the character on screen has no partner | The pairing is missing, or the partner ped is not there |
Partner.sync is off, so duo poses are not used | ConfigSelector.Partner.sync = false |
no duo poses for lover | That list in Partner.animations is empty |
already open | It is already running; Backspace or the command closes it |
The sync one catches people out. With sync = false the partner does not share a pose at all — it stands on its own mark from ConfigSelector.Partner.freeOffset and cycles its own solo poses, so there is no duo pose to line up. Set sync = true to use the editor. Pairing itself is covered on Partner system.
Nothing happens when I press a key
Is F8 still open? The console eats the keyboard. Close it.
Were you holding that key when the editor opened? It is blocked until you release it.
Is the readout on screen at all? No readout means the editor is not open and the keys are going to the selection menu.
Is the number on the readout changing but the partner not appearing to move? Swing the camera side-on with
A/D. A head-on view hides forward and back almost completely.
My changes vanished when I closed
Expected. Backspace reverts every pose you touched back to its last saved numbers and tells you how many it threw away:
[vorp_character:poseeditor] closed, 2 unsaved change(s) droppedEnter saves one pose — the one on screen. Tune four poses, press Enter once, and the other three are gone on close. The orange NOT SAVED line is the warning; it is accurate, and it is checked against the file rather than against your keystrokes.
The same revert runs if the character or the partner disappears while you are editing, in which case the console names that as the reason.
Saved numbers stopped applying
| Cause | Fix |
|---|---|
The pose's label was renamed in animations.lua | Rename it back, or re-save the pose |
The pose was deleted from animations.lua | The saved entry has nothing to attach to |
partner_poses.json is not valid JSON | The server prints is not valid JSON, ignoring it and ignores the whole file |
| The file was lost in an update | Restore it from your backup, or re-save |
A hand-edited file is the usual reason for the third row, and because one bad character disables every pose in the file, the symptom is all of your poses reverting at once rather than one.
Changes do not show for a player already on the screen
The numbers arrive immediately — the pose picks them up the next time it is applied, which is the next time that player cycles poses, changes character, or reopens the screen. Nobody needs to reconnect and nothing needs restarting.
Related: Partner system · Poses · Configuration · Emote library · Troubleshooting
Still stuck? Ask in Discord with your F8 output, your ConfigSelector.Partner.editor block, and the contents of partner_poses.json.