[HOW-TO] [TUTORIAL] Create your own scaleform using Flash + GFxExporter

This guide is a work in progress as R* Scaleforms are still being digged and discovered day by day.

Ok so this is intended to build and stream your first own scaleform.
I started diggin 1 week ago into this amazing world and after an initial sense of loss, i started understanding how R* handles it.

First of all the basic tools. Youl’ll need:

Adobe Flash CS6 PRO trial (R* used CS4 and CS5 for its scaleforms but it’s ok)
GFxExporter (this is used to convert from swf to gfx format, i’ll explain later in the guide, download all the files and place them in a folder)
JPEXS Free Flash Decompiler (To decompile your scaleform… and not only that)
– FiveM Client and a Server to test with.

Part 1 - Setting everything up for work

Ok so, first of all, don’t launch Adobe Flash Pro yet, we need to create a folder where we will store all of the project first, what you call it is not important, what’s important instead is the package directory, just like how you would set it up in Java or other similar languages.

Inside your folder, create four distinct folders one inside the other, so you can get the following directory YourFolder\com\rockstargames\gtav\levelDesign\ inside this folder is where we are going to put our ActionScript files.

Now you can open Adobe Flash Pro, this is a very old application, i suggest to play with it and its options for a while… in about 1 day of playing you’ll get the hand of it :slight_smile:

Ok once opened, you can get a view like this

This is the Classic (base) settings of Flash’s Workspace… if you go in the Top-Right area you can change your Workspace.
I personally use the Developer one with the addition of the actions panel anchored in the Left-Bottom side of the screen as it fits perfectly what we need to do:

Part 2 - Creating our Project

Now that we have set our Workspace, we can create a new project, in the Left-Top part of the screen you can see the Project panel, here we can create a new project, to do that just select the drop down bar and click into "New Project…"

image

this window will appear:

image

Here you can set the name of the project for now we’ll call it GuideScaleform, then select the yellow folder icon and navigate to the “YourFolder” folder we mentioned before, the application will set the project path there.
Select the “Create default document” tick as we need it to build the graphic interface of our scaleform and give it a name (it will be your swf / gfx file name)

Important!! Always set the Destination at Flash Player 8 and Script to ActionScript 2.0

When we’re done click “Create Project” and we have our project like this
image

The file AuthotimeSharedAssets.fla is generated automatically and can be ignored we will not use it but we need it to publish our project into swf so don’t touch it and leave it there.

now we can start working on our Scaleform.

Part 3 - The Drawing

First thing to do, is double clicking the fla file we created, an empty white page will open.
look on the right side of the screen…

Make sure that the flash player is version 8 and Action Script is ActionScript2, then we change our project dimensions, the fps can go from 24 to 29 to 30 in some scaleforms, up to you, the size must be 1280 x 720.
Almost all scaleforms uses 1280 x 720 screensize to work with even the 3D ones, some use smaller sizes but for now this will be good for us.

Next step is creating CONTENT and BOUNDING_BOX symbols these 2 are the main parts of the scaleform and i’ll explain later why. Go right side and click on the Add Symbol button (the very first one) or right click on the lower empty space and select “New Symbol",

the symbol is a Movie Clip and while it can have the name you want, it must have a linkage to the Action Script, under “ActionScript Linkage ”, check both cases and write in the Identifier box CONTENT .
Repeat the same and in the Identifier box write “BOUNDING_BOX

the 2 symbols should look like this
image

now, on the main screen click on that little icon spacer.png on top and select whatever you called BOUNDING_BOX Symbol.

Now click on the Rectangle Tool or press R), create a rectangle, then select the "Selection Tool (or press V), select the rectangle and set its XY position to zero, the color does not matter, you can set the alpha to 0% or not as the code later will set it as invisible anyway.
This symbol represents your screen’s boundaries and will contain the custom scaleform.

