Skip to content

Adding the Dances to an Emote Menu ​

This is the route most servers take, and the one the pack is built for.

rm_dance_24 streams animations and does nothing else. The whole resource is fxmanifest.lua, a data table in clips.lua, a one-line server.lua that prints a startup message, and eight .ycd files in stream/. There is no menu, no command, no key binding, no events and no exports — and no config options either. Players reach the dances through the emote menu your server already runs, or through a script of your own.

The pack's own docs/ folder says the same thing, and in this pack those guides are accurate.

Nothing is missing from your download

All 27 rows in clips.lua are live, nothing is commented out, and every dictionary a row names is present in stream/. "24+" means 24 main dances plus 3 bonus ones. The count is not short — see the dance list.

What an emote menu needs from you ​

Every emote system reduces a custom animation to the same small set of values. Whatever the fields are called in your resource, these are what to put in them:

What the menu asks forWhat to give it
Dictionaryredmorrow_dance_24@dance for the 24 main dances, or that name plus @f for the female version
Clip nameThe clip from the dance list
Flag1 — loop
DurationWhatever the resource uses for "run until stopped", normally -1
Loop settingOn. All 27 dances are loops
Label and categoryYours to choose. The shipped ones are rough — see below

Do not pass the figure from the duration column to the menu as a play time. That number is metadata the pack author wrote into clips.lua; nothing in the resource reads it, and a 2.467 s dance given a 2.467 s duration ends before the player has let go of the key. Use it to sort or label your menu, and let the loop flag decide when the dance stops.

Flags ​

RedM has its own eScriptedAnimFlags values. They are not GTA V's, so a flag word copied out of a FiveM emote resource will not mean here what it meant there.

UseFlag
Loop the dance1
Play once0
Play once and hold the last frame2
Loop upper body only, so the player can walk1 + 8 + 16 = 25

For dances, 1 is almost always what you want. Full value table in Playing a dance.

The 24 main dances ​

One dictionary pair covers all 24:

BodyDictionary
Maleredmorrow_dance_24@dance
Femaleredmorrow_dance_24@dance@f

The clip name is identical in both. Take the 24 clip names from The 24 main dances. In all 24 of these rows the id and the clip name are the same string, so either column works. The one row in the pack where they differ is a bonus dance, below.

A row in a generic emote resource therefore looks like this, with your resource's own field names:

lua
{
    label    = 'Samba Dancing',
    command  = 'samba',
    dict     = 'redmorrow_dance_24@dance',
    clip     = 'samba_dancing',
    duration = -1,
    loop     = true,
}

The 3 bonus dances ​

These are the exception. Each one has its own pair of dictionaries, not the main pair:

DanceMale dictionaryFemale dictionaryClipLength
Chicken Dancednac@chicken_dancednac@chicken_dance@fchicken_dance4.767 s
Jazz Dancing (2)dnac@jazz_dancingdnac@jazz_dancing@fjazz_dancing2.033 s
Dancing Twerkdnac@dancing_twerkdnac@dancing_twerk@fdancing_twerk15.2 s

Same flag, same duration handling as the other 24. The only difference is the dictionary string.

Two different dances use the clip name jazz_dancing

This is exactly the place where it bites.

  • The row with id jazz_dancing_2 is the clip jazz_dancing inside dnac@jazz_dancing.
  • The row with id jazz_dancing is a different dance: the clip jazz_dancing inside redmorrow_dance_24@dance.

A menu that keys its rows on the clip name alone will collide, and one of the two dances will quietly disappear from your list or overwrite the other. Key on the id, or on the dictionary and clip name together.

This is the only row in the pack whose id differs from its clip, and the only clip name used twice. Every other row has id == clip.

Handling both bodies ​

Every dance ships twice: a version fitted to the male body and one fitted to the female body. The female dictionary is always the male name plus @f, with the same clip names inside. That holds for all 27 rows without exception — in every row bodies.male is the dict field and bodies.female is that string plus @f.

Both versions play on either body. Neither one breaks. The matching one fits better.

If your menuThen
Supports a per-body dictionaryPoint female characters at the @f dictionary
Does notAdd each dance twice, labelled "(M)" and "(F)", or use the male version for everyone

Adding each dance twice turns 27 rows into 54 and puts the choice on the player, which is honest but noisy. Using the male version for everyone is a legitimate choice if your menu cannot branch; it looks slightly off on female characters rather than wrong.

If your menu hands the dance to a function of yours, pick the dictionary there:

lua
-- GET_META_PED_TYPE returns 0 for male and 1 for female.
-- Compare the number: 0 is truthy in Lua, so testing it as a boolean is wrong.
-- IsPedMale may come back as 0/1 rather than true/false on RedM, so handle both.
local function isFemale(ped)
    if GetMetaPedType then
        local ok, t = pcall(GetMetaPedType, ped)
        if ok and t == 1 then return true end
        if ok and t == 0 then return false end
    end
    local male = IsPedMale(ped)
    return not (male == true or (type(male) == 'number' and male ~= 0))
end

local function dictFor(row, ped)
    if isFemale(ped) then return row.dict .. '@f' end
    return row.dict
end

Appending @f is safe in this pack precisely because the pairing is mechanical in all 27 rows. That is not true of every RedMorrow pack — in 100+ Female Poses, seven dictionaries are named after a different pose than their id, so names there must be read from the table rather than built.

