Skip to content

Adding 30+ Dances to an Emote Menu ​

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

redmorrow2 streams animations and does nothing else. The whole resource is fxmanifest.lua, a data table in clips.lua, two .ycd files in stream/, and the documentation. There is no menu, no command, no key binding, no events, no exports and no config options. Players reach the dances through the emote menu your server already runs, or through code of your own.

The pack's own three guides in docs/ say the same thing, and for this pack they are accurate.

The manifest loads no scripts at all

fxmanifest.lua has no client_scripts and no server_scripts. This is the structural fact that shapes the whole page:

  • clips.lua is never loaded. Config.Clips does not exist at runtime, on the client or on the server, and clients never download the file. It is a reference document that happens to be valid Lua.
  • stream/ is picked up automatically by CFX without a manifest entry, which is why the pack works with no scripts.
  • There is no server.lua, so the pack prints no startup message of its own. The server console shows only the ordinary start line.

To read the list programmatically you have to load it from disk yourself — see Generating the rows.

Nothing is missing from your download

All 34 rows in clips.lua are live and nothing is commented out. Both dictionaries are present in stream/, both are referenced, and every clip name resolves. "30+" means 34, so the count is not short. The full list is on 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
Dictionaryredmorrow2@dance, or redmorrow2@dance@f for the female version
Clip nameThe clip from Dance list
Flag1 — loop
DurationWhatever the resource uses for "run until stopped", normally -1
Loop settingOn. All 34 dances are mode = 'loop'
Blend-in, if exposed4.0, or 2.0 for the six floor moves
Label and categoryYours to choose

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. -1 means no time limit — with the loop flag the dance runs until something stops it.

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 these dances, 1 is almost always what you want. The individual values are LOOPING 1, HOLD_LAST_FRAME 2, NOT_INTERRUPTABLE 4, UPPERBODY 8, SECONDARY 16 and ABORT_ON_PED_MOVEMENT 32; the mode field maps as 'loop' = 1, 'hold' = 2, 'once' = 0, with 8 + 16 added when walk is set. No row in this pack sets walk or flags.

Upper-body play looks wrong on these

These are full-body moves, breakdance especially. Flag 25 keeps the legs on the walk animation while the arms dance, which is useful for a wave or a salute and visibly broken on a headspin. Use 1 and let the dance own the whole body.

Two dictionaries, 34 clips, no exceptions ​

BodyDictionary
Maleredmorrow2@dance
Femaleredmorrow2@dance@f

That is the entire mapping. All 34 dances are in both dictionaries, under identical clip names. There are no per-dance dictionaries, and in every row dict equals bodies.male while bodies.female equals bodies.male with @f appended.

The naming is equally plain. Every row has id equal to clip, and no id, clip name or label is repeated anywhere in the pack. The clip name is the id, so there is nothing to derive and nothing to key around: a menu that stores rows by clip name works, and so does one that stores them by id.

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

lua
{
    label    = 'Moonwalk',
    command  = 'moonwalk',
    dict     = 'redmorrow2@dance',
    clip     = 'moonwalk',
    duration = -1,
    loop     = true,
}

Thirty-three more rows differ from that one in three strings.

Handling both bodies ​

Every dance ships twice: a version fitted to the male body and one fitted to the female body. Both versions play on either body. Neither one breaks. The matching one fits better — a male-fitted dance on a female character reads as slightly off rather than wrong.

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

Adding each dance twice turns 34 rows into 68 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.

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 34 rows. More on the native side of this in Scripting the pack.

The six floor moves ​

Six moves begin on the ground rather than standing, and clips.lua gives each of them blendIn = 2.0 — about half a second — instead of the 4.0 every other row uses. The slower blend-in makes the character ease down to the floor instead of snapping to it.

ClipName
crossleg_freezeCrossleg Freeze
flair_1Flair (1)
breakdance_footwork_1Breakdance Footwork 1
breakdance_footwork_3Breakdance Footwork 3
breakdance_footwork_to_freezeBreakdance Footwork To Freeze
breakdance_footwork_to_idleBreakdance Footwork To Idle

All six are in the breakdance group. If your emote menu exposes a blend-in setting, set 2.0 on these six rows and leave the other 28 at 4.0. If it does not expose one, they still play — they just arrive hard, and that is a cosmetic problem rather than a broken entry.

blendIn is the only optional field this pack uses. Lengths and the rest of the per-row detail are on Floor moves.

Groups, if your menu uses them ​

