CCXL: Hairs
Summary
Published: Jan 20 2025 by mana vortex and island_dancer Last documented edit: July 14 2025 by nutboy, mana vortex, island_dancer, CyberVesna and Silverlags
This page will tell you how to use ArchiveXL to add hair to the character creator.
Wait, this is not what I want!
To learn more about the character creator, check Game Components explained -> Character Creator: .inkcc
To convert an existing hair mod to CCXL, check Convert a hair mod to hair CCXL mod
Requirements
You have downloaded the example project from Nexus
TL;DR
If you would rather understand what you're doing, please skip to Step 1: Deleting .ent files!
Download example project
Add your
.meshfile to the projectCopy the
appearances,materialEntries, andlocalMaterialDefinitionsfrom the template meshOverwrite it with your own
Overwrite the
.rigand the.animgraphwith your own, if you have themAdjust
.appfile entryIf you're not using base game textures: Change files paths in the
.miRename the
.xlfileChange translation key in the
.jsonfile to something unique for your modChange translation entries in the
.inkcharactercustomizationfileCustompath everything — do not publish anything that still contains tutorial files!
Profit
Let's go!
We will be moving backwards through the files: starting at the bottom, and working our way to the top (the character creation and the .xl control file).
Start by downloading the example project from Nexus
Unpack the
sourcefolder into the root of your existing hair project so that it merges with yoursMove any
.mesh,.animgraph, and.rigfiles from your original hair toyour_modder_name\ccxl\your_first_addition\meshes
Step 0: Deleting empty meshes
Starting with 8.16.2, Wolvenkit has the menu option Project -> Clean up -> Delete empty meshes. This will delete placeholder files from your hair mod.
Step 1: Deleting .ent files
If you don't have any .ent files, you're good!
If you do have them, delete them now – we don't need them in our CCXL projects.
Step 2: Adjusting the .app file
Your .app should look like this:

Your .app partsOverrides should look like this:

Wait, I'm missing meshes!
If you have more than one .mesh file, for every additional mesh, complete the following steps:
Duplicate the
entAnimatedComponentChange the
rig's depot path to the relative path of the corresponding .rig fileChange the
graph'sdepot path to relative path of the corresponding .animgraph fileChange the
nameso that it's unique (add_pt_1at the end or number it)
Duplicate the
entSkinnedMeshComponentchange the depot path to point it at your extra mesh
Select
parentTransformand change thebindNameto yourentAnimatedComponent's name (step 1c above)Select
skinningand change thebindNameto yourentAnimatedComponent's name (step 1c above)Change the
nameto be unique
Duplicate the
appearancePartComponentOverridesinpartsOverrideschange the
componentNameto your newentSkinnedMeshComponent's name from step 2repeat this step for each new meshComponent you add
Optional: Component uniqueness
If you are running into issues, you can assign unique
ids to all of your components. Go through them one by one, select theiridattribute, and select "Generate new CRUID" from the context menu.
How does this work?
Thanks to ArchiveXL magic, your .app file needs only one appearance. All other appearances will be extrapolated from it!
You can use any of the existing base game hair colours, as long as the definition itself is valid.
The template file has three .app files – one of them is for your hair's default appearance, one is for the cyberware_01 appearance, and one is for the first person hair.
If you do not have a cyberware_01 appearance, you can delete this file and adjust the file path under Step 6: The .inkcharactercustomization file
Step 3: The .mesh files
This section will explain how ArchiveXL works its magic to pick all the right hair colours and -textures from three entries and a piece of duct tape.
We'll now go through everything step by step.
3.1 Appearances
As you can see, you only need a single appearance — ArchiveXL will generate all the rest.
If your hair mesh is set up differently from the template file, you need to adjust the chunk materials here!

In our example, the first submesh uses the material @long, and the second one the material @cap.
The names must be set as follows:
<name_of_appearance>@<name_of_material> => black_carbon@long3.2 Material definitions
The tutorial hair has only two materials, and three material entries (@context, @long, @cap):

You can define more materials here if you need them (please note the box below)
You have to use the exact material names that ArchiveXL is expecting, or extra hair colours won't work.
For a full list, see CCXL Theory: Scopes and extensions -> Hair materials
Now, let's look at the materials themselves.
3.3 Materials
You have to repeat this step for every mesh file in your project. Be careful, as different meshes may use different texture sets. In this case, you need an extra .mi file for them.
@context
This is a blank container for storing contextual parameters. This is not a functioning material instance.
You can use contextual parameters in any mesh by creating a blank material named @context .
Please note the following:
It should always be the first
materialEntries. That is, it should always be index position 0.baseMaterialshould always be null.In
valuesyou then create a key whose value is a string of typeCpuNameU64.If you wish to use basegame materials as is, this string may be any context BaseMaterial in PlayerCustomizationHairFix.xl. e.g.:
context:
LongBaseMaterial: base\characters\common\hair\textures\hair_profiles\_master__long_bright.mi
CapBaseMaterial: archive_xl\characters\common\hair\textures\hair_profiles\hh_025_ma__pompadour_cap.miYou can find all of the fix xl configs in "Cyberpunk 2077\red4ext\plugins\ArchiveXL\Bundle\". Do not modify these files in any way, as they are required for CCXL hair implemention to function correctly.
If you wish to change basegame materials (e.g. path to custom hair textures), then your @context string will be a path to one of the external material instance (
.mi) files in the project.You can create a contextual parameter by doing the following:

