Dead Cells

Dead Cells

61 ratings
SkinMaker: How to Create Skin Mods
By Mooner and 1 collaborators
SkinMaker is a custom tool for creating Dead Cells skin mods. This guide will detail what the tool can do and how to work with it.
2
2
2
   
Award
Favorite
Favorited
Unfavorite
Basic Overview
SkinMaker is a custom tool I created with the goal of simplifying skin-making by automatically generating required animations from a set of sprites. It is developed in Java, and as such will require you to install Java to run it (Java 8 is recommended).
Note that it is a command line interface tool. A graphical user interface for the tool is something I'm considering for the future, but unfortunately won't have time for anytime soon.

You can get the tool here[drive.google.com]
You can find the following files in the link:
  • SkinMaker.jar - the tool itself
  • GlobalProperties.json - file used for basic configuration of the tool, more on it in Using the tool - Commands and Configuration section
  • modelColorPropertiesConfig.json - more about this in Models section
  • Example Skin - folder containing all the sprites and configuration for an example skin, to serve as a reference when making your own

You can see examples of mods created with the tool here: https://steamproxy.net/sharedfiles/filedetails/?id=2513727857
Using the tool - Commands and Configuration
As mentioned in the previous section the tool uses command line interface. In case you have no experience with using command line, we will go over how to find it and make it ready to run the commands mentioned in this section.

To open command line (Windows) you just need to search for the "cmd" or "powershell" (either of them will work) application and launch it. This will open a window where you can enter commands. Now we only need to switch to the directory where you have the SkinMaker tool. The command for this is cd, followed by a path to the directory. Like this:

cd <path to SkinMaker directory>

As an alternate option you can press the shift key together with right clicking in the folder where you have saved the SkinMaker tool. Among the provided options you should see something along the lines of "Open command window here" or "Open PowerShell window here". This will open the command window already set to the directory you launched it from.

Once you have set the proper directory you can launch the tool. The command required to run the tool is fairly simple.

java -jar SkinMaker.jar -dynskins <path to project configuration>

The beginning of the command java -jar is simply saying to use java to run the tool.
Next we have specified the name of the tool to run which is SkinMaker.jar followed by the arguments.
-dynskins is used to tell the tool to run skin creation, without this argument the tool will do nothing. This is followed by a single, or multiple paths to your skin configuration files, separated by spaces. Example of path: "C:FilesMyProjectMyProjectConfiguration.json". Make sure to include the quotes "" around your path, especially if the path contains any spaces.

There are additional optional parameters that can be used, most of which are intended to simplify testing of skins. You can learn more about these in the Using the tool - Optional Parameters section later on.

You might've noticed that with the SkinMaker was bundled a GlobalProperties.json file. This is a global configuration containing some basic information like where the game is installed and where to find the expanded game files.