The resource's server owner guide suggests three groups, and they are worth applying because the split is exact and complete: 20 + 6 + 8 = 34, and every clip is in exactly one group.

GroupCountClips
Breakdance20breakdance_ready, breakdance_uprock, breakdance_uprock_var_1_start, breakdance_uprock_to_ground, breakdance_1990, breakdance_1990_1, breakdance_footwork_1, breakdance_footwork_3, breakdance_footwork_to_freeze, breakdance_footwork_to_idle, breakdance_swipes, flair, flair_1, headspin_start, breakdance_freezes, breakdance_freeze_var_1, breakdance_freeze_var_2, breakdance_freeze_var_3, breakdance_freeze_var_4, crossleg_freeze
Hip hop6wave_hip_hop_dance, wave_hip_hop_dance_1, tut_hip_hop_dance, booty_hip_hop_dance, slide_hip_hop_dance, step_hip_hop_dance
Party8moonwalk, can_can, hokey_pokey, twist_dance, shopping_cart_dance, butterfly_twirl, bellydancing, silly_dancing_1

The split is not in the category field

Every one of the 34 rows carries category = 'dance' — a single flat category. The three groups above are prose in the resource's server owner guide, not data you can read. A menu built straight from category gets one undifferentiated list of 34.

Use the table above in your menu's own config, or rewrite category in clips.lua first and generate from that. category is one of the fields you are allowed to change — see The clips.lua table.

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 redmorrow2@dance (or redmorrow2@dance@f) as the dictionary, the clip name from the dance list, 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, and because every row here has one dictionary pair and one clip name per dance, there is no special case to work around.

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:

cfg
ensure redmorrow2
ensure your_emote_menu

Streaming does not actually depend on start order — CFX collects stream/ whenever the resource starts — so position in server.cfg is not critical. Putting the pack first is a habit worth keeping anyway, because it rules the question out when you are debugging something else. Download, upload and entitlement are on Installation.

Generating the rows instead of typing 34 ​

Thirty-four rows is past the point where hand-typing is a good use of an evening. Generate them from the pack's own table instead.

This is the one place where the missing client_scripts line matters in practice. In a pack that loaded clips.lua, you could read a global or call an export. Here Config.Clips never exists at runtime, so a script has to read the file from disk and parse it. clips.lua is listed in escrow_ignore, so it ships readable, which is what makes this work.

LoadResourceFile is server-side, so the shape is: read it on the server, hand it to clients over an event.

Server side, in your own resource:

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

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

    return env.Config.Clips or {}
end

local danceClips = getDanceClips()

RegisterNetEvent('mydances:requestClips', function()
    TriggerClientEvent('mydances:clips', source, danceClips)
end)

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

Client side, in the same resource:

lua
local danceClips = {}

RegisterNetEvent('mydances:clips', function(clips)
    danceClips = clips
    -- build your menu rows here
end)

CreateThread(function()
    TriggerServerEvent('mydances:requestClips')
end)

Rename the mydances:* events to fit your resource. Read it once at server start rather than per request; the file does not change while the server runs.

If your menu wants rows in a config file instead, print them and copy the output:

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

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

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

Change the format string to emit your resource's field names, a SQL INSERT, or a JSON array. Add c.dict .. '@f' to the line if you want the female dictionary in the same row, and c.blendIn or 4.0 if your menu takes a blend-in.

#clips is 34 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 0, the pack is not installed where LoadResourceFile is looking — it takes the resource name redmorrow2, which is both the folder name and the manifest name.

Check one dance before you add all 34 ​

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

    lua
    DoesAnimDictExist('redmorrow2@dance')

    true means the dictionaries reached the client. false means the resource is not started or the asset-pack entitlement check failed — see Troubleshooting.

  2. Add one row to your emote menu's config: moonwalk out of redmorrow2@dance, flag 1, duration -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 redmorrow2@dance@f, so you have seen both bodies work before you paste in the other 33.

  5. Try one floor move — crossleg_freeze — so you know whether your menu lets you soften the blend-in.

  6. Add the rest, generated rather than typed.

A clip from a dictionary that never loaded fails silently

No error in the server console, nothing in F8, the character just stands there. That is why step 1 is worth the ten seconds: it separates "the pack is not reaching the client" from "my menu row is wrong", and those two have nothing in common except the symptom.

Editing clips.lua does not change your emote menu ​

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

clips.lua is a reference list that ships with the pack, and here the manifest does not even load it. 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 new name has to be copied into the menu's own config as well. Equally, nothing in redmorrow2 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.