Skip to content

The 30+ Dances clips.lua Table ​

clips.lua lists all 34 dances with their dictionary, clip name, length and play mode. It is the file you read when you are wiring the pack into something, and it is the only Lua file in the download you can open.

It is also never loaded.

The manifest does not load it ​

fxmanifest.lua has no client_scripts block and no server_scripts block. Not an empty one — no block at all. The whole manifest is the fx_version / game / lua54 header, the name and version fields, an escrow_ignore list and dependency '/assetpacks'.

That single fact sets this pack apart from every other RedMorrow animation pack, and three consequences follow from it:

Config.Clips does not exist at runtimeNot on the client, not on the server, not inside redmorrow2 itself
Clients never download clips.luaIt is not a client script, so it is not in the manifest's file list
The pack prints no startup lineThere is no server.lua to print one

stream/ is picked up automatically by CFX without needing a manifest entry, which is why a pack with no scripts of any kind still works. The animations stream, the dictionaries exist in game, and nothing anywhere consults this table.

So clips.lua is a reference document that happens to be valid Lua. Copy the names out of it, or load it from disk yourself — see Reading the table from your resource.

Rows34
Live entries34
Commented out0
Global it would setConfig.Clips
Loaded asNothing. The manifest has no script blocks
SizeAbout 11 KB

What ships, and what is readable ​

escrow_ignore in the manifest lists four entries:

lua
escrow_ignore {
    'clips.lua',
    'README.md',
    'CHANGELOG.md',
    'docs/*.md',
}

The last is a glob over three guides, so six files in the download stay plain, readable text. clips.lua is the only Lua file among them. fxmanifest.lua is readable as a matter of course. The only protected files are the two .ycd dictionaries in stream/, which come to about 2.9 MB.

There is no server.lua, no client.lua, no config.lua and no html/ folder. There is also no LICENSE.md — what you may and may not do with the pack is covered in docs/CUSTOMER_GUIDE.md in your download, under its own heading.

The customer guide has one unfilled placeholder

docs/CUSTOMER_GUIDE.md lists its support contact as [DISCORD LINK]. The real link is discord.gg/w4Ew4k3Exn. Everything else in the three guides matches the rows and matches the build.

What reads it ​

Nothing, on either side.

The pack has no menu, no chat command, no key binding, no event, no export and no config. Players reach the dances through an emote menu your server already runs, or through code you write. Every field below is metadata waiting for that code. Scripting the pack covers the native call; Emote menus covers wiring the names into a menu you already have.

The resource's own three guides state this correctly. They are worth reading and they are not stale.

One row ​

Every entry is a single-line table, flat, with the same nine keys in the same order, plus a tenth, blendIn, on six of them:

lua
{ id = 'moonwalk', label = 'Moonwalk', dict = 'redmorrow2@dance', clip = 'moonwalk',
  category = 'dance', duration = 1.033, mode = 'loop', rootMotion = false,
  bodies = { male = 'redmorrow2@dance', female = 'redmorrow2@dance@f' } },

The whole file is a header comment, two statements and a table:

lua
Config = Config or {}

Config.Clips = {
    -- 34 rows
}

It declares no functions, registers no events, starts no threads and exports nothing. It assigns a literal and stops.

Once you have loaded it yourself, Config.Clips is a plain array: #Config.Clips is 34 and ipairs walks it in file order. That order is neither alphabetical nor grouped — breakdance, hip hop and party rows are interleaved, and the first nine rows alone cover all three groups. Do not rely on position. Look rows up by id.

Fields ​

FieldTypeMeansRead by anything?
idstringThe key you look a dance up by. Unique across the tableNo
labelstringA display name for a menu or listNo
dictstringThe animation dictionary — the .ycd filename without the extension. Always the male versionThis is the value you pass to RequestAnimDict
clipstringThe clip name inside that dictionaryThis is the value you pass to TaskPlayAnim
categorystringA grouping key for a menu. 'dance' in every rowNo
durationnumberLength in secondsNo
modestringSuggested playback: 'loop' in every rowNo
rootMotionbooleantrue would mean the clip moves the character. false in every rowNo
bodiestable{ male = dict, female = dict .. '@f' }No
walkboolean, optionaltrue = upper body only, so the player keeps walking. Not present on any rowNo
flagsnumber, optionalRaw RDR3 TaskPlayAnim flags; overrides mode and walk. Not present on any rowNo
blendInnumber, optionalBlend-in delta for full-body play. Set to 2.0 on six rowsNo