Groups, if your menu uses them ​

The category field in clips.lua is lopsided:

CategoryRows
dance24
Chicken Dance1
Jazz Dancing1
Dancing Twerk1

Grouping straight from that field gets you one group of 24 and three groups of one, with inconsistent capitalisation between them. Put all 27 in a single Dances group in your menu instead, or rewrite the field — category is one of the fields you are allowed to change. Details in Categories.

With RedM Emotes ​

RedM Emotes stores its library as rows, and each row carries a dictionary and a clip name. That is all these dances need, so they drop in like any other custom dictionary: one row per dance, with the dictionary and clip from the tables above, the loop setting on, and a label of your choosing.

The three supported ways to add a row, the exact column names, and the cache rebuild you need afterwards are documented at Three ways to add an emote. Nothing about this pack changes that procedure.

Start the pack before your emote menu ​

The dictionaries have to exist on the client before a player opens the menu and picks a dance. Order in server.cfg is the simplest way to guarantee that:

cfg
ensure rm_dance_24
ensure your_emote_menu

The ensure line follows the folder name, not the manifest

In CFX the resource name is the directory name. The folder is rm_dance_24, so ensure rm_dance_24 is the correct line.

The name field inside fxmanifest.lua is redmorrow_dance_24, and that is metadata — it renames nothing. It is also why the startup message reads:

text
[redmorrow_dance_24] Dance animation pack started.

Do not copy that bracketed name into your server.cfg. More in Installation.

Generating the rows instead of typing 27 ​

Twenty-seven rows is past the point where hand-typing is a good use of an evening, and hand-typing is where the jazz_dancing collision turns into a bug. Generate them from the pack's own table.

clips.lua sets a global called Config inside rm_dance_24's own Lua state. CFX gives every resource its own state, so your emote resource cannot read Config.Clips directly and there are no exports to hand it over. There are two ways round that: copy the rows, or load the file and read it in a sandbox of your own.

clips.lua is listed in escrow_ignore, so it ships readable on disk, which is what makes the second option work:

lua
-- Reads rm_dance_24's own clip list. Returns an empty table if the pack is
-- not installed or the file will not parse.
local function getDanceClips()
    local src = LoadResourceFile('rm_dance_24', 'clips.lua')
    if not src then return {} end

    local env = { Config = {} }
    local chunk = load(src, '@rm_dance_24/clips.lua', 't', env)
    if not chunk or not pcall(chunk) then return {} end

    return env.Config.Clips or {}
end

The sandboxed env is the point: the file assigns to Config, and running it inside env keeps that assignment out of your own globals while still giving you the table.

Then print the rows in whatever shape your menu's config wants, and copy them out of the console:

lua
RegisterCommand('dancedump', function()
    local clips = getDanceClips()

    for _, c in ipairs(clips) do
        print(("    { id = '%s', label = '%s', dict = '%s', clip = '%s', duration = -1, loop = true },")
            :format(c.id, c.label, c.dict, c.clip))
    end

    print(('-- %d rows'):format(#clips))
end, false)

Change the format string to emit your resource's field names, or a SQL INSERT, or a JSON array. Add c.dict .. '@f' to the line if you want the female dictionary in the same row. The output lands in the console of whichever side you ran the command on.

#clips is 27 and the array is contiguous

Nothing in clips.lua is commented out, so there is no filtering to do and no gap to skip. If you get a number other than 27, the folder name in LoadResourceFile does not match what is on disk — it takes the folder name, rm_dance_24, not the manifest name.

Read dict off the row — do not build it from the id

'redmorrow_dance_24@dance' is right for 24 of the 27 rows and wrong for the three bonus dances, which live in dnac@... dictionaries. A clip requested from a dictionary that never loaded fails silently: no error in the server console, nothing in F8, the character just stands there. Those three would look like broken menu entries with no clue as to why.

Check one dance before you add all 27 ​

  1. Confirm the pack streamed. In the F8 client console:

    lua
    DoesAnimDictExist('redmorrow_dance_24@dance')

    true means the dictionaries reached the client. false means the resource is not started, the ensure line does not match the folder, or the asset-pack entitlement check failed. See Troubleshooting.

  2. Add one row to your emote menu's config — samba_dancing out of redmorrow_dance_24@dance, flag 1.

  3. Restart the emote resource, not just the pack. Most emote menus read their config once at start and will not see your edit until they do.

  4. Play it, then play it on a female character with the @f dictionary, so you have seen both bodies work before you paste in the other 26.

  5. Add the rest, generated rather than typed.

Editing clips.lua does not change your emote menu ​

The two lists are separate, and this is the single most common misunderstanding about packs shaped like this one.

clips.lua is a reference list that ships with the pack. Your emote menu has its own config, its own database table or its own file. Renaming a dance in clips.lua renames it in clips.lua and nowhere else — the names have to be copied into the menu's own config as well. Equally, nothing in rm_dance_24 reads your menu, so the pack cannot break it.

What you may and may not change in that file is covered in The clips.lua table. The short version: label, category, mode and walk are yours; dict and clip are not, because an RDR2 dictionary stores its own name inside the .ycd file.

Next ​

Still stuck? Ask in Discord.

Documentation for RedMorrow. Scripts are licensed per server — redistribution is not permitted.