RivalityFX Docsrivalityfx.com ↗

Presentation block (present)

Stability: Stable.

present is the one shared block every descriptor — a mode, a cosmetic pack, or a battleground — uses to present itself. It holds the whole card identity (title / sub / rgb) plus the showcase (desc / hero) and external info / buy links. One shape, one validator, shared across every domain — so a mode and a pack present identically instead of each re-inventing its own name / sub / rgb fields.

It is pure presentation — it never holds functional data (a mode keeps its flow/rules, a pack its status/sku/skins outside present). Every field is optional, so a domain may still default a missing one.

Fields

FieldTypeNotes
titlestringDisplay title — the card heading. (A mode also keeps a functional label.)
substringShort subtitle under the title (e.g. Solo · Best of, VIP).
rgbstring"r g b" accent triplet for the card (CSS rgb(var(--m-rgb))).
descstringOne-paragraph description — the hero sub-line / pack blurb.
herostringHero / splash-art image URL — the card banner. A CDN http(s)://…, a /path, or a cross-resource nui://<resource>/<path> for art bundled in the descriptor's own resource.
cardstringThumbnail for a grid cell — same URL forms as hero, authored small (16:9, ~640×360). Used by pickers that draw many cells at once, such as the map picker. A surface that wants a thumb falls back to hero when card is absent.
infostring"More info" external link URL (docs, a teaser page, …).
buystring"Buy" external link URL. A cosmetic pack also derives one from its sku.

All fields are optional strings. info/buy should look like a web URL (http(s)://… or /path); hero and card may additionally be a nui://… asset (see Hosting the art). A value that doesn't match is a load-time warning, not an error.

Why card is separate from hero. A picker decodes every visible thumbnail when the menu opens. Feeding it full-bleed 1920×1080 splash art is a real frame-time cost in CEF, so ship a small one for grids and keep hero for the full-width band.

Hosting the art

hero is loaded straight into an <img> in the NUI, so it must be a URL the page can fetch — pick one of:

  • CDN / website — an absolute http(s)://… URL. Best when the art is large, shared, or updated independently of the resource.

  • Bundled in your resource — ship the file in your resource's media/ and reference it cross-resource as nui://<resource>/<path>. Declare the file in your fxmanifest's files{} so clients download it (a server-only mode needs no client_scripts for this). Self-contained — the cover travels with the mode. This is what the shipped mode_duel reference does:

    -- fxmanifest.lua
    files { 'media/*.webp' }
    -- config.lua
    present = { hero = 'nui://mode_duel/media/cover.webp' }

Links open via copy-to-clipboard. A FiveM NUI page can't open the system browser, so the menu copies an info/buy URL and tells the player to paste it — the same pattern as the Discord button. Host the target anywhere (your site, a Tebex page).

Hero art dimensions — the two surfaces differ. hero is always rendered with CSS object-fit: cover (scaled to fill its frame and cropped), but the frame's shape depends on which descriptor ships it, so author for the right one:

DescriptorFrameAuthorCrop note
Modehero band — wide & shortlandscape 16:9 (1920×1080, min 1600×900)the band darkens the leading (left) edge for the overlaid copy — keep the focal point off the far-left third
Cosmetic packunlock panel — a tall left columnportrait ~3:4 (e.g. 900×1200, min 750×1000)fills a vertical column edge-to-edge — subject CENTRED, full-height composition

All .webp. A 16:9 image in the pack panel (or a portrait in the mode band) survives but crops hard to its centre strip, so match the surface.

Example

present = {
    title = 'Neon',
    sub   = 'Premium',
    rgb   = '245 191 79',
    desc  = 'A premium streamed skin pack — yours forever.',
    hero  = 'https://cdn.example.com/packs/neon-hero.webp',
    info  = 'https://example.com/packs/neon',
    buy   = 'https://example.com/store/package/neon',
}

Where it applies

The engine (modes) and the customization module (packs) flatten present onto the top-level name/sub/rgb/desc fields the NUI reads, and also pass the block through for the hero band — so both surfaces present from the same source.

DescriptorSurfaced by
Cosmetic packThe Appearance rail (title/sub/rgb as the pack tab) + unlock panel (hero as art, desc as the blurb, info as a "More info" link; the Buy CTA derives from sku).
ModeForwarded in the lobby snapshot; the rail card uses title/sub/rgb, and the mode cover renders the identity band: hero as full-bleed splash art (falling back to the typographic band when absent), title as the page title, desc as the sub-line, info/buy as the cover's "Preview" link row (copy-to-clipboard in-game).
BattlegroundCarried for a future map-picker surface — no player-facing battleground card renders it yet.

Authoring

present is validated by the shared SDK helper (Sdk.validatePresent, @sdk/shared/kit.lua), which each domain's defineMode / definePack / defineBattleground calls — so a malformed block fails loudly at your resource's own load, like the rest of the descriptor.

See also