Now it doesn’t need to always be 1280x720, for example if you are making a menu and want to render it in 3D or in any mode outside of Fullscreen, the rectangle should probably be the same size as the menu itself. What’s the most important from what I can guess is that the position must be zero’d.

Now using the same little icon spacer.png select the CONTENT symbol to show, THIS is where we are going to draw our scaleform… everything is drawn into the CONTENT symbol.
Now Drag&Drop the BOUNDING_BOX symbol from the library into the CONTENT screen and again, set the BOUNDING_BOX rectangle’s position XY to 0.
you can see when it’s 0 because the little + symbol is on the top-left corner like in the picture

Now on the timeline in the bottom of your workspace, add a new layer to keep drawing, you can see the layers as steps, each step is a set of drawings that takes you to the end, first layer is the bounding_box’s one, the next layer will make us draw a rectangle inside the bounding box layer, place wherever you want as long as it’s inside the bounding_box layer.
you can draw your rectangle big or small as you want but not too small to let us draw some texts into it.

now adding another layer we select the Text Tool ( T ), we are going to add a text that will not change by script or user input we’ll set it as Static Text

In the nearby we’ll be adding a TextBox that will be filled by script via scaleform functions and natives…
Draw it and select Dynamic Text in the drop-down, leave the text box empty, and add an instance name “PlayerNameText

Since we are adding texts we need to add a font to the scaleform or they won’t be visible at all, to do that select one of the textboxes and click on the “Embed…” button located in the Properties Tab, go to the “Character ranges” category and check All in the list, next, go to the Options tab then under “Linkage” check both boxes and click OK, you should see the font added into the Library panel.

The basic drawing part is done for now.

Part 4 - The ActionScript code

Now the fun part, go up in the project folders navigate into com\rockstargames\gtav\levelDesign folder and in here click on New File icon
image
Set File Type as Action Script and call it BaseScriptUI.as ==> Create it and copy this code into it

class com.rockstargames.gtav.levelDesign.BaseScriptUI extends MovieClip
{
	var BOUNDING_BOX;
    var CONTENT;
    var TIMELINE;

	function BaseScriptUI()
	{
		super();
	}
	function INITIALISE(mc)
	{
		this.TIMELINE = mc;
		this.CONTENT = this.TIMELINE.attachMovie("CONTENT", "CONTENT", this.TIMELINE.getNextHighestDepth());
		this.BOUNDING_BOX = this.TIMELINE.attachMovie("BOUNDING_BOX", "BOUNDING_BOX", this.TIMELINE.getNextHighestDepth());
		this.BOUNDING_BOX._visible = false;
	}
}

This is the BaseScriptUI code, present in every drawn scaleform, it’s the super class for every creation you’ll see why… create a new ActionScript file in the folder and call it the same way you called your fla file but UPPERCASE as the file name must be the same as the class name casewise too.

this will be your main Scaleform code and you’re going to copy this base code to start with:

class com.rockstargames.gtav.levelDesign.GUIDESCALEFORM extends com.rockstargames.gtav.levelDesign.BaseScriptUI
{
   function GUIDESCALEFORM()
   {
      super();
   }
   function INITIALISE(mc)
   {
      this.TIMELINE = mc;
      this.CONTENT = this.TIMELINE.attachMovie("CONTENT","CONTENT",this.TIMELINE.getNextHighestDepth());
   }
   function SET_PLAYER_NAME(str)
   {
      this.CONTENT.PlayerNameText.htmlText = str+" !";
   }
}

As you can see i wrote GUIDESCALEFORM all capital… since all scaleforms are wrote like this, i decided to keep it as that.
You can note that the Scaleform itself extends BaseScriptUI this is the reason why we need it and see it in almost every scaleform.
Another thing to note is that i already set a Scaleform function for you, SET_PLAYER_NAME is the function you’ll call to set the empty text box we drew earlier… for convention all the “public” scaleform functions (the ones that can get called by the scripts) are written ALL_CAPITAL_WITH_UNDERSCORES while internal functions are always written lowCapitalWithoutUnderscores

