Jump to content
Media Servers Online: EmuMovies Sync | Launchbox Sync | EmuMovies FTP ×

JSFL script to help create basic themes


Nabeshin

Recommended Posts

I'm going to share a tool I made that I hope it'll make it easier to some people to create themes for Hyperspin (it's very basic!). Sorry for my english 😛
Link with some examples from the Spectrum themes I'm working on to serve as a sample: https://www.mediafire.com/file/m3tdv9i7t39fnb5/SpectrumThemes.zip/file

The reason why I did this tool, is because I found some of the stuff I had to do a little too tiring, thought  most likely because of my ignorance of theme creation. I found several limitations, like I had to edit and manipulate every image, losing a lot of quality during the process, I couldn't include galleries, etc. Therefore, to make my life easier, I tried to create this tool to help me manage all that.

I should point out, however, that as I mentioned, I don't know much about how people normally approach theme creation. I mean, there are probably better ways than the ones I used, or other tools to make the task easier that I'm not familiar with. So, you guys can decide for yourself if this tool can help you or if you find it unnecessary. I also want to point out that I've never touched JSFL before (countless hours... and such a pain xD). Therefore, I'm sure that if you use it, you'll surely find things that don't work, or don't work entirely well.
So it would be incredibly helpful that if you found any errors, let me know so I can try to fix them.

So, what is it?
To make it easier for me to create themes, I decided to define a common structure for all the games on a platform, download all the images without thinking about rescaling or anything like that, and then run a script that generates a SWF file, for each game, from the XML in the database.
And that's what this tool does. A script that, given a structure that defines the theme, goes through each game in an XML, and with the well-ordered images you have, creates a SWF movie for each game.

What do you need?
When using JSFL, you need a program that can run these, like Adobe Animate.

How do you use it?
So, to run this tool, we'll open Adobe Animate, open the scriptCreacioTemplate.jsfl file, and click the play button in the top right corner.
When you do this, the program will ask you which structure you want to use, and once selected, you'll see that Adobe Animate will go through every game in your XML, construct the movie (importing images, positioning them, animating them, adding text, etc.), and export every single one of them into separated SWF movies.

Key points for using it:
Let's now look at what elements the tool uses to create these movies, so you can configure and create your own.

The tool is made up of three key elements.
The first is an XML file with a fixed name, database.xml. This will be the list of games from which the SWF movie will be created. The format is like this:
<menu>
   <game name="Altered Beast (Europe)" index="" image="">
      <description>Altered Beast (Europe)</description>
      .
      .
      .
   </game>
You will see that it is very similar to what we already see in Hyperspin (the databases). In the end, it is just a "menu" node, and inside it a list of "game" files. The key point that you have to pay special attention to is the "name" attribute of these. With this value, as we will see in more detail later, it will be the way to know, for example, which game the images we have prepared belong to. In the case above, it could be, for example, Altered Beast (Europe).jpg (we will see later how they should be saved or prepared).

The second would be the process of searching for and downloading images and other resources that you want to use for each game. Everything is well organized.
For example, if you want to have the game logos on screen in your theme, you would have to go to the folder where you extracted all the scripts (for example, D:\scriptJSFL), and there you could, for example, create a new folder named "logos" (D:\scriptJSFL\logos), and inside it place the logo images (D:\scriptJSFL\logos\Altered Beast (Europe).png).
It's important to note that you don't need to edit or modify these images. In principle, you only need to change the name so the tool can find them, but nothing more. The system will automatically resize the image or adapt it from 4:3 to 16:9. Later, you'll see how inserting images works in more detail, and it will become clearer.

The third and final key element, and the most complex difference, would be the file with the common structure you want to use to create your movie file. This file is where you will specify parameters such as the resolution of the movie, framerate, what elements it will consist of (images, for example), their position, sizes, etc.
This will be saved in a JSON file (it is actually a JS variable, but there is no need to go into that, let's say that the format you can use is exactly the JSON format), and inside it will have, let's say, a base with a variety of basic parameters such as resolution or framerate, the path where the movies will be created, etc., and then an array with all the elements you want to indicate, such as background images, logos, etc.
Here is a simple example:
{
   "resX": 1024,
   "resY": 768,
   "frameRate": 60,
   "duration": 90,
   "backgroundColor": "#c0c0c0",
   "pathSavedFiles": "backgroundSWF",
   "elements": [
      {
         "type": "images",
         "pathRel": '/background/',
         "category": "Background",
         "x": 0,
         "y": 0,
         "maxDimensioX": 1024,
         "maxDimensioY": 768
      }
   ]
}
In this example, as for the base parameters, those of the movie itself, you can see how the resolution (resX and resY), the framerate, the duration of the movie, the background color, the relative path where each movie for each game will be created are defined and, finally, we have the elements parameter, where you will have a list of all the elements of your movie (in this case there is only one image, which acts as a background).
You can see other basic parameters that a project can have in ANNEX 1.

Elements available for the elements parameter.
The "elements" parameter is an array of objects, and therefore, you can include as many elements as you want.
The allowed element types, which will go within this array, are FLA files, text elements, and image elements.
All elements have a common parameter, which is the category. This will be the name of the layer internally within the project, and therefore, must be unique for each element. That is, you cannot include two elements with the same value. And it will always be a character string (for example, "test", "Art1", "Art2", "something", etc.).

Let's look at the different types of elements available:
- FLA files: used to copy the content of FLA files. For example, if we add:
{
   "type": "import-fla",
   "pathRel": '/textFLA/'
}
Using the XML example at the beginning, the system would search for an Altered Beast (Europe).fla file within the textFLA folder, and if it finds one, it would import its contents.
As you can see, this way we would search for specific FLA files for each game. But we also have the option of importing a fixed FLA.It would be like this:
{
   "type": "import-fla",
   "pathRel": '/fla/',
   "fileName": "loadingscreenFull"
}
In this case, it will look for the loadingscreenFull.fla file inside the fla folder, and import all the content into each game.

- Text: This is simply used to add text. You can either specify the text directly or try to get the text from one of the nodes that the game has in the XML.
Let's look at an example of direct text:
{
   "type": "text",
   "category": "TextIlustracions",
   "x": 772,
   "y": -4,
   "amplada": 195,
   "altura": 100,
   "text": "Art",
   "size": 34,
   "color": "#FFFFFF"
}
What you would do is, in the positions that appear here, you would create a rectangle with the width and height that appear here, with the font color and size that appear here, and you would place the text that is in the "text" parameter directly.
Let's now see an example of getting a field from the XML:
{
   "type": "text",
   "category": "TextNomJoc",
   "x": 8,
   "y": 19,
   "amplada": 260,
   "altura": 100,
   "field": "description",
   "size": 24,
   "color": "#000000"
}
In the same way as above, it will create a text rectangle, with the parameters that are here, but in this case it will take the description node that the game XML had, which in the example we had would be Altered Beast (Europe). You will find more information about the parameters it can have in appendix 2.

- Images: to add images. The system works in a way that it looks for images, in jpg or png format, that have the same file name as the name of the game. For example, if we have this images element:
{
   "type": "images"
   "category": "ImatgesArt1"
   "pathRel": '/Art1/',
   "x": 10,
   "y": 200,
   maxDimensioX": 400,
   "maxDimensioY": 400
}
The system will search the Art1 folder for images in supported formats that have the game name, for example, D:\scriptJSFL\Art1\Altered Beast (Europe).png. It will adapt its dimensions to occupy the maximum space defined with the maxDimensioX and maxDimensioY parameters. That is, imagine that maxDimensioX and maxDimensioY define a canvas, and what the system will do is, without losing the aspect ratio of the image, try to fit it within this canvas (making the image larger or smaller, depending on its original size).
It will also adapt the width of the image to the 16:9 format, so that when Hyperspin stretches the image from 4:3 to 16:9, it will still look good. Although, this fix can be disabled.
This element also works as an image gallery (the image will change). To do this, you just have to add more than one image to the game. For example, you could have D:\scriptJSFL\Art1\Altered Beast (Europe).png, D:\scriptJSFL\Art1\Altered Beast (Europe)(1).jpg, D:\scriptJSFL\Art1\Altered Beast (Europe)(2).jpg, D:\scriptJSFL\Art1\Altered Beast (Europe)(3).jpg, etc.
In ANNEX 3 you will see in more detail the basic parameters for the images.

Note that you can apply animations to the images. The animations that you can set are of "in" as for when the image enters, "rest" as when the image is already on screen and static, and "galleryBetween" which will be the animations that will occur when changing from one image to another in the case of a gallery.
An example of an animated image element would be:
{
   "pathRel": '/Art1/',
   "category": "ImatgesArt1",
   "x": 772,
   "y": 8,
   "maxDimensioX": 400,
   "maxDimensioY": 300,
   "type": "images",
   "animations": {
      "in": {
         "types": [
            { "type": "transition-from-right"},
            { "type": "fade" }
         ],
         "secondsDuration": 0.5,
         "secondsDelay": 0
      },
      "rest": {
         "types": [
            { "type": "pulse"}
         ],
         "secondsDuration": 8,
         "secondsDelay": 15
      }
   }
}
In this example, "in" and "remain" animations are defined. The "in" animation, as you can see, will be a transition from the right (off the screen) to the position you have defined in the image (x and y parameters of the image element), combined with a fade effect (it would be a fade in when entering), and the animation will have a duration of 0.5 seconds.
As for the "remain" animation, it will simply be a pulse animation.
You will see more details about the animation parameters and the different ones that exist in ANNEX 4.

Conclusion
I think this has explained everything.
Please understand that I did very very limited testing. Pretty much only what I needed for my themes that Im doing with this. Therefore, it might happen that you try to do things that are supposed to work but fails anyway. In those cases, let me know and I will try to fix it.
As I said before, I don't know if it will really help you or what. I hope so. in the end I'm just sharing because regarless that if it's useable or not, it took me a lot of hours to do, so I thought it would be a waste. Also I understand this is a lot of text and I'm sorry for that, but in case you end up trying it and use it, any feedback you want to make will be more than welcome.

Contents you will find in the ZIP
Inside the zip that I share with you, apart from the code, I have put a small example with the 3 Streets of Rage games from the Megadrive. They serve only as a simple example of how it works. I have tried to make it as simple as possible.
To run it, as I mentioned above, open Adobe Animate or similar, open the scriptCreacioTemplate.jsfl file, click on play at the top right, and when it asks for the file, select for example 1 - structure Simple.json.
If you have done it correctly, you should see how Adobe Animate goes through each game in the XML, and assembles the structure you have selected, importing the images, positioning them, etc. Once finished, in the backgroundSWF folder, you should see a SWF file for each game.
These would be the movies we would use as the background for the Hyperspin theme template.
As a bonus, there's a bat file that I will use to create a zip with the XML of the theme for every swf created. But it's adapted to my JSON, so you will have to tweak it a little to make it work for you, but it's super easy to see how it works.

Final observations:
- First of all, keep in mind that depending on what you want to do, it may take a while (text, for example, is VERY slow).
- It's important to note that if the system sees that you've already created the movie for a specific game, it won't do it again. It will notify you and move on to the next one.
- Also, something that has happened to me sometimes, you have to be careful with the structure of your JSON file, since a misplaced comma, for example, can cause the entire execution to fail. That is, let's imagine for example the following base parameters:
{
   "resX": 1024
   "resY": 768,
   "frameRate": 60,
   "duration": 90,
   "backgroundColor": "#c0c0c0",
   "pathSavedFiles": "backgroundSWF"
}
Pay attention, not so much to the content, but rather to the format. You will notice that between the resX and resY parameters, the comma is missing after the resX value. This type of error can cause the script to fail when executing. Therefore, you have to make sure that the format is correct. To get a better idea of how it works, you can look at how the JSON format works, since it is more or less the same.

ANNEX 1: Basic parameters:
- resX: The X-axis resolution. Must be a number.
- resY: The Y-axis resolution. Must be a number.
- frameRate: The movie's framerate. Must be a number.
- backgroundColor: Simply specify the background color for the movie.
- saveAsFLA: You have the option, if you want, to save as FLA instead of exporting as SWF (also with the game name, just like the SWF would be). Since the script allows you to have FLA elements (you'll see this later), it can be useful for performance issues, since it will allow you to split the process into different steps. The value must be boolean (true or false). For example:
{
   saveAsFLA: true
}
- doTest: If you activate this parameter, the system will only take the first game you have defined in the XML, and instead of exporting the project as SWF or saving as FLA, it will simply stop and leave the project open in Adobe Animate. This parameter is useful when you are still building the structure file, to see how things are looking.
- pathSavedFiles: This will be the folder, within the script folder, where the results of running the script will be saved. If for example you define something like:
{
   pathSavedFiles: "backgroundSWF"
}
If you have the script in D:\scriptJSFL, you will have to have created the folder D:\scriptJSFL\backgroundSWF. And in this folder you will see that the script will create a SWF file (or FLA if you have the saveAsFLA parameter activated) for each defined game. For example, in the XML example that we have at the beginning, once the script is executed, the following file should exist:
D:\scriptJSFL\backgroundSWF\Altered Beast (Europe).swf
- noFixAspectRatio: As I mentioned at the beginning, I didn't want to have to manually manipulate and edit each image, so the system does it automatically, scaling the images to the widths you define, but also automatically applying the X-axis rescaling for when Hyperspin stretches the movie to 16:9 monitors.
If you want to create themes for 4:3 screens, you would have to enable this parameter, also with boolean values (true or false).

ANNEX 2 : Text Element Parameters
- x: position of the element on the X axis. Must be a number.
- y: position of the element on the Y axis. Must be a number.
- wide: width of the text rectangle (when it reaches the end, it will make a new line). Must be a number.
- height: height of the text rectangle. Must be a number.
- text: the text itself, when you want to directly specify it. For example:
{
   text: "Text to display on screen"
}
- field: the name of the node to take the text from. For example, if in the XML we had a node like this:
<menu>
   <game name="Altered Beast (Europe)" index="" image="">
      <genre>Beat-'Em-Up</genre>
    .
    .
    .
   </game>
</menu>
And we wanted to display the "genre", we would put the parameter like this:
{
   field: "genre"
}
- font: the name of the font you want to use. If it is not installed or is not specified, _typewriter or Times will be used.
- size: The font size. Must be a number.
- color: The font color. Must be in HEX #RRGGBB format. For example, #000000 or #a0a0a0.
- maxLength: Number of characters to display. If the string to be displayed is longer than this, the string will be truncated and '...' will be added at the end.
- secondsDelay: The time, in seconds.to display the text. Must be a number.
- secondsDuration: The time, in seconds, that the text will be on the screen. Must be a number.
- framesEntreCaracters: When this field is entered, the typewriter effect will automatically be activated. This means that every x frames a letter will be added to the total text. In other words, a text like "Beat em up" would appear frame by frame like this: "B", "Be", "Bea", "Beat", ... Therefore, if you enter a number, for example 5, a letter will be added every 5 frames. For example:
{
   framesEntreCaracters: 5
}
I should note, however, that I have noticed that at least with Adobe Animate, this process is extremely slow. I'll see if I'm doing something wrong or if it can be optimized. But for now I would recommend that if you want to add text with this effect, you make your project with two steps: a first step to save as FLA with the text and its effect, and the second and final one is to simply import the text to the project (importing is extremely faster than creating the effect).

ANNEX 3 : Images
- pathRel: is the relative path where the images will be searched for.
- x: position in X where the image will be placed.
- y: position in Y where the image will be placed.
- maxDimensioX: maximum width that the image can have (the system will try to occupy the maximum space in the area marked by this field with the maximum height, adapting the measurements respecting the aspect ratio of the image).
- maxDimensioY: maximum height that the image can have (the system will try to occupy the maximum space in the area marked by this field with the maximum width, adapting the measurements respecting the aspect ratio of the image).
- center: boolean field (true / false). As we mentioned before, the system will resize the image to take up as much space as possible within the maximum width and height dimensions. However, this means that one corner will have empty space. The center parameter centers the image in the corner with the empty space.
- secondsDelay: The time, in seconds, for the image to appear. Must be a number.
- secondsDuration: The time, in seconds, for this element to be visible. Must be a number.
- secondsBetweenImages: The number of seconds each image will remain visible in a gallery. - animations: This is where any animations you want to specify for this element will go
. This will be an object where you can specify the options in, rest, and galleryBetween.
The in would be the animations for when the image enters, rest would be the animations that it will have once the image is on the screen, and finally galleryBetween would be the animation that will occur between the change of images in the gallery.
To indicate this, here is an example:
{
   animations: {
      in: {
         "types": [
            { "type": "transition-from-left" },
            { "type": "fade" }
         ],
         "secondsDuration": 2
      },
      rest: {
         "types": [
            { "type": "pulse"}
         ],
         "secondsDuration": 3
      }
   }
}
With this example you would see that the in transition would apply the fade-in combination along with a transition from the left, off the screen, to its position. The duration of the transition would be 2 seconds.
As for the rest animation, it is simply a pulse animation.

ANNEX 4 : Animations
- secondsDuration: seconds that the animation will last. Therefore, it must be a number.
- secondsInBetween: Only applicable in some animations, such as pulse. It marks the time, in seconds, between animations.
- easeType: This will be the type of tween we will create for the animation. You can see the different types available in Adobe Animate and you can see the number of the one you have selected in the instruction history. By default, it is 10. It is a number.
- tweenEasing: The tweenEasing parameter we used when creating the tween (I don't remember if it was like the intensity). By default, it is 100. It is a number.
- types: This is an array with all the animation types you want to combine for the animation. It will have the type parameters with the value and, sometimes, depending on the animation, it will have some more specific animation parameters. Let's see what may exist:
-- transition-from-*: where * can be down, up, left, or right. Basically, it is a simple movement, from the edge indicated in the name to the position indicated in the image. For example:
{
   types: [
      {type: 'transition-from-down'}
   ],
   "secondsDuration": 2
}
-- elastic-transition-from-*: has the same directions as the previous one, and does exactly the same thing, but upon arrival it has a more elastic effect.
-- bounce-transition-from-*: has the same directions as the previous one, and does exactly the same thing, but upon arrival it has a bounce effect.
-- fly-across: selects two points randomly, two positions of these points, and makes a transition between these two points, taking into account that it will appear off-screen and leave the screen as well. It is affected by the secondsInBetween parameter (time between transitions).
-- pulse: simply makes a pulse effect. It has an optional field called scale, to manually define how big you want it to grow. The default is 1.3. An example:
{
   types: [
      {type: 'pulse', scale: 2.3}
   ],
   "secondsDuration": 2,
   "secondsInBetween": 0
}
-- hover: allows you to make a hover effect. It accepts the movementRang parameter, which in turn will have the x and y parameters. What the system does is create a rectangle with the movementRang parameters, which will be the range of movement allowed to do the hover. The system will make normal transitions to random points within this space and will make as many movements as possible, calculated from the duration of each movement and the frames that the image will be on screen. For example, if we place:
{
   types: [
      {type: 'hover', movementRang: {x: 400, y: 200}}
   ],
   "secondsDuration": 2,
   "secondsInBetween": 0
}
With this example, starting from the point where we have the element (fields x and y of the image), it will create a surface of 400 pixels wide x 200 high. This will be the area from which the movement of the image will be allowed. And knowing that each movement will take 2 seconds, it will create the number of movements necessary for it to be in motion all the time. Note that you can omit one of the fields inside movementRang, for example, by not specifying the y, and making the hover horizontal only.
-- blur: simply a blur effect. An example combined with fade:
{
   types: [
      {type: 'blur'},
      {type: 'fade'}
   ],
   "secondsDuration": 2,
   "secondsInBetween":0
}
-- fade: simply a fade effect.
-- zoom: simply a zoom effect. It has the scale parameter, which will be the zoom to which it will transition. An example with fade:
{
   types: [
      {type: 'zoom', scale: 3},
      {type: 'fade'}
   ],
   "secondsDuration": 2,
   "secondsInBetween": 0
}
-- page-flip: page-flip effect, which consists of scaling the x axis, maintaining the scale in y.

EinaFinalJSFL.zip

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...