Props & Shared Emotes
Nine emotes ship outside the database, defined in shared/extras.lua. They are config-defined because they carry nested data — prop offsets, partner animations — that does not fit the flat table schema.
| Kind | Count | Shipped |
|---|---|---|
shared | 4 | Dance Together, Take Hostage, Pet Dog (Standing), Pet Dog (Sitting) |
prop | 5 | Carry Basket, Fan (Right Hand), Fan (Left Hand), Parasol, Dog Bone |
These rows are not in rm_emotes and never will be
They are read from shared/extras.lua at load. They cannot be starred, /e random never picks them, and PlayById cannot reach them. They do appear in the Recent tab, resolved against their synthetic ids — so reordering shared/extras.lua makes an existing recent entry point at a different extra. Prop emotes hover-preview normally; shared emotes never do, because they need a partner. See the editor quirk below.
The entry shape
RM.Extras = {
{
kind = 'shared',
name = 'Dance Together',
animation = { dict = '...', name = 'arthur_dance_loop', flag = 1 },
partner = {
offset = { x = 0.2, y = 0.5, z = 0.0, w = 155.0 },
animation = { dict = '...', name = 'karen_dance_loop', flag = 1 },
},
},
}| Field | Meaning |
|---|---|
kind | 'prop' or 'shared' |
name | The label on the card |
animation | { dict, name, flag } — flag 1 = full body, 25 = keep control |
prop | { model, bone, position {x,y,z}, rotation {x,y,z} } |
partner | { offset {x,y,z,w}, animation {...} } — w is the heading offset |
Prop emotes
A prop emote attaches a model to a bone and plays an animation. Most ship with flag = 25, which keeps player control — so you can walk around holding the item. Dog Bone is the exception: it ships with no animation block at all, so it attaches the prop and nothing else — and there is nothing for the mannequin to hover-preview.
A maintain loop runs while the emote is active. If the game ever drops the prop or the animation stops, both are restored automatically. The prop is removed when you stop the emote.
Playing a normal animation while holding a prop ends the prop emote first.
Adding your own
{
kind = 'prop',
name = 'Coffee Cup',
prop = {
model = 'p_cup02x',
bone = 'SKEL_R_Finger12',
position = { x = 0.07, y = 0.02, z = 0.04 },
rotation = { x = -20.0, y = 0.0, z = 0.0 },
},
animation = { dict = 'amb_wander@...', name = 'base', flag = 25 },
},Restart the resource afterwards. Getting position and rotation right is trial and error — the shipped entries are the best reference, since each was tuned against a real bone.
Shared emotes
A shared emote needs a second ped. The closest one within RM.Shared.range (3 metres by default) is picked automatically.
If the partner is a player:
- They see floating text above the requester's head:
<name> wants <emote> — [E] accept / [R] decline. Eaccepts,Rdeclines.- No answer within
RM.Shared.timeout(8000 ms) auto-declines, and the requester sees<name> declined your request. - On accept the partner is moved into position and both animations start together.
If the partner is an NPC or an animal — which is what the Pet Dog emotes are for — there is no prompt. The ped is placed and both animations start immediately.
If nothing is in range you get "Nobody in range". Either player stopping ends it for both.
The partner.offset w value is a heading offset, which is why Dance Together places the partner at 155° rather than facing straight on.
The admin editor quirk
Prop and shared entries appear in the Admin tab's list, carrying synthetic ids from 90000.
Editing them there does nothing
Clicking one opens the form and saving appears to succeed — but it affects zero database rows, because these entries do not live in the database. The Discord webhook still logs "Emote updated" or "Emote deleted".
Edit them in shared/extras.lua instead.
Never store a synthetic id
They are generated at runtime starting at 90000 and are not stable across config edits. Adding one entry renumbers the ones after it.
Reaching them from another resource
PlayById searches only the database-backed library, so it cannot reach these. PlayByCommand can — it searches the database library first, then the prop and shared rows:
exports.rm_emotes:PlayByCommand('carrybasket')See the Developer API.
Security note for shared emotes
Be honest with yourself about the boundary here.
The two-ped relays are trust-on-first-use. The requested animation definition is forwarded verbatim and played on the receiving client without checking that the receiver ever sent a request, and the stop relay cancels a target's active prop or shared emote with no pairing check. A modified client can therefore push an animation onto, or interrupt, another player.
Accepting a shared request also teleports the accepting player to the requester — but that path does require the victim to press accept, and a pending request expires after RM.Shared.timeout.
Server-side validation on these relays is limited to "the target is a different, connected player and the payload is a table". Do not build anything that matters on top of them.