The last part of the work is basically adding the actions and publish our scaleform.
Click on your scene button
image

If you don’t have the Action panel as i do, simply press F9 and anchor the window to one of the side panels.

In the Action window we’re going to paste this code,

var TIMELINE = new com.rockstargames.gtav.levelDesign.GUIDESCALEFORM(); // Constructor of your custom scaleform
TIMELINE.INITIALISE(this);

This is the last code to be passed when publishing, if there are errors anywhere in your ActionScript codes or in the drawing, the swf will be still published but this timeline won’t be, if decompiling your scaleform you can’t find this code, this means you have an error somewhere in your code.
When writing code is good practice to always check for errors and to auto-indent by using these 2 symbols in the editor, if an error appears it will be shown.
image

Part 5 - Publishing

Go to “File” on top and select “Publish Settings”, be sure that the Target is set to Flash Player 8.0 and Script to ActionScript 2.0, then click OK.

Go to “File” again and select “ActionScript Settings”, then set a Classpath to your com folder inside your project folder and click OK.

Now we are ready, go to “File” and select “Publish” (or use Alt + Shift + F12) and in your project folder you’ll see a new “GuideScaleform.swf” file.

Now this is a good time to check if everything is set up properly, if you see something missing, go back and see if you missed something.
To be sure everything is gone as expected, you can also open the swf file with JPEXS Free Flash Decompiler and you’ll see that everything we’ve done is there, check for the timeline too in the “Script => frame 1 => DoAction” file… in the end it should be something like this

Finally, open the folder where gfxexport is located, drag the .SFW file onto gfxexport.exe, wait a sec and it should create a .GFX file in our project directory near the .SWF file.

Now here’s the hardest part, be very attentive, take this .GFX file and put into your stream folder.
And congratulations! You just made and installed a custom scaleform in your server! Now all you have to do is call it like any other scaleform by using the name of the file with either your own method or the usual Natives.

Part 6 - What’s next

Digging and trying… i’ve found out you can actually use internal R* tools to better create your code and scaleform, for example, if you add a png file to the scaleform like this:

GFxExporter will strip the images and leave only red shapes (yeah the same you saw into other scaleforms) the trick is here… the exporter will take the stripped pics and turn them into .DDS files with weird naming, if you put those .DDS files into a custom .YTD file and place it near your .GFX file with the same name and bam… the scaleform will load the shapes automatically

If you still need to load some textures via code, then you can do it like this, there are 2 ways:

  1. Load the texture file via script (RequestStreamedTextureDict()) and then use this code to draw the texture onto a custom symbol in the CONTENT timeline
	function loadTextureIntoMovieClip(txd, texture)
	{
		var thisObj = this;
		var _loc3_ = this._componentsForLoadingImages.length + 1;
		var _loc2_ = new com.rockstargames.ui.core.BaseComponentInfo(_loc3_);
		this._componentsForLoadingImages[_loc3_] = _loc3_;
		_loc2_._depth = _loc3_ + 10;
		_loc2_._mc = this.CONTENT.yourCustomItem; // this is the symbol you created in content like a rectangle turned to symbol
		_loc2_._listener = new Object();
		_loc2_._loader.addListener(this.loaderObject._listener);
		_loc2_._listener.thisObj = thisObj;
		_loc2_._listener.componentID = _loc3_;
		_loc2_._listener.onLoadInit = function(target_mc)
		{
			var _loc2_ = this.thisObj._componentsForLoadingImages[this.componentID];
			_loc2_._loader.removeListener(_loc2_._listener);
			_loc2_._loader = null;
		};
		var _loc5_ = "img://" + txd + "/" + texture;
		_loc2_._loader.loadClip(_loc5_,_loc2_._mc);
	}
  1. Let the game do the work for you without natives using internal calls:
    com.rockstargames.ui.game.GameInterface.call(“REQUEST_TXD_AND_ADD_REF”) this will request the dictionary without using the scripts natives. Its parameters:
1. type (int) -> for generic textures use com.rockstargames.ui.game.GameInterface.GENERIC_TYPE
2. gfx file name (string) -> this is not the name of the scaleform.. but the gfx file.. if you change name to the file.. change name here!
3. txd (string) -> the dictionary of the texture to load
4. (optional) type of texture i think (string) -> it's a string that change in base of needs.. sometimes it's background for backgrounds.. for callscreen is "callscreen_thumbnail", optional in some gfxs
5. alreadyLoaded (bool) -> i think this is a way to check if the texture dict was loaded already.. dunno but it's optional in some gfxs

callback parameters ADD_TXD_REF_RESPONSE:

1. textureDict (string) -> the texture dict requested
2. success (bool) -> true if the request was succesful
3. uniqueId (int) -> not used.. sometimes this and success are inverted ADD_TXD_REF_RESPONSE(textureDict, success, uniqueID) -> ADD_TXD_REF_RESPONSE(textureDict, uniqueID, success)

The callback is called automatically and MUST be included into your scaleform code or else it won’t work… an example:

	function requestTexture(txd)
	{
		if (txd != "" && txd != undefined)
		{
com.rockstargames.ui.game.GameInterface.call("REQUEST_TXD_AND_ADD_REF",com.rockstargames.ui.game.GameInterface.GENERIC_TYPE,"TEST_7",txd);
		}
	}

	function TXD_HAS_LOADED(textureDict, success)
	{
		if (success)
		{
			if (textureDict == this._stockMenuDict)
			{
				this.loadTexture(textureDict,this._bannerTexture,this.bannerSprite);
				this.loadTexture(textureDict,this._bodyTexture,this.bodySprite);
			}
		}
	}

	function loadTexture(txd, texture, container)
	{
		var thisObj = this;
		this.loaderObject._depth = 100;
		this.loaderObject._mc = container;
		this.loaderObject._loader = new MovieClipLoader();
		this.loaderObject._height = this.loaderObject._mc._height;
		this.loaderObject._width = this.loaderObject._mc._width;
		this.loaderObject._x = this.loaderObject._mc._x;
		this.loaderObject._y = this.loaderObject._mc._y;
		this.loaderObject._listener = new Object();
		this.loaderObject._loader.addListener(this.loaderObject._listener);
		this.loaderObject._listener.thisObj = thisObj;
		this.loaderObject._listener.onLoadInit = function(target_mc)
		{
			target_mc._width = this.thisObj.loaderObject._width;
			target_mc._height = this.thisObj.loaderObject._height;
			target_mc._x = this.thisObj.loaderObject._x;
			target_mc._y = this.thisObj.loaderObject._y;
			var _loc2_ = this.thisObj.loaderObject;
			_loc2_._loader.removeListener(_loc2_._listener);
			_loc2_._loader = null;

		};
		var _loc3_ = "img://" + txd + "/" + texture;
		this.loaderObject._loader.loadClip(_loc3_,this.loaderObject._mc);
	}

Also we’re lucky because GTAV Flash supports gfx extensions so you can add advanced features into your scaleform like parallax effect directly into your scaleform without having your script to do the math

example: 2021 09 18 01 43 32 - YouTube

i’m also including all the R* ActionScript tools i found so far that R* used to code scaleforms, you can add it to your folder structure… when a component is called or instatiated the swf will include it automatically during the publishing.

final_structure.zip (1.4 MB)
Thanks to @simpled-dev and its amazing research we can now have and use some good library on flash and actionscript 2, download the e-book collection here: 238.08 MB file on MEGA

Conclusion

credits: a HUGE thank you to @lacoL for helping me into the digging and learning Flash :smiley:

I Hope this will be the beginning of the understanding of an important part of the Game graphics…
Please be kind with my english / pictures lang… i’m italian…
Thanks for reading!

