Use an existing or custom Scaleform movie
Scaleform is GTA V’s Flash-derived native interface system. FiveM can use existing movies and custom .gfx assets. It is not restricted to a fixed list of built-in messages, and rendering it is not free: load only what the feature needs, draw it while visible and release the handle.
For browser-based layouts and ordinary web tooling, compare NUI. For a game movie or a specific native HUD integration, use the contracts below. The reference is the pinned Cfx.re Scaleform guide .
Authoring custom GFx
The documented authoring pipeline uses ActionScript 2, targeting Flash Player 8, with Adobe Flash Pro CS6. ActionScript 3 uses a different VM and is not supported by this GTA Scaleform implementation. Convert the authored .swf to .gfx with a legitimately available gfxexport.exe from the Scaleform GFx SDK; the official guide names SDK 4.0 as suitable. This project does not distribute those proprietary tools or imply that they are freely downloadable.
The game expects a global TIMELINE object. Public functions called by game natives must be members of that object. A file that opens in a Flash player but exposes no matching TIMELINE method is not a working native interface.
Use the official Scaleform boilerplate download as an upstream reference, not as a fixture claimed to have been built here. Put your owned exported movie in the resource’s streaming files and request it by its movie name without .gfx. Keep authoring files outside the client download pack unless intentionally distributing them.
Feature limits
The documented implementation does not support shape filters, ordinary Flash masking or embedded raster graphics. Text blur is also unsupported; a glow-based approximation is not the same effect. Texture loading and masking use the game-specific mechanisms described below. Do not assume a SWF feature survives conversion because it works in the editor.
Loading, calling and drawing
RequestScaleformMovie(name) gives a handle. Wait for HasScaleformMovieLoaded(handle) with a timeout and a yield. Then begin a method, push arguments with the correct types and end it. Movie-specific method names are not universal: inspect the target movie’s public interface.
| Step | Native family |
|---|---|
| Start method | BeginScaleformMovieMethod(handle, methodName) |
| Numeric/boolean arguments | ScaleformMovieMethodAddParamInt, ScaleformMovieMethodAddParamFloat, ScaleformMovieMethodAddParamBool |
| Short identifiers, such as texture names | The string-parameter native, also documented under _PUSH_SCALEFORM_MOVIE_METHOD_PARAMETER_STRING. |
| Normal display text | BeginTextCommandScaleformString, AddTextComponentSubstringPlayerName, EndTextCommandScaleformString. |
| Complete a no-return method | EndScaleformMovieMethod() |
| Draw at a 2D position | DrawScaleformMovie(...) |
| Draw across the screen | DrawScaleformMovieFullscreen(...) |
| Draw in world space | DrawScaleformMovie_3d(...); inspect the native signature and target track. |
| Release ownership | SetScaleformMovieAsNoLongerNeeded(handle) |
The official manual warns about a color shift when a 3D movie is drawn under blackout. The native reference remains the parameter authority. C# also has a higher-level Scaleform wrapper .
A client example with interruption-safe cleanup
Create a resource with client_script 'client.lua' in its manifest. The docscaleform command displays a known built-in movie for three seconds. A second invocation replaces the first rather than leaking another draw loop.
-- client.lua
local generation = 0
local activeHandle = nil
local function release(handle)
if handle ~= nil then SetScaleformMovieAsNoLongerNeeded(handle) end
end
local function cancel()
generation = generation + 1
release(activeHandle)
activeHandle = nil
end
RegisterCommand('docscaleform', function()
cancel()
local request = generation
local handle = RequestScaleformMovie('mp_big_message_freemode')
activeHandle = handle
CreateThread(function()
local started = GetGameTimer()
while request == generation and not HasScaleformMovieLoaded(handle) do
if GetGameTimer() - started >= 5000 then
if activeHandle == handle then
release(activeHandle)
activeHandle = nil
end
print('Scaleform load timed out.')
return
end
Wait(0)
end
-- Cancellation already released this request's handle.
if request ~= generation then return end
if BeginScaleformMovieMethod(handle, 'SHOW_SHARD_WASTED_MP_MESSAGE') then
BeginTextCommandScaleformString('STRING')
AddTextComponentSubstringPlayerName('Preview')
EndTextCommandScaleformString()
BeginTextCommandScaleformString('STRING')
AddTextComponentSubstringPlayerName('This message closes automatically.')
EndTextCommandScaleformString()
ScaleformMovieMethodAddParamInt(5)
EndScaleformMovieMethod()
end
local shown = GetGameTimer()
while request == generation and GetGameTimer() - shown < 3000 do
DrawScaleformMovieFullscreen(handle, 255, 255, 255, 255, 0)
Wait(0)
end
if request == generation and activeHandle == handle then
release(activeHandle)
activeHandle = nil
end
end)
end, false)
RegisterCommand('docscaleformstop', cancel, false)
AddEventHandler('onResourceStop', function(name)
if name == GetCurrentResourceName() then cancel() end
end)This example is source-reviewed teaching code, not a claim of executed game rendering. Test successful display, timeout, rapid repeated commands and a resource stop during loading and drawing. In Lua, use nil to represent no owned handle; do not accidentally release a newer request from an old coroutine. For return-valued methods, use the appropriate return-value native path rather than treating EndScaleformMovieMethod() as the returned application value.
Textures and masks
Game textures use img://textureDictionary/textureName, for example img://mpcarhud/albany. A normal HTTP image URL or an embedded bitmap in the authoring file is not interchangeable with that mechanism. Load the intended dictionary and use exact texture names.
DrawScaleformMovieFullscreenMasked(movie, maskMovie, ...) takes a second movie as its mask. The documented mask is hard-edged: a nontransparent mask pixel reveals the underlying pixel, without smooth alpha masking or antialiasing. Do not design an interface that depends on Flash-style feathered masks and assume this native implements them.
Some movies accept limited markup such as <b>, <br>, <FONT FACE='$Font2'>, <FONT SIZE='24'> and <img src='img://dictionary/texture'>. Support belongs to the individual movie/text field. Treat untrusted player text as text, not as a source of arbitrary markup.
The upstream font list is: $Font2, $Font2_cond, $Font2_cond_NOT_GAMERNAME, $Font5, $Machine, $Stencil, $Lubalin, $Bookman, $Stenberg, $Mistral, $HelveticaBLK, $HelveticaBLKI, $Times, $TradeGothic, $AnnaSC, $EngraversOldEnglish, $Bauhaus, and $Redemption. Not every movie supports every font.
Diagnose the failing layer
| Failure | Check |
|---|---|
| Movie never loads | Exact exported movie name, streaming resource, game track, timeout logs and collisions with another asset name. |
| Movie loads but method does nothing | Global TIMELINE member, spelling, argument types and argument order. |
| Text is truncated or malformed | Use the text-command path for display text, not the short-identifier string helper. |
| Texture absent | Dictionary/texture spelling and img:// URL; do not substitute a web image URL. |
| Flickering or duplicate output | Multiple resources/threads drawing the same UI, stale command requests or missing cleanup. |
| Works until a resource restart | Leaked handles, old callbacks, dependency startup order or stale streamed exports. |
Continue with Lua scheduling, resource cleanup, instructional buttons, and NUI alternatives.