GlobalProperties.json has the following structure:
{ "gamePath": "Dead Cells installation directory", "resPakPath": "path to expanded res.pak folder, "cdbPath": "path to expanded data.cdb folder", "atlasPath": "path to folder with expanded atlases" }
It's important to have this file configured properly in order for the tool to function properly.
The gamePath property is required, if it's not configured properly the tool will not be able to access the game's resources and Mod Tools. You can get your gamePath by going to properties of the game on Steam, then go to Local Files section and select Browse Local Files. This will open up the game folder, simply put path to this folder into the gamePath.
The rest of the properties resPakPath, cdbPath and atlasPath are optional and a default value will be used if they are not present in the GlobalProperties.json file.

What remains is to create the Project configuration file and your sprites. As the configuration file can get quite complex, it will be detailed in multiple sections, starting with the section Creating a Project.
Using the tool - Optional Parameters
This section will introduce optional parameters that the tool supports. Most of these are intended to simplify testing of skins by skipping parts of the process.

-only

The -only parameter can be used to build only a few animations instead of all 500 or so of them.
To use it, the -only parameter needs to be followed by an equal sign (=) and a list of animation names separated by commas.
This parameter significantly reduces the time it takes for the tool to finish processing, which makes it one of the most useful testing parameters. It allows you to preview your skin on a handful of animations and only build the entire animation set after you are happy with how it looks.

Example command with the -only parameter, building only idle and run animations:
java -jar SkinMaker.jar -dynskins <path to project configuration> -only=idle,run

-skipCollapsing

This parameter is used to skip the collapsing of resources using the provided ModTools. Collapsing of resources is one of the last steps of the whole process. The collapsing of atlases (spritesheets) takes an especially long time due to the size of the player character atlas.
An important note is that you cannot test your skin in-game if you use this option since you won't get a final res.pak file.

Example command with the -skipCollapsing parameter:
java -jar SkinMaker.jar -dynskins <path to project configuration> -skipCollapsing

-skipBuildingDir

One of the first actions the tool does is prepare files and directories necessary for the processing. This includes cleaning up any remaining files from previous runs, creating copies of required resources (res.pak, data.cdb, etc.), and preparing the output directories.
As we are working with quite a large amount of files (lot of animation frames, cdb entries) it can take a bit to clean up/prepare everything for use.
Once again this speeds up the testing process a bit though nowhere near as much as the previous two options.
An important note is that the tools still requires all the directories to exists, so you shouldn't use this parameter when making any given skin for the first time. Also, I would not recommend using this when creating the final mod file, to avoid any issues related to old files remaining in the folders.

Example command with the -skipBuildingDir parameter:
java -jar SkinMaker.jar -dynskins <path to project configuration> -skipBuildingDir

-skipSpriteIndexing

Dead Cells uses a combination of indexed sprites with color palettes to allow for color variations of skins without the need for each of them to have their own spritesheet. The indexed sprites look like this:


This parameter will simply skip the indexing part of the sprites, making them appear with their intended colors. Similar to the -skipCollapsing parameter, you cannot test your skin in game if you used this parameter (the colors will be one big jumbled up mess).
Its usefulness lies in being able to see the skin sprites with the proper colors without launching the game. Once again saving some time during testing as you won't have to launch the game to check every small tweak you make.
I'd recommend using this parameter in combination with the -skipCollapsing parameter.

Example command with the -skipSpriteIndexing parameter:
java -jar SkinMaker.jar -dynskins <path to project configuration> -skipSpriteIndexing

-forceExpand

With this parameter, you can force the tool to expand all game resources required for your skin/skins. If some of the resources are already expanded it will first delete them and then re-expand them.
This is useful mostly when a new update drops and you want to make sure the tool uses the most recent game files.
This parameter will increase the processing time as some resources can take quite a bit of time to expand (mostly atlases/spritesheets). By how much the processing time increases will depend on the skin configuration which specifies the atlases that need to be expanded, and whether any old files have to be deleted.

It's important to note that the tool will always expand any non-expanded resources it needs. This parameter is used to re-expand even the ones that are already expanded.

Example command with the -forceExpand parameter:
java -jar SkinMaker.jar -dynskins <path to project configuration> -forceExpand
Creating a Project
A project is a json configuration file representing the mod you're about to make. It contains just some basic information and a list of skins that will be part of the mod. Each Project can have one or more skins in it (these will all be bundled together in one res.pak file that can be uploaded to the workshop)

A project file has the following structure:
{ "name": "MyProject", "outputPath": "C:\\Files\\MyProject\\Output", "skins": [] }
name - represents the name of the project
outputPath - path to a folder where you want outputs stored, this is where your skin mod will be once the tool has finished building it
skins - list of skin objects, each representing a skin that will be created (more on structure of skin objects in their own section)

All paths inside the Project file can be either absolute (example: "C:\Files\MyProject\Output") or relative (example "\output"). This applies to the outputPath in the Project but also all path in it's underlining skins.
When using relative paths, the tool bases them on the directory of the Project json file as the "working directory".

Example:
Our project json file is "MyProject.json" is stored in the following location:
C:\Files\MyProject\MyProject.json
Then our working directory would be:
C:\Files\MyProject
Now if I wanted to specify the output path, I could use the absolute path of the output folder:
C:\Files\MyProject\Output
Or just the relative path
\Output
Both the absolute path and relative path will point to the same folder.
Creating a Skin - skin object
In this section we'll go over the basic structure of the skin object. Each skin object represents a uniquely shaped skin that will be part of the mod. Each skin can also include optional color variations.

The skin object has the following structure:
{ "name": "MySkin", "inputPath": "C:\\Files\\MyProject\\MySkin\\sprites", "builderSettings": [], "customModel": true, "models": [], "disableHead": true, "skins": {}, "colorProperties": [], "customAnimations": {}, "scarfColors": {} }

name - name of the skin
inputPath - folder where the sprites of the skin are located
builderSettings - list of BuilderSettings objects (more in it's own section)
customModel - true/false but honestly in most cases this should use the true option
models - list of models to edit, only applicable if customModel is false (can be ommited if customModel is true)
disableHead - true/false determines whether the original smoke head should be disabled ot not
skins - option to modify any properties of the skin file and it's related item file in the game's data.cdb
colorProperties - list of paths to properties files containing colors that are used within the skin. These are then used to create color palettes the game uses (more in it's own section)
customAnimations - allows to use custom animation sprites for certain animations, replacing the default ones (more in it's own section)
scarfColors - allows to change the colors of the scarf trailing behind the player character
BuilderSettings - Overview
BuilderSettings are some of the most important parts of your skin configuration. They are used to configure everything that will appear in the final animation frames of your skin, be it sprites, parts of existing skins or lines connecting different Joints in the player character's skeleton.
Because of this it's also one of the more complex objects in the configuration.

There are three different types of BuilderSettings, each with different attributes. Which type is used is defined bz the type attribute. The available types are:
  • Dynamic - used to specify which sprites are to be used in your skin creation and where they are to be placed
  • Original - used to add parts from existing skins into your skin
  • Line - used to draw lines between Joints

Aside from the type attribute, each BuilderSettings also share the drawingMode and drawingOrder attributes (more on them in their section)
BuilderSettings - drawingMode and drawingOrder
drawingMode

The drawingMode indicates how the individual sprite should be drawn into the final frame with the rest of the sprites.
Supports the following modes:
  • OVERWRITE - the sprite will be placed over anything that's already in the frame
  • DONT_OVERWRITE - the sprite will be placed only on transparent pixels in the frame, will not affect any previously placed body parts/sprites
  • TRACKS_BASED - uses extra information from the animation files to determine the mode OVERWRITE/DONT_OVERWRITE. Sprites with this option should be among the last in the drawingOrder. Useful for body parts that can often appear in front of and behind other sprites (for example arms). This option does not work for BuilderSettings with type Original.




drawingOrder

The drawingOrder determines when the sprite should be drawn into the final frame. This is an optional parameter. If not specified, the sprite will be drawn after all the default builders (or builders with specified drawing order).

The drawing order has two main attributes mode and builder.

mode can be BEFORE and AFTER. It indicated whether the sprite should be drawn before or after the builder specified in the builder attribute.

builder is used as a reference to any other BuilderSettings object.
Each builder reference has to have a type attribute. The rest of the attributes will be different for each type.

"type": "Dynamic"
References a BuilderSettings (Dynamic) object. Contains additional attribute spriteName which is used to reference a BuilderSettings object with the same spriteName.

"type": "Original"
References a BuilderSettings (Original) object. Contains additional attributes model and bodyPart which are used to reference a OriginalBodyPartBuilderSettings object with the same model and bodyPart attributes.

"type": "Line"
References a BuilderSettings (Line) object. Contains additional attribute builderRef which is used to reference a BuilderSettings (Line) object with the same builderRef attribute.

The following gif ilustrates how individual BuilderSettings, in the Example skin, are applied based on the drawingOrder:
BuilderSettings (Dynamic)
Dynamic BuilderSettings are used to specify which sprites are to be used in your skin creation and where they are to be placed.

Before we move onto the structure of the Dynamic BuilderSettings detailed in the next section, we will go over some existing default options that may simplify your configuration file.

There's number of "sprites" or "body parts" the tool can automatically detect and place on the proper place without you needing to specify it in the BuilderSettings. All you need to do for this to take effect is to name your sprite in the proper way, so the tool can recognize it. (More on sprite naming in Creating Sprites section)

The sprite names that have a default BuilderSettings attached to them are:
body bodyUppper bodyLower upperLeftLeg lowerLeftLeg leftFoot upperRightLeg lowerRightLeg rightFoot pelvis upperLeftArm lowerLeftArm upperRightArm lowerRightArm leftShoulder rightShoulder
This also represents the default drawingOrder of the sprites (from top to bottom)

The names of the sprites should be fairly self explanatory as to which body part do they reffer. But to avoid any possible confusion we will go over each of them.

Following is a visual explanation of what each of above mentioned body parts represent.

body - area between neck and pelvis


bodyUppper - chest area (should be used with bodyLower, it's an alternative to body)


bodyLower - midriff area (should be used with bodyUppper, it's an alternative to body)


upperLeftArm - area between shoulder and elbow


lowerLeftArm - area between elbow and wrist


pelvis - pelvic area


upperLeftLeg - area between hip and knee


lowerLeftLeg - area between knee and ankle


leftFoot - foot


rightShoulder - shoulder
BuilderSettings (Dynamic) - Structure
It's time to look into how the BuilderSettings objects look and how they work.

The BuilderSetting object has the following structure:
{ "type": "Dynamic", "spriteName": "MySprite", "position": {}, "rotation": {}, "flip": {}, "warp": {}, "normalMapMode": "BLANK", "drawingMode": "OVERWRITE", "drawingOrder": {}, "frameMultiplication": 2 }

spriteName represents the name of the sprite the BuilderSettings apply to.
We will go over the rest of the options in detail in their own sections.
BuilderSettings (Dynamic) - position
The position object represents where the sprite will be placed. The position always represents where the center of the sprite will be placed.
Each position object has to have a type attribute. The rest of the attributes will be different for each type.

"type" : "SinglePointPosition"
For this type the sprite's position is defined by a single joint in the character's skeleton (for list of available joints visit the Joints section)

The additional attributes for SinglePointPosition are:
  • position - the name of the joint
  • offsetX - offset to the X coordinate of the position
  • offsetY - offset to the Y coordinate of the position

Example SinglePointPosition object:
{ "type": "SinglePointPosition", "position": "TORSO", "offsetX": 0, "offsetY": 0 }

"type" : "MiddlePointPosition"
For this type the sprite's position is defined by a middle point between two joints

The additional attributes for MiddlePointPosition are:
  • joint1 - the name of the first joint
  • joint2 - the name of the second joint
  • offsetX - offset to the X coordinate of the position
  • offsetY - offset to the Y coordinate of the position

Example MiddlePointPosition object:
{ "type": "MiddlePointPosition", "joint1": "SHOULDER_L", "joint2": "ELBOW_L", "offsetX": 0, "offsetY": 0 }
BuilderSettings (Dynamic) - rotation
The rotation object indicates how the sprite should be rotated if necessary.
Each rotation object has to have a type attribute. The rest of the attributes will be different for each type.

"type" : "TwoPointsRotation"
For this type the sprite's rotation is defined by two positions: the center of the rotation and the target of the rotation.

The additional attributes for TwoPointsRotation are:
  • rotationCenter - the rotation center position (same position object as defined above)
  • rotationTarget - the rotation target position
  • rotationOffset - offset in degrees added to the rotation

Example TwoPointsRotation object:
{ "type": "TwoPointsRotation", "rotationCenter": { "type": "SinglePointPosition", "position": "SHOULDER_L", "offsetX": 0, "offsetY": 0 }, "rotationTarget": { "type": "SinglePointPosition", "position": "ELBOW_L", "offsetX": 0, "offsetY": 0 }, "rotationOffset": -90 }

Following is a visual example of rotationCenter and rotationTarget, and how they are used to calculate the angle of rotation.

On the following images rotationCenter is represented as the blue point and rotationTarget as the red point. The image on the left shows a state of 0° rotation angle, this is when the rotationTarget is directly to the rigth of the rotationCenter.
The image on the right shows a 45° rotation.



On the next image we see this demonstrated on the body sprite from the Example skin. As the rotationCenter we use the NECK_TOP joint and as rotationTarget we use LOWER_SPINE joint.
The image on the left shows the two points and the rotation angle calculated from the two points.
Image in the middle shows what it looks like when the rotation is applied to the body sprite. We can see that this looks wrong. We would like for the body to not be rotated in this case, in a way we would want out default 0° rotation to be when the rotationTarget is directly underneath the rotationCenter, instead of when it's to the right as demonstrated above.
This can be easily adjusted with the rotationOffset attribute. In the image on the right we see the rotation after applying rotationOffset of -90° (negative rotation angle rotates counter clockwise, while positive clockwise). With the offset applied our sprites is rotated the way we want it to be.



"type" : "NoRotation"
This type indicates that the sprite will not be rotated. No additional attributes are used with this type.
BuilderSettings (Dynamic) - flip
The flip object indicates how the sprite should be flipped if it necessary (horizontal flipping/mirroring of the sprite).
Each flip object has to have a type attribute. The rest of the attributes will be different for each type.

"type" : "LineAndPointFlip"
For this type the decision whether to flip/mirror the sprite is based on the relative position of one point to a line (defined by two points). If the point is located to the "right" of the line, no actions is performed. If it's located to the "left" of the line then the sprite is flipped/mirrored.

The additional attributes for LineAndPointFlip are:
  • linePosition1 - the position of the first point defining the line
  • linePosition2 - the position of the second point defining the line
  • pointPosition - the position of the point used for determining whether to flip the sprite
  • supportingPointPosition - the position of the point used for determining whether to flip the sprite, in case pointPosition lies directly on the line (optional)

Example LineAndPointFlip object:
{ "type": "LineAndPointFlip", "linePosition1": { "type": "SinglePointPosition", "position": "KNEE_L", "offsetX": 0, "offsetY": 0 }, "linePosition2": { "type": "SinglePointPosition", "position": "HEEL_L", "offsetX": 0, "offsetY": 0 }, "pointPosition": { "type": "SinglePointPosition", "position": "TOE_L", "offsetX": 0, "offsetY": 0 }, "supportingPointPosition": { "type": "SinglePointPosition", "position": "TOE_END_L", "offsetX": 0, "offsetY": 0 } }

"type" : "NoFlip"
This type indicates that the sprite will not be flipped. No additional attributes are used with this type.
BuilderSettings (Dynamic) - warp
The warp object specifies a transformation/warp that will be applied to the sprite.
Each warp object has to have a type attribute. The rest of the attributes will be different for each type.

"type" : "TwoPointsWarp"
For this type the sprite's height will be adjusted to match the distance between two points.

The additional attributes for TwoPointsWarp are:
  • position1 - the position of the first point
  • position2 - the position of the second point
  • lengthOffset - offset applied to the distance between the two points

Example TwoPointsWarp object:
{ "type": "TwoPointsWarp", "position1": { "type": "SinglePointPosition", "position": "KNEE_R", "offsetX": 0, "offsetY": 0 }, "position2": { "type": "SinglePointPosition", "position": "HEEL_R", "offsetX": 0, "offsetY": 0 }, "lengthOffset": 2 }

"type" : "NoWarp"
This type indicates that the sprite will not be warped. No additional attributes are used with this type.



To ilustrate the usefulness of this feature let's look at the following images. First we have a frame from the idle animation, on the left is just the skeleton of the player character, with highlighet area between the left elbow and wrist. In the middle is lowerLeftArm sprite from the Example skin while using the NoWarp option. And finally on the right is the same sprite but using the TwoPointsWarp option.


From this example the difference is not that noticable, the sprite using the TwoPointsWarp is slightly shorter, and the details are a bit different because of it but both options look alright.

So let's look at a different example, this time from the run animation.


Immediatelly we can see that the highlighted area between elbow and wrist is much shorter. Most of it is hidden as the arm is pointing nearly directly at the cammera. Now the difference between the NoWarp and TwoPointsWarp options is much more visible. While using TwoPointsWarp the sprite's length is adjusted to match the distance between the elbow and the wrist. While with the NoWarp option the sprite retains it's full length, which it this case means that the sprite extends noticably beyond the elbow on one side, and beyod the wrist and even the entire hand on the other.

The TwoPointsWarp option is used in default BuilderSettings (Dynamic) for all the limbs
upperLeftLeg lowerLeftLeg upperRightLeg lowerRightLeg upperLeftArm lowerLeftArm upperRightArm lowerRightArm
BuilderSettings (Dynamic) - normalMapMode
The normalMapMode indicates what kind of normal map should be used for the sprite.
Supports the following modes:
  • BLANK - the normal map for this sprite will be blank (this is the recommended option if your sprites already have shading)
  • CUSTOM - the normal map for this sprite will use a custom sprite. The normal map sprite needs to exist alongside the color sprite and have the same name plus the _n suffix
  • ORIGINAL - the normal map for this sprite will use the same normal map as the default skin (beheaded)
BuilderSettings (Dynamic) - frameMultiplication
This is an optional parameter that is used only for animated sprites. It's primary use is to slow down the animation of the sprite by duplicating it's frames.

Example: let's say we have animated sprite with 3 animation frames (0, 1, 2)
Without frameMultiplication the frames will be applied in the following order
0, 1, 2, 0, 1, 2, ...
With frameMultiplication set to 2 the frames will be applied in the following order
0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, ...

Example of different frame multiplications applied to my Hornet skin
https://steamproxy.net/sharedfiles/filedetails/?id=2863403314

From left to right, no frame multiplication, 2 times frame multiplication, 3 times frame multiplication


As you can see, the animation is playing way too fast without any frame multiplication. By applying it we can reduced the speed of the animation to better suit our needs. The final skin uses frame multiplication set to 2 (middle image).
BuilderSettings (Dynamic) - Overwriting Defaults
As mentioned in the BuilderSettings (Dynamic) section, there are multiple default BuilderSettings (Dynamic) the tool can automatically apply based on the sprite names. In some cases, however, the default settings may not fit your needs, but you may want to keep the names recognized by the default BuilderSettings.

In this case all you need to do is specify a BuilderSettings (Dynamic) object with spriteName matching the default BuilderSettings (Dynamic) you wish to overwrite. You can overwrite default BuilderSettings (Dynamic) completely by specifying all attributes of the BuilderSettings (Dynamic) objects (refer to BuilderSettings (Dynamic) - Structure section) or partially by specifying only the attributes you wish to change, keeping the rest of the attributes with the default values.

To provide some examples, we will look at couple of BuilderSettings (Dynamic) from the Example skin.

BuilderSettings (Dynamic) - lowerRightLeg

Here is an example of the BuilderSettings (Dynamic) for lowerRightLeg sprite. As you can see we are only changing the drawingMode of the BuilderSettings (Dynamic). Everything else will be kept as default.
{ "type": "Dynamic", "spriteName": "lowerRightLeg", "drawingMode": "OVERWRITE" }

BuilderSettings - pelvis

Here is an example of the BuilderSettings (Dynamic) for pelvis sprite. In this case we're changing a couple more attributes. We changed the position of the sprite, its drawingMode, and its drawingOrder.
{ "type": "Dynamic", "spriteName": "pelvis", "position": { "type": "SinglePointPosition", "position": "PELVIS", "offsetX": 0, "offsetY": -4 }, "drawingMode": "OVERWRITE", "drawingOrder": { "mode": "AFTER", "builder": { "type": "Dynamic", "spriteName": "leftFoot" } } }
Creating Sprites
In this section I'll show some examples of how the input sprites used by the BuilderSettings (Dynamic) might look like and some naming conventions the tool expects when it comes to the names of the sprites. This is not a tutorial on how to make pixel art.

As you know by now, the tool works with sprites of individual "body parts" which it than places on the proper place based on the BuilderSettings (Dynamic). As such each "body part" you wish to include should have it's individual sprite or multiple sprites in some cases.

Here we can see a body sprite from the Example skin included with the tool:

This sprite is named body_0_0.png the sprite name contains 3 parts separated by _
  • The sprite name (body) - is the identification of the sprite. This sprite name is specified in the BuilderSettings (Dynamic) to know which settings to use for which sprite. The sprite name cannot contain _ character as it's used as a separator for the parts
  • side (0) - the side is a numeric value indicating which "side" is the sprite from as in front/back. It is used during animations where the player character turns either completely or partially in order to allow the sprite to change with turning. More details and example can be found a bit later in this section.
  • animation index (0) - represents the sequence of animation frames if the sprite is animated, starting from 0




Side

As mentioned briefly earlier, the side represents which side of the body part the sprite represents.
The numbers starts from 0 which represents a sprite from the front and increase as the character turns. You can have any number of sides, the only requirement is that number of sprites from the front needs to match number of sprites from the back (exception is if you have only 1 side). For odd number of sides, the middle one should represent looking at the body part directly from the side.

We will once again demonstrate it using the Example skin, this time including all the sides for the body:



I would recommend using at least 3 sides (as demonstrated above) for body parts like body and head. Rest of the body parts can often go without sides, but it highly depends on the specific skin.
Using more than 3 sides can provide a smoother transition, based on some small testing I found 5 to be fairly nice spot of not having too many side sprites and being smooth. Anything beyond 7 is most probably not worth doing due to the limited resolution of the game.



Animation index

This should be pretty self explanatory. The animation index allows for having animated sprites. It can be anything from the character blinking to clothes swaying in the wind or anything else you want. The animation index then simply indicates the order in which the frames will be used, starting from 0.

As an example, I will use my Hornet skin which has an animated body/dress
https://steamproxy.net/sharedfiles/filedetails/?id=2863403314



It uses 6 animation frames (animation index 0-5) and frameMultiplication of 2 (doubling every frame to make the animation play slower.
BuilderSettings (Original)
Similarly to the previously described BuilderSettings (Dynamic), the BuilderSettings (Original) object is used to add body parts into the skin. But instead of adding custom sprites, it adds a body part from an existing skin.

What's important to know is that the tool differentiates the body parts purely based on color. Some skins have multiple body parts using the same color (for example the default skin uses the same color for arms and feet), and as such they will always be added together.

The structure of the BuilderSettings (Original) object looks like this:
{ "type": "Original", "model": "beheaded", "bodyPart": "BODY", "colorMapping": {}, "skinColorMapping": "skinName", "supportingBodyPart" : {}, "drawingMode": "DONT_OVERWRITE", "drawingOrder": {} }

The drawingMode and drawingOrder behave the same as in BuilderSetting (Dynamic) object so I will not go over them again. Refer to the relevant sections in BuilderSettings.

The only difference is that drawingMode TRACKS_BASED is not supported for BuilderSettings (Original) object.

Here's short explanation of the attributes, more details on each further in this section:
  • model - name of the spritesheet of existing skin
  • bodyPart - name of the body part (for list of available bodyParts, refer to the Models section) every model also supports ALL option which will add all the body parts of the model
  • colorMapping - object specifying what colors should the body part use in the skin (more on structure later on in this section)
  • skinColorMapping - name of the skin from data.cdb to use for color mapping (the body part will have the same colors as it has in the specified skin)
  • supportingBodyPart - optional attribute used to help add body parts that share colors with other body parts
  • drawingMode - same as BuilderSettings drawingMode (except TRACK_BASED)
  • drawingOrder - same as BuilderSettings drawingOrder (optional)




model

model is the name of the spritesheet/atlas of a particular skin (for example the default skin's atlas is called beheaded)
It is specifying from which model to add the body parts. (For list of configured models and their bodyParts visit the Models section)




colorMapping

colorMapping object contains all the colors from a body part, and what colors (in hexadecimal format) they should be changed to in the custom skin.

Example structure:
{ "scarf_light": "#0000ff", "scarf_dark": "#0000ff" }
This represents the colorMapping for the SCARF body part of the beheaded atlas/spritesheet.

Either colorMapping or skinColorMapping must be specified in the BuilderSettings (Original) object. In case both are present, colors in colorMapping take priority.

So let's say we have the following BuilderSettings (Original) to add SCARF from the beheaded model into our skin:
{ "type": "Original", "model": "beheaded", "bodyPart": "SCARF", "colorMapping": { "scarf_light": "#79dd5e", "scarf_dark": "#346435" }, "drawingMode": "OVERWRITE" }

In the following image we see how the colorMapping sets the color of the bodyPart. On the left we see the beheaded sprite, with the SCARF bodyPart colors highlighted.
On the right we see the SCARF bodyPart applied to our skin, with the colors specified in colorMapping. (For list of configured models and their bodyParts visit the Models section)






supportingBodyPart

This optional parameter is useful in some specific situations when you are trying to add a bodyPart that shares colors with some other bodyPart (and thus you wouldn't be able to add them separately). Example of this is FEET body part from the defaul beheaded model shares color with the ARMS body part.
With supportingBodyPart we can specify an aditional body part from a different model that can help with the separation.

supportingBodyPart object has the following attributes:
  • model - the model from which to take the bodyPart
  • bodyPart - the bodyPart to use
  • mode - can be INTERSECTION / NO_INTERSECTION, determins how the extra check should behave

If the mode is INTERSECTION it means that only that part of bodyPart will be added, which matches also the supportingBodyPart.
If the mode is NO_INTERSECTION it means that only that part of bodyPart will be added, which does not match the supportingBodyPart.

Example of supportingBodyPart using the Hyper Light Drifter FEET body part:
{ "model": "beheadedHyperLightDrifter", "bodyPart": "FEET", "mode": "INTERSECTION" }

Let's demonstrate the above mentioned example. We will be using BuilderSettings (Original) to add bodyPart FEET from model beheaded.

Top left image shows the issue, the beheaded model shares the same color for the FEET and ARMS and as such the tool would add the ARMS into our skin as well.
Top right image shows the beheadedHyperLightDrifter model, and we can see that it's FEET bodyPart does not share color with any other bodyPart
Bottom left shows the FEET bodyPart from beheadedHyperLightDrifter overlayed over the beheaded sprite (The darkened area of the sprite). Here we can see how the supportingBodyPart works.
Bottom right is our final results, the left image shows our skin if we use the INTERSECTION mode. While the right image shows our skin if we use the NO_INTERSECTION mode.
The INTERSECTION mode added everything from the FEET bodyPart of beheaded model that was within the overlayed beheadedHyperLightDrifter FEET bodyPart. And the NO_INTERSECTION mode added everything that wasn't in the overlayed area.






Example of complete BuilderSettings (Original) object:
{ "type": "Original", "model": "beheaded", "bodyPart": "FEET", "colorMapping": { "feet_light": "#0000ff", "feet_dark": "#0000ff" }, "supportingBodyPart": { "model": "beheadedHyperLightDrifter", "bodyPart": "FEET", "mode": "INTERSECTION" }, "drawingMode": "DONT_OVERWRITE", "drawingOrder": { "mode": "AFTER", "builder": { "type": "Dynamic", "spriteName": "bodyUpper" } } }
Models
Models represent the unique skins in the game, and is used to access the proper spritesheet. The tool has--by default--configured only 6 models (beheaded, beheadedTickR5, beheadedSanta, beheadedServante, beheadedSonic, beheadedHyperLightDrifter) but it supports user configuration for more.

Each model has a different set of body parts that can have one or more properties. I hope most of the names will be self explanatory.

Configuration for the models can be found in modelColorProperties.json file included with the tool. I won't go over the individual model configurations as it's a long file. Anytime you need to know what body parts exist in a model, you can reference the file itself.

Each model configuration starts with the model name, containing an object with the configuration
"beheaded": {}

There's 3 properties for each model.
  • deindexingSprite - frame of animation that is used to deindex the configuration properties, this is usually the first idle frame
  • properties - contains the list of properties that exist in the sprite, each is usually a unique color. Each property has a numerical value indicating it's index/position in the palette
  • bodyParts - body parts are basically a group of properties that form some part of the sprite. Each property can be part of multiple body parts if needed.
BuilderSettings (Line)
As the name suggests, BuilderSettings (Line) object is used to draw lines into the final sprites. Each line is defined by two positions (refer to BuilderSettings (Dynamic) - position), the color of the line, the thickness of the line, and the drawingMode for the line.

BuilderSettings (Line) has the follwing structure:
{ "type": "Line", "lineStart": {}, "lineEnd": {}, "color": "#6b4434", "thickness": 1.5, "drawingMode": "TRACKS_BASED", "drawingOrder": {} }

  • lineStart - the position of the first point in the line
  • lineEnd- the position of the second point in the line
  • color - the color of the line in hexadecimal format
  • thickness - the thickness of the line (higher number means thicker line)
  • drawingMode - refer to BuilderSettings - drawingMode and drawingOrder
  • drawingOrder- refer to BuilderSettings - drawingMode and drawingOrder

Example of :
{ "type": "Line", "lineStart": { "type": "SinglePointPosition", "position": "SHOULDER_L", "offsetX": 0, "offsetY": 0 }, "lineEnd": { "type": "SinglePointPosition", "position": "ELBOW_L", "offsetX": 0, "offsetY": 0 }, "color": "#6b4434", "thickness": 1.5, "drawingMode": "TRACKS_BASED", "drawingOrder": { "mode": "AFTER", "builder": { "type": "Dynamic", "spriteName": "body" } } }
Skin Object - skins
The skins part of the skin object is used to indicate the existing outfit that is to be replaced by your skin. Optionally, you can also made any desired changes to the data.cdb files of the outfit (such as the in-game name and description).

The structure of the skins object is as follows
{ "skin name": { "item": {}, "skin: {}", "colorProperties": "path/to/color.properties" } }

Each skin is referenced by its name, this should match the name of the skin file in data.cdb. As mentioned earlier, it can contain the item and skin objects that can be used to change any part of the relevant data.cdb entry.
If no changes are desired, this can be left empty.
"skin name": {}

The structures of the item and skin objects should match their respective structures in data.cdb. You only need to include those attributes that you wish to change, the rest can be omitted.
We will not be going over the structure of these objects, as the purpose of this guide is not to explain the structure of the game's files.



colorProperties

colorProperties contains a path to colors.properties files. Which is used to create color palettes for the skin.

A colors.properties file contains a list of property name and color pairs.

property name can be either the color property of a body part from the default(beheaded) model, or an aditional_color, which simply adds a new color to the palette.

aditional_colors should be numbered starting from 0 in ascending order. All colors included in your skin need to be present in the color properties file.

Example of what a color.properties file looks like:
aditional_color_0=#f9861b aditional_color_1=#112860 aditional_color_2=#eeb48b aditional_color_3=#224baa aditional_color_4=#060608 aditional_color_5=#ffffff aditional_color_6=#ac421a aditional_color_7=#9e634c

The colorProperties attribute can be left empty, which will make the tool generate the properties on it's own from the skin's sprites. This can save some work in the case that you don't want multiple color variations of the skin.



Global settings

In case you have multiple skins specified in the skins section and want to make a change to their respective skin and item parts or use a single color.properties file across all of the skins, you can do it trough specifying a "Global" skin by using "Global" as the skin name.

It follows the same structure as all the other skins. It has one extra property mode which can be either REPLACE_EMPTY or REPLACE_ALL.

REPLACE_EMPTY means that it will replace only the properties, defined in the Global skin settings, of the skin/item CDB file that are not present, null or empty (in case of array elements).

REPLACE_ALL means that it will replace all properties, defined in the Global skin settings, of the skin/item CDB.

If mode is not provided it will use the REPLACE_EMPTY option.
Skin Object - customAnimations
In case you want to make some animations of your skin more unique, you can use the customAnimations option. If not, just keep the object empty "customAnimations": {}.

The customAnimations object has the following structure:
{ "model" : { "animation name" : "path to folder with animation" } }

  • model - refers to the model being used to create the skin, this is kept as beheaded mostly
  • animation name - the name of the animation to replace

When using customAnimations, each frame of the animation has to be named the way its respective frame is named in the atlas. Otherwise, the tool will not recognize them, so make sure the names are correct.

Example of using customAnimations to change the idle animation into a fighting stance:
Skin Object - scarfColors
This object is used if you want to change the color of the scarf in the skin without changing any other property of the scarf.

It has the following structure:
{ "skin name" : [ "15430182", "16613163" ] }

skin name is the name of the skin file in data.cdb (the name used in the Skin Object -skins section). It's followed by a list of colors in decimal format that will be used to replace the existing ones. If a skin has more scarfs than the colors specified, it'll go back to using the colors from the start again, repeating until all scarf colors are replaced.
Joints
Joints refer to individual connecting points of the player character skeleton. They are used to specify the position/rotation of a sprite, or to draw lines into the final frame. You can find the list of available Joints bellow. It should be apparent which parts of the skeleton they refer to based on their names.

HEAD NECK_TOP NECK_BOTTOM TORSO MID_SPINE LOWER_SPINE PELVIS THIGH_L KNEE_L ANKLE_L HEEL_L TOE_L TOE_END_L COLAR_BONE_L SHOULDER_L ELBOW_L WRIST_L FINGER_0_START_L FINGER_0_MID_L FINGER_0_FAR_L FINGER_0_END_L FINGER_1_START_L FINGER_1_MID_L FINGER_1_FAR_L FINGER_1_END_L FINGER_2_START_L FINGER_2_MID_L FINGER_2_FAR_L FINGER_2_END_L FINGER_3_START_L FINGER_3_MID_L FINGER_3_FAR_L FINGER_3_END_L FINGER_4_START_L FINGER_4_MID_L FINGER_4_FAR_L FINGER_4_END_L THIGH_R KNEE_R ANKLE_R HEEL_R TOE_R TOE_END_R COLAR_BONE_R SHOULDER_R ELBOW_R WRIST_R FINGER_0_START_R FINGER_0_MID_R FINGER_0_FAR_R FINGER_0_END_R FINGER_1_START_R FINGER_1_MID_R FINGER_1_FAR_R FINGER_1_END_R FINGER_2_START_R FINGER_2_MID_R FINGER_2_FAR_R FINGER_2_END_R FINGER_3_START_R FINGER_3_MID_R FINGER_3_FAR_R FINGER_3_END_R FINGER_4_START_R FINGER_4_MID_R FINGER_4_FAR_R FINGER_4_END_R
Step-by-Step of the Tool's Process
In this (and the next) section we will go over what the tool does once it's launched. The tool will send basic progress updates to the console, but in this section we will go more in depth into what's happening. This is merely to shed some light on the internal workings of the tool, you don't have to read this section to understand how to use it.



First the tool checks the first argument provided. As mentioned in section Using the tool - Commands and Configuration this should be -dynskins. If there's no arguments or the first argument is invalid the tool will just end it's processing as it's considered invalid action.

When the -dynskins argument is identified it starts the processing of Project files.
First it loads the GlobalProperties.json and beheadedModHelper_tracks.json (located in the game's ModTools folder, this file contains the animation data).
Then it continues processing the arguments provided when launching the tool. These should contain one or more paths to Project json files and any optional parameters from Using the tool - Optional Parameters section.



Loading project properties

At this point the tool will report it's first progress update. This means that it started loading the Project json files into memory. The loading is finished when the next progress update is reported.

Any error encountered in this section will relate to either the specified Project json file not existing (possibly due to a typo in the path you provided) or the file not matching the structure detailed in the sections above.



Expanding required resources

Now that the Project files were successfully loaded, the tool will start validating if all the resources required to process the Projects are available.

This includes:
  • expanded res.pak - specified by the resPakPath in GlobalProperties.json
  • expanded data.cdb - specified by the cdbPath in GlobalProperties.json
  • expanded atlases - specified by the atlasPath in GlobalProperties.json and by the OriginalBodyPartBuilderSettings of each Project

Any resources not found will be expanded to the appropriate location specified in GlobalProperties.json.

In case the -forceExpand optional parameter was used, all the resources will first be deleted (if they exist) and will be re-expanded afterwards.



After all required resources are expanded the tool will load modelColorPropertiesConfig.json containing the configuration for the models, whether it's the default configured ones or the user configured ones.



Project: ProjectName

After this will be processed the individual Projects as such the following progress updates will appear for every Project. The projects will be processed in the same order they were specified in the tool's arguments.



Creating directory structure

Now the tools starts preparing directories it'll need to create the Project. First it'll delete any existing files for this Project that were created by previous runs of the tool. After which it'll create the required files, which are a copy of the expanded res.pak and data.cdb. And a copy of expanded heroSkins.atlas (this atlas is being used for the preview of skins at the Tailor).

In case the -skipBuildingDir option was used, this entire part will be skipped.



Skin: SkinName

Now we're starting to process individual skins that are part of the Project. As such the following progress updated will be happening on Skin level.

First the sprites of the skin are loaded. The tool will load all .png files from the folder specified in the Skin's inputPath. To avoid errors in this part make sure all the sprites follow the naming convention detailed in Creating sprites section.

After the sprites are loaded, the tool will start processing the BuilderSettings (Dynamic) from the builderSettings part of the Skin. It starts will loading any default BuilderSettings (Dynamic) (See BuilderSettings (Dynamic) section) based on the loaded sprites and applying any overwriting of the default settings (See BuilderSettings (Dynamic) - Overwriting defaults section). And combines them with any custom BuilderSettings (Dynamic) in the Skin configuration.

Then the tool proceeds to process the BuilderSettings (Original) or more specifically the color mapping for each body part specified in the settings. If only colorMapping property is specified then no changes are made to the builder.
If skinColorMapping is specified the tool loads the mentioned skin to get information about which palette is the skin using. And after that it loads the palette and extracts the skins colors from it.
Then it updates the colorMapping with these colors (any colors already in colorMapping are not overwritten).



Updating CDB skin files

Now the tool will make any necessary changes to the data.cdb entries for the skins that are to be replaced (see Skin Object - skins section).
In here will be applied all changes defined by the Skin Object properties (Creating a Skin - Skin object section) disableHead, customModel, skins (Skin Object - skins section) and scarfColors (Skin Object - scarfColors section).



Creating skin palettes

The tool will create color palette files for each skin defined in the skins property of the Skin Object (Skin Object - skins section) using the color properties files defined in the colorProperties property of each skin or generated automatically from the sprites if no color properties are provided.



At this point we're getting to the main part of the process, which is creating the the sprites for all the animations. We start by getting all animation names from the beheadedModHelper_tracks.json. In case the -only optional parameter was used the animation list will be reduced to just the specified animations.

After that the default drawing order is loaded (BuilderSettings (Dynamic) section) and is modified based on drawingOrder property of the configured builders.



Building animations for model: modelName - numberOfFinished / numberTotal

We're finally making the actual sprites. Here will be displayed how many animations were already completed (an animation is considered complete if all frames of the animation were successfully built) and how many animations are being created in total.

First for each animation the tool applies all builder settings (BuilderSettings (Dynamic), BuilderSettings (Original) and BuilderSettings (Line)) for each frame based on the drawingOrder.
After that the sprites are indexed using the previously created palette, if the -skipSpriteIndexing optional parameter was used this will be skipped. And at last the sprites are saved into the proper place in the output directory.



Making custom animations

Here the tool will replace any default animations (created in the previous step) with custom animations specified in the customAnimations property of the Skin Object (Skin Object - customAnimations section)
Step-by-Step of the Tool's Process (Continued)
Creating HeroSkins preview

In this step the tool will create the required files in the heroSkins.atlas (that was prepared in the Creating directory structure step) for the newly created skin, so it can be properly displayed in the preview at the tailor's.

This step is only being executed if the customModel property of the Skin Object is set to true. But as specified in the Creating a Skin - Skin object section, this should be always the case.



Collapsing atlas files

All the sprites created for the skin will be collapsed, and the collapsed atlas will be placed into the res.pak directory of the Project. This is calling the game's ModTools directly. It is one of the slowest steps in the process due to the large amount of sprites.

In case the -skipCollapsing optional parameter was used this step will be skipped.



At this point we're finished with all the steps happening at the skin level. Now if the Project contains multiple skins it'll start processing the next one, and we will see all the steps from Skin: SkinName up to Creating HeroSkins preview repeat for the next skin.

After all skins are finished processing the tool will make some final actions for the entire Project.



Collapsing CDB

Using the game's ModTools, the tool will collapse the expanded data.cdb of the Project and place it into the res.pak directory of the Project.

In the case that the -skipCollapsing parameter was used, this step will be skipped.



Collapsing heroSkins atlas

Using the game's ModTools the tool will collapse the expanded heroSkins.atlas of the Project. And place it into the res.pak directory of the Project.

In the case that the -skipCollapsing parameter was used, this step will be skipped.



Creating pak file

The final step for each Project. Using the game's ModTools, the tool will create the final res.pak mod file in the output directory specified by the outputPath property of the Project.

In the case that the -skipCollapsing parameter was used, this step will be skipped.



If multiple Projects were specified in the input, the tool will move onto the next one. So you will see all the Project level steps repeating for the next project.

Once all specified projects finish processing, the tool will conclude.
Changelog 2023-03-07
Uploaded new version of SkinMaker.jar

Changes:
  • Updated working with ModHelperSkin.json to reflect change in the file in update 3.3
  • Updated "skins" property in the skin object to reflect changes in the skin files in data.cdb in update 3.3
    • additional properties added for glowData section
    • additional properties added for scarfs section
Changelog 2023-03-31
Uploaded new version of SkinMaker.jar

Changes:
  • Fixed issue in the process of expanding game resources when not all required resources were expanded
Changelog 2023-09-24
Uploaded new version of SkinMaker.jar

Changes:
  • Fixed issue in generating default palette when colors from BuilderSettings(Line) were not included in the palette file
  • Updated how the tool works with CDB files for skins and items. This makes the tool up to date with changes to the structure of the skin CDB files in update 3.4. This change will also ensure that further changes to teh structure of the CDB files will not impact the tools functionality in the future.
Changelog 2024-08-27
Uploaded new version of SkinMaker.jar

Changes:
  • Minor updates to align with some structural changes to ModHelperSkin, this version will be needed to create skins with the lates ModHelperSkin for update 3.5 but this new version will still support even the old format
Changelog 2024-08-28
Uploaded new version of SkinMaker.jar

Changes:
  • Fixed "scarfColors" option (Skin Object - scarfColors section) having no effect
Changelog 2024-08-29
Uploaded new version of SkinMaker.jar

Changes:
  • Fixed an issue when ModelColorProperties (described in the Models section) was initialized incorrectly in some cases. Which caused BuilderSettings (Original) to not function properly for some models.
29 Comments
Mooner  [author] 29 Aug @ 8:48am 
Uploaded new version of the tool to the drive.
Full list of changes in "Changelog 2024-08-29" section
Mooner  [author] 28 Aug @ 5:36am 
Uploaded new version of the tool to the drive.
Full list of changes in "Changelog 2024-08-28" section
Mooner  [author] 27 Aug @ 9:40am 
Uploaded new version of the tool to the drive.
Full list of changes in "Changelog 2024-08-27" section
Valorr 18 Jul @ 8:08am 
thanks, btw can u make soma cruz or juste belmont skin ?
Mooner  [author] 15 Jul @ 11:51pm 
For the most part it wouldn't work on Mac. Main reason being that the game's mod tool are present only in the Windows version of the game. The tool is using these to extract the game data and create the final mod file.

With some of the optional command parameters you could skip the extraction/collapsing and just have the tool generate the sprites. But for this you'd need to get the mod tools from the Windows version, and do these steps yourself. Needing to use something like wine to run the mod tools.

I could potentially add an option to the tool that would run the game's modtools with wine, so it can be fully used on Mac/Linux. You'd still need to instal wine and get the mod tools tough.
Valorr 15 Jul @ 10:04am 
Is macbook compatible with this tutorial?
TyLer Dyrkin 7 Jul @ 10:50am 
Can someone make a skin in the form of Matoi Ryuko?
Mooner  [author] 2 Jul @ 11:21pm 
No 3D models. This is a 2d animation solution so you have to draw the sprites and the tool will do the animations.
so can you put any 3d model on it or you just need to draw the sprites?:stress:
Plagued death walker 16 Apr @ 4:33pm 
Can someone simplify it for me please