🌈CrystalCoat™
Adding CrystalCoat to your custom vehicle
Background
CrystalCoat™ works in a unique way: they make use of Inkwidgets
Inkwidgets are used to create in-game UI - like car interior UI, in-game computers, etc
This is important to understand because if you're hearing inkwidgets for the first time - you have to understand, this is not what they are traditionally used for. The game cleverly hacked inkwidgets to use as a dynamic material. Imagine car paint but it's made of tiny LEDs. So while it's brilliant in theory, it has its own challenges when adding to a custom vehicle.
CrystalCoat is made possible with two core components:
The core inkwidget: this consists of two
inkImageWidget
:primaryColor
and asecondaryColor
painted on a mask textureThe Crystal Coat .mt (
base\vehicles\common\materials\vehicle_modding_destruction.mt
): this multilayer shader works behind the scenes to load/unwrap the above inkwidget onto the car part, whereas traditional inkwidgets would need a separate submesh - CrystalCoat inkwidgets don't.
How to add Crystal Coat
.ent
In your vehicle's .ent file, add a new appearance for Crystal Coat

We also need an entEffectSpawnerComponent for Crystal Coat fx effects. You can copy paste this as-is from the Aerondight .ent (base\vehicles\sport\v_sport1_rayfield_aerondight__basic_01.ent
): EffectSpawner3546

.app
Define the appearance that you just created in the .ent: You can duplicate your default appearance to start with.
Updating mesh appearances
For all the meshes that will change color, we need to add a new mesh appearance that uses the .mt I mentioned earlier
To do this, simply duplicate your default mesh appearance, add a new
customizable
material entry, and copy-paste the material definition from for eg.base\vehicles\sport\v_sport1_rayfield_aerondight\entities\meshes\v_sport1_rayfield_aerondight__ext01_hood_a_01.mesh

customizable
material entry. Remember to add your vehicle's MLmask and MLsetup paths
customizable
material for submeshes that need to change colorRemember to update the material values with your custom vehicle's mlsetup and mlmask paths
Set the
customizable
material entry for all the submeshes that change color
Adding WorldWidgetComponent
WorldWidgetComponent
Go to Aerondight's .app file (
base\vehicles\appearances\sport\rayfield_aerondight__basic.app
) and find its customizable appearance ( appearances > player_01_customizable_01)Copy and paste all
WorldWidgetComponent
s related to Crystal Coat (all of them will start withvisual_customization_
) to your customizable appearanceUpdate the
parentTransform
andmeshTargetBinding
for each of the components to the respective car part in your appearance as needed (they don't necessarily need to match one to one: for e.g., you can use the fuel_cap WorldWidgetComponent for something that's not a fuel cap)