25 Likes

Awesome!

Glad we finally figured this out haha what a crazy weekend it was

Just a rough example of what you can do when exporting embeded images, this was done to figure out how the .ytd/.dds files are loaded into the scaleform.

Scaleform with animated GIF

Amazing research.

1 Like

For an example, i re-made NativeUI in scaleform. Take a look here

Can anyone tell me if the instruments in general, such as the speedometer of cars or even the altitude, speed, vertical speed information of aircraft are made using scaleform?

Just followed this tutorial because it focused on something I was trying to work out. The problem is that when I export the swf and convert it to a gfx, JPEXS shows it as having no _Packages folder, so all the scripting is missing, I see no mention of that _Packages folder on this page, so I presume it is something that should just happen automatically. I set the classpath to myFolder/com, so I am not sure what I am missing… could anyone advise please?

I usually have another parent folder before com…like… ScaleformUI/project/com

And then I set the path to project folder
Try that.
If this doesn’t work I’ll be happy to help you tomorrow! (00am here)

I’ll give that a go thanks… I used to be an AS developer but that was over 15 years ago so I have forgotten everything.

So I now have the path F:\GTAVScaleform\GuideScaleform\project

Inside that project folder is a settings and com folder, with the com folder containing the path and files shown in this tutorial.

Also in the project folder is .actionScriptProperties, .project, AuthortimeSharedAssets.fla and GuideScaleform.fla, as well as the GuideScaleform.swf when I export it.

The classpath is set to F:\GTAVScaleform\GuideScaleform\project

After setting all that, the _Packages folder still isn’t being created.

Is the project used for this tutorial available for download at all? I obviously don’t want to take up people’s time trying to solve this because this is probably a me issue. I am old now and sometimes struggle to get my brain in gear, so I am probably missing a fundamental but simple step to getting this right. Your help is genuinely appreciated.

nope… the project folder should only contain com folder and its .as content
Evrything else should be outside of project

an example is on my github GitHub - manups4e/NativeUI-scaleform_flash

I think I am just going to have to take the loss on this one, even publishing your project has the same result. Maybe there is something wrong with my Flash installation, or perhaps something isn’t converting properly with GFExport…

Thank you for your help anyway but I don’t want to take up more of your time.

no that’s fine! to publish my repo you must change the path in the actionscript settings


image

because this one is on my computer… and i’m pretty sure this :poop: of flash is going to keep it and you should change it to the same path on your computer… but leading to the same folder…

I had actually done that and it had failed but when I have just changed it to a relative classpath with .\project\ yours has built with the _Packages present in JPEXS

I have just turned off the Publish Cache though so I don’t know if that had affected anything.

However, after building my project, it still fails… so I obviously need to investigate further with that.

so far in my projects the only reason for missing the _Packages folder in JPEXS was the wrong path in “ActionScript settings” options

That would make sense but both projects now have the same relative classpath and that’s why I am so confused. I think what I am going to try, is deleting the project I have built and start again going through this tutorial step-by-step.

I mean if I can’t get this simple tutorial project working, then it’s probably a sign that I should stick to C# and script mods. But it’s equally frustrating that I can write complex C# mods and yet can’t get a simple project working for a language I used to use as part of my profession.

I created a side-by-side of both projects to show what I mean with the classpaths. Again, thank you for your help… if my rebuild doesn’t work then I will call it a day.

I rebuilt the project and got the exact same result. No matter whether I use an absolute path or a relative path, it just isn’t outputting that _Packages section.

There are only 4 possible options and that’s absolute to either project or com, or relative to project or com. If none of those are correct, I don’t know what correct can possibly be… there are no other options.

I know this might sound an unreasonable request but could you please consider at some point creating the project from this tutorial and adding it as a download so that people learning have a known working project to work from?

I fully understand if this is not something you want to do though, so please don’t worry about saying no.

sure i’ll upload it asap