Only dict and clip have any mechanical meaning, and that meaning comes from the .ycd files, not from this table. The rest are labels for whatever interface you build.

Values that are identical in all 34 rows ​

FieldValue
mode'loop'No 'once' and no 'hold' entries
rootMotionfalseNo dance moves the character off its mark, the moonwalk included
category'dance'One flat category across the whole pack
dict'redmorrow2@dance'The male dictionary, in every row
bodiesboth keys presentmale equals dict, female equals dict plus @f

id always equals clip ​

All 34 rows have id equal to clip. There are no duplicate ids, no duplicate clip names and no duplicate labels anywhere in the pack.

That means there is nothing to derive and nothing to disambiguate: the clip name is the id, and a menu or a database keyed on either one is safe. It is still worth keying on id as a habit, because that is the field the format promises to keep unique.

This differs from the sibling pack

24+ Dances ships three bonus dances out of their own dnac@ dictionaries and has a clip name that appears twice, so one of its rows carries an id that does not match its clip. This pack has no such case. Do not carry that pack's lookup caveats across.

blendIn is the one optional field this pack uses ​

Exactly six rows set blendIn = 2.0 — about half a second — instead of the 4.0 used everywhere else. All six start on the ground rather than standing, and a slower blend-in makes the character ease down instead of snapping to the floor:

idLength
crossleg_freeze2.033 s
flair_11 s
breakdance_footwork_13.167 s
breakdance_footwork_34.567 s
breakdance_footwork_to_freeze3.667 s
breakdance_footwork_to_idle9.6 s

All six are in the breakdance group. The same list, with the reasoning, is on Floor moves.

walk and flags are legal fields that the header comment documents, and no row in this pack carries either. Both are safe to add if you write code that honours them. Nothing in the pack will.

mode, and how it maps to flags ​

mode is advisory. The mapping the header comment intends is:

modeFlags
'loop'1
'hold'2
'once'0

With walk = true, add 8 + 16. The RDR3 eScriptedAnimFlags values are LOOPING 1, HOLD_LAST_FRAME 2, NOT_INTERRUPTABLE 4, UPPERBODY 8, SECONDARY 16 and ABORT_ON_PED_MOVEMENT 32. These are RDR3's values — the flag values differ from GTA V's, so a flag word copied out of a FiveM script will not mean the same thing here.

Upper-body play looks wrong on these dances

Looping upper-body so the player can still walk is 1 + 8 + 16 = 25, and it is a good trick on a wave or a salute. These are full-body moves, breakdance especially — the legs are most of the animation. Played at 25 the character walks around with its arms doing a freeze. Leave them at 1.

duration ​

A number the pack author wrote down, not something measured from the .ycd at runtime. Nothing reads the field — the manifest never loads the file — so the game is the authority and GET_ANIM_DURATION gives the real figure.

Shortestflair_1 at 1 s
Longestbellydancing at 25.367 s
Median4.133 s
Total205.0 s across all 34

Four rows run under a second and a half — flair_1 at 1 s, moonwalk at 1.033 s, wave_hip_hop_dance_1 at 1.167 s and breakdance_ready at 1.433 s. Looped, those read as a repeating beat rather than as a routine with a start and an end. Per-row figures are on Lengths.

What you may change ​

Safe to change ​

FieldWhy it is safe
labelA display string. Nothing matches on it
categoryA grouping string. Nothing matches on it
modeAdvisory only — your own code decides what it means
walkNot present on any row; add it and honour it yourself
blendInAdvisory only. Your code reads it or it does nothing
durationAdvisory only. Nothing reads it
idSafe, as long as it stays unique and you update your own references

You can also add fields of your own: a price, a job restriction, a rank gate. The table is data and nothing validates its shape.

category is the obvious thing to rewrite ​

All 34 rows carry category = 'dance'. A menu built straight from that field gets one undifferentiated list of 34 entries, which is a long scroll for a player looking for the moonwalk.

The pack's own server owner guide splits the 34 into breakdance, hip hop and party, and that split is exact and complete — 20 + 6 + 8 = 34, every clip in exactly one group — but it exists only as prose in that guide, not as a field you can read. The three groups are listed in full on the dance list. Writing them in is cheap:

lua
{ id = 'breakdance_uprock', category = 'Breakdance' },
{ id = 'tut_hip_hop_dance', category = 'Hip Hop' },
{ id = 'moonwalk',          category = 'Party' },

Pick one capitalisation and keep to it. The ids divide further if you want finer groups: sixteen start with breakdance_, five end in _hip_hop_dance, seven have freeze in the name.