.yaml / tweak edits
Add the following to your vehicle's tweak:
That's it! Install and launch - and you should see something happen.
Addressing issues
Unless you're extremely lucky, you should start seeing issues. Roughly there are two buckets of issues:
Glitches
What this is: Crystal Coat paint glitching to black or something in certain angles or certain TPP camera views
There are a few known causes and way to fix this:
You have more than 10
WorldWidgetComponent
sThe game currently for whatever reason (likely for resource management) glitches if you have more than 10
WorldWidgetComponent
s defined and used in your customizable appearanceTo address this, for now, you can try joining meshes like the fuelcap doesn't need to be a separate mesh, it can be part of the body so you can save 1 WorldWidgetComponent
Angled meshes
Sometimes, or even randomly, certain meshes that are angled like door meshes for instance, can have a persistent glitch effect that comes and goes in certain angles
To address this, first try 'breaking' the component name
Crystal Coat identifies different car parts by looking at their component names, which are standard and common across cars like
door_fl_a
, etcSo for example, if you're facing glitches on your left door, try renaming your
door_fl_a
entPhysicalMeshComponent >door_fl_a_broken
Remember to update
parentTransform
andmeshTargetBinding
for the correspondingWorldWidgetComponent
and see if this fixes your issueIf it does, rememeber to also update the
destruction
>detachableParts
tweak record in your vehicle's tweak file since the door component name is now different
Artifacts
What this is: rectangluar or something artifacts on the paint OR inconsistent or incorrect direction of gradient colors
To fix this, we need to understand how the core inkwidget functions
To do this let's look at the Crystal Coat inkwidget (WorldWidgetComponent
> widgetResource
> base\gameplay\vehicles\visual_customization\vvc_car_appearance_widget.inkwidget
)
Click into the "Widget Preview" tab > Export inkWidget as XML > save and open the XML file
The XML file (although currently Wkit doesn't support editing XML > inkwidget) will give you a good overview of how the inkwidget functionally works.
There are a lot of components (that aren't really needed -- we will see this in the next section) however the most important section is this one:

Here we see two InkImageWidgets
being defined for the two colors that can be set for Crystal Coat. We also see a textureAtlas
-> this is the mask which defines how the color is painted and controlled further with the layout
and renderTransform
values.
This is primarily what we're concerned with. The artifacts originate from these masks and any other color gradient issues as well
For most custom vehicles, it makes sense to have only one color i.e primaryColor as the customizable option. While it is possible to define both and somehow adjust the layout values to get the correct orientation, I have not tried that so let's focus on making this inkwidget paint ONLY the primaryColor
To do this, go back to the edit view and go to libraryItems > Root > package > inkWidgetLibraryItemInstance > gameController
You should see primaryColor
and secondaryColor
From here you need to swap the mask with a completely white mask, adjust the layout an d renderTransform values so that primaryColor occupies the entire space. Then you need to make secondaryColor disappear similarly: you can delete the textureAtlas value and make the size = 1,1 which should make it disappear.
If you don't want to do all of this, feel free to download this inkwidget where I've already done all of this: https://www.nexusmods.com/cyberpunk2077/mods/13947
You can see a demonstration of this primaryColor-only functionality in this custom vehicle mod: https://www.nexusmods.com/cyberpunk2077/mods/13396
Note - you might also notice glitchAnims (and a dedicated an .inkanim file): these are used when the car gets hit by a bullet or collission. Feel free to remove or tweak thos as well.
Color accuracy
As of 2.12a, the base color (i.e. defined in the mlsetup of the customizable
mesh appearance) of the vehicle has a heavy influence on the final Crystal Coat color
For eg, if your base color is white, then it's impossible to get accurate darker colors. And vice versa.
This is unfortunately not a problem that can be fixed in the core inkwidget, and needs messing with the shader itself which this mod by ShinnPL does: https://www.nexusmods.com/cyberpunk2077/mods/13685 by (likely) changing how the inkwidget/crystal coat shaders work under the hood
Changing the GUI
The Crystal Coat GUI is primary controlled via this Inkwidget: base\gameplay\gui\widgets\notifications\vehicle_visual_customization.inkwidget
If you want to load a custom GUI for your custom vehicle, you can use this redscript:
Script credits thanks to hgyi56
How to edit the Crystal Coat GUI
You can replace assets by adding the respective .inkatlases to your project and linking them inside the inkwidget (fool proof of way of doing this is by converting the inkwidget to JSON, CTR + F and replace paths)
This way you can replace the default car preview with your own, remove the Rayfield logo, etc. You can also change the text by editing the Lockey
To remove the secondary color picker, CTR + F in the inkwidget JSON for
inkCircleInnerWidget
,colorPickerInner
,pointerTargetSelectedInner
,inner-circle
,gradient_circle_inner
,color_wheel_inner
,CirclesInner
and set theiropacity
values: 0. Also set theisInteractive
value to 0 (wherever it is set to 1 for the mentioned). You can then adjust the outer color picker as well, replace it with maybe a thicker color wheel like so in the inkatlas file:
This gui inkwidget is also available at https://www.nexusmods.com/cyberpunk2077/mods/13947
Last updated
Was this helpful?