You need to create one entry for every type of material that you want ArchiveXL to expand.
For a full list, see CCXL Theory: Scopes and extensions-> Hair materials
If your hair is using a material multiple times (e.g. long, long, cap), you still create only one LongBaseMaterial value.

@long
This material defines the hair cards. It points at the .mi file in your project, where the hair's textures are defined.
All ResourcePaths must have Soft flags for this to work, including the baseMaterial! (see screenshot)
Since the dynamic context does not transfer to the .mi, we need to set the HairProfile here.
The {material} placeholder in the file entry will be replaced with the chunk mask name from the appearance (e.g. black_carbon).

@cap
This material defines the hair cap (the stubbles on the scalp). It points at the .mi file in your project, where the scalp's textures are defined.

Since the dynamic context does not transfer to the .mi, we need to set the GradientMap here. Omitting this will lead to the hair cap looking way darker than it's supposed to.
Step 4: The .mi files
With the exception of the hair cap, the .mi file is a completely normal material template file (link not necessary for understanding this guide).
The hair cap base material is included within ArchiveXL. If you aren't using one, you don't need to know any of this — just move all properties without dynamic properties from the .mesh file into your .mi.

Step 5: The translation entry
Open the included .json file, and make sure to change the entries according to your needs.
There are two translation entries, because this tutorial assumes that you want to name the cyberware_01 variant differently.
For an explanation of what is what, keep reading.

femaleVariant
Your First Hair
maleVariant
leave it blank
If no value is found, then femaleVariant acts as default
primaryKey
0
Will be generated by ArchiveXL, leave it alone
secondaryKey
UI-Customization-your_first_hair
Used in the .inkcharactercustomization file to set your hair's entry name
Step 6: The .inkcharactercustomization file
inkcharactercustomization fileHere is where everything connects to each other.
Open the file, we will look at the entries now.
6.1 headGroups
These entries create character creator additions, while the CustomizationOptions define them (think of a materialDefinition and a materialInstance in a .mesh file).

6.2 gameUiSwitcherInfos
Let's take a look at the headCustomizationOptions. The first to entries of the type gameuiSwitcherInfo add our new hair to Cyberpunk's character creator menu, so that they show up when you scroll through the hairs.
The first entry
If you're only using one hairstyle mesh, keep this entry nameless, or it will overwrite the Character Creator: .inkcc's base switcher!
link: Targets one of the
headGroupsentriesnames: Contains the
headGroup'soptions

The second entry: hairstyle_cyberware
hairstyle_cyberwareThis entry defines the hairstyle for cyberware_01.
6.3 gameUiAppearanceInfos
gameUiAppearanceInfosThe template inkcc has three gameUiAppearanceInfos, one for your hair, one for the cyberware_01 variant, and one for FPP.
If you do not have an extra appearance for cyberware_01, you can re-use the default hair .app file.
Make sure to adjust the paths to your corresponding .app file:

Step 7: The .xl file
From your project's resource directory, open the .archive.xl file that you created in the previous guide. Add the following lines at the bottom (make sure that there are no leading spaces):
customizations:
female: your_modder_name\ccxl\your_first_addition\_pwa.inkcharcustomization
localization:
onscreens:
en-us: your_modder_name\ccxl\your_first_addition\localization\your_first_hair_wa__local.json
resource:
scope:
player_wa_hair.app:
- your_modder_name\ccxl\your_first_addition\appearances\your_first_hair_wa.app
- your_modder_name\ccxl\your_first_addition\appearances\your_first_hair_wa_cyberware.app
- your_modder_name\ccxl\your_first_addition\appearances\fpp\your_first_hair_wa_fpp.app
player_wa_hair.mesh:
- your_modder_name\ccxl\your_first_addition\meshes\your_first_hair_wa.mesh
- your_modder_name\ccxl\your_first_addition\meshes\your_first_hair_wa_cyberware.meshStep 8: Renaming and moving
Now it's time to custompath your project.

On some versions of WolvenKit, you might encounter an issue where a file like .inkcharcustomization fails to apply the custom path, in that case you'll have to open the file and copy relative path of your .apps
It's recommended to look in the Log view and check if there's an error in a renaming custompaths in files.
Troubleshooting
Hair colour extensions don't work on my hair!
Most likely, you screwed up the names of your material definitions. They must be exactly as ArchiveXL expects them to be. Go back to 3.2 Material definitions and double-check everything.
Otherwise, check that your componentsOverride in the partsOverrides of the .app is correctly named. (see Your .app partsOverrides should look like this:)
If that doesn't help, check the log (see CCXL: Hairs)
My hair colour doesn't change at all!
Check if material patching/expansion worked: Search the ArchiveXL log for the name of the broken hair mesh. Most likely, there is a warning or an error that you can fix.
In your
.appfile(s), check thepartsOverrides. Make sure that the component names are correct, and that the appearance is the same as the one you assigned in thecomponentsarray.
I have duplicate entry in hairstyles options!
This happens due to having a different localizedName forcyberware_hairstyle switcher that's inside the.inkcc file. For exampleUI-Customization-your_first_hair in the blank switcher, and UI-Customization-your_first_hair_cyberware in the cyberware_hairstyle switcher.
If you want to have a unique hairstyle mesh when cyberware_01 is enabled refer to 6.2 gameUiSwitcherInfos, specifically the hint about link and name.
Last updated