Do not generate the groups from the ids, though. The breakdance group is 20, and four of those twenty — flair, flair_1, headspin_start and crossleg_freeze — do not carry the breakdance_ prefix. Take the grouping from the dance list and write it in by hand.

Never change ​

FieldWhy
dictMust match the name baked inside the .ycd file
clipMust match the clip name inside that dictionary

An RDR2 dictionary stores its own name. dict is therefore not a filename you are free to rename — it is a lookup key that has to agree with the asset, and renaming the file in stream/ breaks it just as surely as editing the string here. stream/ is escrow-protected in any case, so the .ycd files cannot be edited or renamed on disk. The risk is entirely in this file.

Both mistakes fail silently

A wrong dict means the dictionary never loads. A wrong clip means it loads and plays nothing. Neither raises an error, in the server console or in F8 — the character simply stands there.

Guard with DoesAnimDictExist, put a timeout on the HasAnimDictLoaded wait and print your own line, because that line is the only warning you will get. Scripting the pack has the loader.

The bodies table ​

Every dance ships in two versions, one fitted to the male body and one fitted to the female body. bodies is where the pair is written down:

lua
bodies = { male = 'redmorrow2@dance', female = 'redmorrow2@dance@f' }

The invariant holds across all 34 rows, without exception:

bodies.malealways equals the row's own dict, which is always redmorrow2@dance
bodies.femalealways redmorrow2@dance@f — the male name plus @f
Clip nameidentical in both dictionaries

There are only two dictionaries in the pack and no per-dance ones, so dict .. '@f' is a correct rule for every row here. Reading bodies.female is still the better habit: it costs nothing, it is what a pack with a different naming scheme would carry, and it keeps the choice of body in one place in your code.

dict alone is the male version

A row's dict is the male dictionary, not a body-neutral one. If you ignore bodies and pass dict to RequestAnimDict, every character on your server dances on the male skeleton. Both versions play on either body — the mismatched one just reads badly, and on the floor moves it reads worse.

Picking between them needs GET_META_PED_TYPE, which returns 0 for male and 1 for female. The comparison has a trap in it: 0 is truthy in Lua, so compare the number rather than testing the return as a boolean. IsPedMale is a reasonable fallback but may hand back 0/1 rather than true/false on RedM, so handle both. The function is written out on Scripting the pack.

The two dictionary names are also on Two dictionaries, that is all.

Reading the table from your resource ​

Config is a Lua global, and CFX gives every resource its own isolated Lua state — so a global set inside redmorrow2 would exist only inside redmorrow2. In this pack it is not even that: the manifest loads no scripts, so the assignment never runs anywhere. Your own resource can start the pack, depend on it, stream its dictionaries and play every dance, and still see this:

lua
-- in your own resource: always nil
print(Config and Config.Clips)

There is no export to ask through either, because the pack registers none.

Two ways round it.

1. Copy the rows into your own resource ​

The reliable option, and the right default if you are feeding an emote system, a job script or a saloon scene. Read the values out of clips.lua or out of the dance list and write them into your own file:

lua
local Dances = {
    { id = 'moonwalk', clip = 'moonwalk', label = 'Moonwalk', group = 'Party' },
    { id = 'can_can', clip = 'can_can', label = 'Can Can', group = 'Party' },
    { id = 'breakdance_uprock', clip = 'breakdance_uprock', label = 'Breakdance Uprock', group = 'Breakdance' },
    { id = 'flair_1', clip = 'flair_1', label = 'Flair (1)', group = 'Breakdance', blendIn = 2.0 },
}

local MALE_DICT = 'redmorrow2@dance'
local FEMALE_DICT = 'redmorrow2@dance@f'

Two dictionary names cover the whole pack, so they can live as constants rather than per row. The pack still has to be started for the dictionaries to exist in the stream — copying the table copies the names, not the animations.

2. Load clips.lua into a sandbox ​

clips.lua is listed in escrow_ignore, so it is still a readable file on disk after escrow. That means LoadResourceFile can fetch its text and load can run it in an environment you control.

LoadResourceFile is a server-side native, and the clients never receive clips.lua as a script, so the usual shape is: read it on the server once, hand it to clients over an event.

Server side, in your own resource:

lua
-- Returns redmorrow2's Config.Clips, or an empty table.
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()
print(('[mydances] loaded %d dances'):format(#danceClips))

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

Client side, in the same resource:

lua
local danceClips = {}
local byId = {}

RegisterNetEvent('mydances:clips', function(clips)
    danceClips = clips
    byId = {}
    for _, c in ipairs(danceClips) do
        byId[c.id] = c
    end
end)

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

Rename the mydances:* events to fit your resource. byId['flair_1'].blendIn is 2.0 and byId['flair_1'].bodies.female is redmorrow2@dance@f.

Why the sandbox

env is the chunk's entire world. Seeding it with Config = {} is what the Config = Config or {} line at the top of the file expects, and reading env.Config.Clips afterwards keeps the 34 rows out of your own globals — so a future version of the file cannot overwrite a Config of your own.

The pcall matters as much. A chunk loaded into an empty environment has no natives, no print and no require, so a file that called anything would error and you would get an empty table back rather than a crash. clips.lua assigns a literal and stops, which is exactly the shape the sandbox needs.

LoadResourceFile takes the resource name

The first argument is the resource name, which in CFX is the directory name on disk. Here the folder is redmorrow2 and the manifest's name field is redmorrow2 as well, so 'redmorrow2' is correct in both places and matches the ensure redmorrow2 line in server.cfg. If your server renamed the folder, change all three. Installation has the detail.

Which option to take

Copying the rows survives an update untouched and is the right default. The sandbox loader is worth it when you want the pack to stay the single source of truth, or when you are generating a menu rather than hand-writing one. Re-check it after an update, because a future version could change the file's shape; copied rows cannot break underneath you.

After an edit ​

  1. Save clips.lua. Nothing in the pack loads it, so the pack itself needs no restart and cannot be broken by what you wrote. A restart redmorrow2 is harmless but pointless. The server console says what it always says:

    text
    Started resource redmorrow2
  2. Restart whatever consumes the list. If you copied rows into an emote menu or your own script, that resource is the one that needs restarting — and if you edited its config as well, after its own rules:

    cfg
    restart my_emotes
  3. Restart your sandbox loader too. getDanceClips runs once when your server script starts, so an edit to clips.lua does not reach a resource that is already running.

  4. Play one dance in game. A silent failure looks identical to no failure, so look at the character rather than at the console.

A syntax error here is silent

In a pack that loaded clips.lua as a script, a missing comma would stop the resource from starting, which at least tells you something. Here it cannot: the file is never parsed by the pack. A broken file simply makes pcall(chunk) fail inside your sandbox loader and hands you an empty table — an emote menu with no dances in it and nothing in the console. Print #danceClips after loading, as in the snippet above.

Your emote menu keeps its own list

Editing clips.lua changes this pack's reference list and nothing else. It does not change your emote menu, your database or the copy you pasted into your own resource — those hold their own names, and a label you rename here will not appear in front of players until you rename it there as well. Emote menus covers the common menus, and for the database-backed route see RedM Emotes.

Keep a copy of your edited file outside the folder. Re-downloading the resource from the Cfx.re portal replaces clips.lua with the shipped version.

Editing the rest of the download ​

FileEdit it?
clips.luaYes. label, category, mode, walk, blendIn, and fields of your own
README.md, CHANGELOG.md, docs/*.mdYes. Readable text, nothing loads them
fxmanifest.luaLeave it. There is nothing in it to tune
stream/*.ycdNo. Escrow refuses to start a changed protected file
.fxapNo. It arrives with the customer download and must stay as it is

The dependency '/assetpacks' line in the manifest is the Cfx.re licence-key entitlement check. Without it the resource refuses to start, so it is not something to remove while tidying. The pack runs only on a server whose sv_licenseKey belongs to the Cfx.re account that bought it. Download it from portal.cfx.re under Assets then Granted Assets, and upload over FTP in binary mode — ASCII mode corrupts the protected files.

Because there are no scripts at all, the pack costs 0.00 ms on the client and on the server. Players download about 3 MB of animation files the first time they join and the files are cached after that. A dictionary only loads into memory when someone plays a dance from it.

See also ​

Page
Dance listAll 34 dances, with clip name, length and group
Scripting the packThe thirteen-argument native call, start to stop
Emote menusPutting the names in the menu you already run
InstallationThe ensure line, the folder name, the licence-key check
TroubleshootingSymptom, cause, fix
FAQShort answers, including what the pack does not do
Animation BasicsHow RedM animations work in general
RedMWhere RedM differs from FiveM, flags included
24+ DancesThe sibling dance pack. Different dictionary names, so both can run together
100+ Female PosesAnother assets-only pack, female only
30+ Female PosesThe pose pack that does ship a menu

Still stuck? discord.gg/w4Ew4k3Exn.

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