> For the complete documentation index, see [llms.txt](https://sebun1.gitbook.io/skins/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sebun1.gitbook.io/skins/schema/material-target.md).

# Material Target

## Overview

A **Material Target** declares which material to modify and exactly what to do to it when its parent Skin Group is active on a gear. Each target lives in its own `.mattarget.json` file placed anywhere inside the skin group's folder tree — the mod discovers them recursively.

For a easy way to create Material Target manifest files, check out [Editing Material Targets](/skins/editor/editing-material-targets.md).

{% hint style="warning" icon="triangle-exclamation" %}
Multiple Material Targets with different configurations that target the **same material** within the **same** Skin Group is **undefined behavior**! There is no guarantee as to which material target definition will be used. If you want to provide different versions of a gear part (say for different guns), you **NEED** to do so in different Skin Groups!
{% endhint %}

## File Naming & Folder Structure

Files must have the extension `.mattarget.json`. The filename itself is free-form.

```
my-skin/
  manifest.skingroup.json
  rifle.mattarget.json            ← any name is fine
  details/
    scope.mattarget.json          ← nesting is fine too
```

## Manifest Schema

```jsonc
{
  "material_name": "Front_Pistol_4",
  "match_groups": [ /* optional variant filter */ ], // legacy: matchGroups
  "shader": "Cell/Player/CustomGearShader", // optional shader override
  "properties": {
    "_MainTex": {
      "type": "Texture2D",
      "data": { "src": "textures/albedo.png" }
    }
  }
}
```

### Fields

<table><thead><tr><th width="141.9998779296875">Field</th><th width="139.66650390625">Type</th><th width="106.333251953125" data-type="checkbox">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>material_name</code></td><td>string</td><td>true</td><td>Exact name of the material to match. Must match the in-game material name precisely (case-sensitive).</td></tr><tr><td><code>match_groups</code></td><td>array of match group objects</td><td>false</td><td>Optional variant filter used to disambiguate materials that share a name. See <a data-mention href="#variant-matching">#variant-matching</a>. When absent or empty, all variants of the named material are matched.</td></tr><tr><td><code>shader</code></td><td>string</td><td>false</td><td>If set, the material's shader is replaced with this shader before any properties are applied.</td></tr><tr><td><code>properties</code></td><td>object (property map)</td><td>false</td><td>Dictionary of shader property name → property definition. See Properties.</td></tr></tbody></table>

## Variant Matching

Some materials in GTFO share the same name (for example, `"Spear"` exists on multiple unrelated items). `matchGroups` lets you add additional texture-name conditions to narrow down the match.

The structure mirrors the filter system on Skin Groups: it is a **DNF**. The target matches when **any** group in `matchGroups` matches, and a group matches when **all** of its conditions match.

Each condition checks whether a specific texture slot on the material carries an expected in-game texture name:

```jsonc
"matchGroups": [
  {
    "conditions": [
      { "slot": "_MainTex", "value": "mat_spear_playerMain" }
    ]
  }
]
```

When `matchGroups` is empty or omitted, the target matches all variants of the material (wildcard).

### Condition Object Fields

<table><thead><tr><th width="124">Field</th><th width="134">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>slot</code></td><td>string</td><td>The shader texture slot to inspect (e.g. <code>_MainTex</code>).</td></tr><tr><td><code>value</code></td><td>string</td><td>The expected in-game texture name currently assigned to that slot.</td></tr></tbody></table>

Use the **Select Material** dialog in the SkinGroup Editor, or check the gear dump, to find and fill in the correct in-game texture names.

## Properties

The `properties` map is keyed by shader property name (e.g. `_MainTex`, `_Glossiness`). Each value is an object with a `type` discriminator and a `data` payload:

```jsonc
"properties": {
  "_MainTex": { "type": "Texture2D", "data": { "src": "albedo.png" } },
  "_Glossiness": { "type": "Float",  "data": { "value": 0.5 } }
}
```

If a property name does not exist on the material's current shader, or the type does not match, the property is skipped and a warning is logged — it will not cause a crash.

### Property Types

{% tabs %}
{% tab title="Texture2D" %}
Sets a texture slot.

```jsonc
{
  "type": "Texture2D",
  "data": {
    "src": "textures/albedo.png",
    "options": "Albedo"
  }
}
```

<table><thead><tr><th width="94.5">Field</th><th width="145.8333740234375">Type</th><th width="106.833251953125" data-type="checkbox">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>src</code></td><td>string</td><td>true</td><td>Path to the texture file, relative to the <code>.mattarget.json</code> file's directory. Can also be a Texture Macro expression (e.g. <code>@WHITE</code>).</td></tr><tr><td><code>options</code></td><td>string or object</td><td>false</td><td>Import options. When omitted, options are inferred from the slot name automatically (see below).</td></tr></tbody></table>

#### **Import Options**

<table><thead><tr><th width="157.3333740234375">Value</th><th width="104.1666259765625">Linear</th><th width="115.3333740234375">Mipmaps</th><th>Use for</th></tr></thead><tbody><tr><td><code>"Albedo"</code></td><td>false</td><td>true</td><td>Color/albedo maps</td></tr><tr><td><code>"Data"</code></td><td>true</td><td>true</td><td>Normal maps, metallic-smoothness, masks</td></tr><tr><td><code>"AlbedoNoMips"</code></td><td>false</td><td>false</td><td>UI / decal textures that should not be mipmapped</td></tr><tr><td><code>"DataNoMips"</code></td><td>true</td><td>false</td><td>Data maps that should not be mipmapped</td></tr></tbody></table>

You can also supply a custom object (**this is the most canonical form**):

```jsonc
"options": { "linear": true, "mipmaps": false }
```

When `options` is omitted the mod infers sensible defaults from the slot name — for example, slots containing `normal` or `bump` default to linear + no mipmaps, while color slots default to non-linear + no mipmaps. It is fine to rely on our inference for standard Unity shader slots.

#### Mipmaps

The base game will not create mipmaps for the custom textures that we load. To include mipmaps, set the `mipmaps` key to true for import options as mentioned above.

***

Internally we initialize textures using the provided options by calling the following

```cs
	new Texture2D(..., mipChain: options.Mipmaps, linear: options.Linear);
```

#### Special Cases

**Emissive Maps**

When the property name is `_EmissiveMap`, the mod automatically enables the `ENABLE_EMISSIVE` material keyword so the emissive actually renders.
{% endtab %}

{% tab title="Float" %}
Sets a float or range shader property.

```jsonc
{
  "type": "Float",
  "data": { "value": 0.75 }
}
```

<table><thead><tr><th width="116.5">Field</th><th width="125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>value</code></td><td>float</td><td>The float value to set.</td></tr></tbody></table>
{% endtab %}

{% tab title="Color" %}
Sets a color shader property. Each channel is a float in the `0`–`1` range.

```jsonc
{
  "type": "Color",
  "data": { "r": 1.0, "g": 0.2, "b": 0.2, "a": 1.0 }
}
```

<table><thead><tr><th width="104.5001220703125">Field</th><th width="116.6666259765625">Type</th><th width="107.333251953125">Default</th><th>Description</th></tr></thead><tbody><tr><td><code>r</code></td><td>float</td><td><code>0</code></td><td>Red channel (0–1)</td></tr><tr><td><code>g</code></td><td>float</td><td><code>0</code></td><td>Green channel (0–1)</td></tr><tr><td><code>b</code></td><td>float</td><td><code>0</code></td><td>Blue channel (0–1)</td></tr><tr><td><code>a</code></td><td>float</td><td><code>1</code></td><td>Alpha channel (0–1)</td></tr></tbody></table>
{% endtab %}

{% tab title="Vector" %}
Sets a Vector4 shader property (commonly used for tiling/offset or custom packed data).

```jsonc
{
  "type": "Vector",
  "data": { "x": 2.0, "y": 2.0, "z": 0.0, "w": 0.0 }
}
```

<table><thead><tr><th width="111.1666259765625">Field</th><th width="106.166748046875">Type</th><th width="112.5">Default</th><th>Description</th></tr></thead><tbody><tr><td><code>x</code></td><td>float</td><td><code>0</code></td><td>X component</td></tr><tr><td><code>y</code></td><td>float</td><td><code>0</code></td><td>Y component</td></tr><tr><td><code>z</code></td><td>float</td><td><code>0</code></td><td>Z component</td></tr><tr><td><code>w</code></td><td>float</td><td><code>0</code></td><td>W component</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

## Full Example

```jsonc
{
  "material_name": "Head_Hammer_5",
  "matchGroups": [
    {
      "conditions": [
        { "slot": "_MainTex", "value": "Head_Hammer_5_Albedo" }
      ]
    }
  ],
  "properties": {
    "_MainTex": {
      "type": "Texture2D",
      "data": { "src": "textures/albedo.png", "options": "Albedo" }
    },
    "_NormalMap": {
      "type": "Texture2D",
      "data": { "src": "textures/normal.png", "options": "Data" }
    },
    "_EmissiveMap": {
      "type": "Texture2D",
      "data": { "src": "textures/em.png" } // options inferred to be "AlbedoNoMips" for _Em
    },
    "_MetallicGlossMap": {
      "type": "Texture2D",
      "data": { "src": "@METALLIC_SMOOTHNESS(0.8,0.6)" }
    },
    "_Glossiness": {
      "type": "Float",
      "data": { "value": 0.6 }
    }
  }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sebun1.gitbook.io/skins/schema/material-target.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
