Skip to content

Creating a Content Pack

Floogen edited this page May 30, 2025 · 89 revisions

A content pack for Alternative Textures (AT) allows for texture variation for most placeable objects (including from Json Assets and DGA), furniture, entities (farm animals and horses) and buildings (including those from Solid Foundations).

These content packs are compatible with other AT content packs, meaning multiple packs can modify the same object (e.g. multiple AT content packs can offer alternative textures for the Mini-Obelisk object).

The concept for adding a new texture variation is very similar to replacing a texture via Content Patcher's Load action.

TL;DR Edition

  1. Create a parent folder with the content pack's name.

  2. Create and fill in manifest.json as a content pack.

  3. Create a Textures folder, add it under the content pack's main folder.

  4. Create a sub-folder under Textures with the name of the object

    a. The name of the folder(s) under Textures do not matter, but it is recommended to use the object's name for clarity.

  5. Create a texture.json under the created sub-folder, using the required fields found here.

  6. Create a texture.png under the same sub-folder.

    a. This image file should be a modified version of the object's existing sprite.

    b. You can use individual split textures (e.g. texture_0.png, texture_1.png...) rather than a single texture.png.

    c. If both split textures files and texture.png exist under the same folder, texture.png will be used instead.


Structure

An Alternative Textures content pack consists of the following structure:

[AT] Example Pack
├── manifest.json
│
└── Textures
    ├── Cask_Summer
    │   ├── texture.json
    │   └── texture.png
    │
    ├── Suit_Of_Armor
    │   ├── texture.json
    │   ├── texture_0.png
    │   └── texture_1.png
    │
    └── Sunflower
        ├── texture.json
        └── texture.png

If this is your first time creating a content pack, it may be useful to read the Stardew Valley Wiki for creating a content pack.

 

First Steps

The first step to making your content pack is to create a top level folder with the name of your content pack. For example: [AT] Example Pack.

After that, you'll want to create the manifest.json file under that folder. Detailed instructions can be found on the Stardew Valley Wiki. Additionally, you can check out the example manifest.json as a reference.

For example:

[AT] Example Pack
└──  manifest.json



It is important to note that the manifest.json file must contain the following for it to be a content pack by Alternative Textures:

"ContentPackFor": {
    "UniqueID": "PeacefulEnd.AlternativeTextures",
    "MinimumVersion": "USE.LATEST.VERSION"
}

Note: Replace "MinimumVersion": "USE.LATEST.VERSION" with the latest version number of Alternative Textures found here.

 

Creating Textures

The folder structure

You will first need to create a Textures folder underneath your main content pack folder.

After creating the Textures folder you'll want to create a sub-folder for every object you want to modify, like so:

.
└── Textures
    ├── Poppy
    │
    ├── Suit_Of_Armor
    │
    ├── MiniObelisk_Summer
    │
    └── MiniObelisk_Winter

You can also have sub-folders under the Textures folder for organizing, like so:

.
└── Textures
    ├── Summer
    │   ├── MiniObelisk
    │   └── Poppy
    │
    └── Winter
        └── MiniObelisk

 

Adding texture variation

To add an alternative texture to your content pack, the framework requires a texture.json under each sub-folder of Textures.

For example:

.
└── Textures
    ├── Poppy
    │   ├── texture.json
    │   └── texture.png
    │
    ├── Suit_Of_Armor
    │   ├── texture.json
    │   ├── texture_0.png
    │   └── texture_1.png
    │
    ├── MiniObelisk_Summer
    │   ├── texture.json
    │   └── texture.png
    │
    └── MiniObelisk_Winter
        ├── texture.json
        └── texture.png

The file texture.json determines what object to give alternative textures and what variations to apply.

An overview of the required properties for texture.json:

Property Description Default
ItemName Optional1 Name of the item which must match exactly to the item's name.
See this page for more details
N/A
ItemId Optional1 Id of the item which must match exactly to the item's ID.
See this page for more details
N/A
CollectiveNames Optional1 List of ItemName which allows for multiple items to be associated to the texture.
See this section for more details
[]
CollectiveIds Optional1 List of ItemId which allows for multiple items to be associated to the texture.
See this section for more details
[]
Type Required The type of the item (e.g. Crop for crops, Craftable for chests)
See this page for more details
N/A
Keywords Optional Used by paint bucket's search function to allow for easier searching of specific textures ["UNIQUEID"]
Seasons Optional The specific seasons for the textures to appear (leaving blank will allow for all seasons)
See this section for more details
[]
TextureWidth 2 Required Width of the texture in pixels
Note: This is the width of the item's vanilla texture, which may not match to texture.png's width
N/A
TextureHeight 2 Required Height of the texture in pixels
Note: This is the height of the item's vanilla texture, which may not match to texture.png's height
N/A
Variations Required The number of variations within textures.png (i.e. rows of variations)
Required if not using ManualVariations
1
DefaultVariation Optional If specified, the framework will always use the given variation when randomly selecting from this pack.
Overrides ChanceWeight for ManualVariations.
N/A
ManualVariations Optional Overrides Variations
See this section for more details
N/A
Animation Optional A list of frames and durations, which allow for animation.
Only supported for Furniture and Craftable objects.
See this section for more details
N/A
IgnoreBuildingColorMask Optional If set to true, the framework will ignore the paint mask texture required for certain buildings.
Only applicable to Type.Building.
N/A
  1. ItemName, ItemId, CollectiveNames or CollectiveIds must be given for the texture to be valid.
  2. TextureWidth and TextureHeight require the dimensions of the item being replaced, which may not exactly match the width or height of texture.png.
    a. Sunflowers would have a TextureWidth of 96 and a TextureHeight of 32.
    b. Mini-Obelisks would have a TextureWidth of 16 and a TextureHeight of 32.
    c. Apple Sapling would have a TextureWidth of 432 and a TextureHeight of 80.
    d. Loom would have a TextureWidth of 16 and a TextureHeight of 32.
    e. Gate would have a TextureWidth of 48 and a TextureHeight of 224.
    f. Wood Fence would have a TextureWidth of 48 and a TextureHeight of 128.
    g. Brown Couch would have a TextureWidth of 128 and a TextureHeight of 96.
    h. Sprinkler would have a TextureWidth of 16 and a TextureHeight of 32.

Note: The framework expects all available frames for items with animations, such as the Loom. See the example pack for reference.

Basic json example

This is a simple texture.json, which adds a two texture variations for the Sunflower object.

{
  "ItemName": "Sunflower Seeds",
  "Type": "Crop",
  "TextureWidth": 96,
  "TextureHeight": 32,
  "Variations": 2
}

You can see Variations was given the value of 2. This value reflects the amount of rows within texture.png, which is divided by the given value in TextureHeight.

In this example, each texture variation has a ~33% chance of occurring (one third for each of the two variations and one third for the default game texture).

Basic texture example

The corresponding texture.png

The texture.png should (in most cases) be a "copy" of the original sprite in terms of TextureWidth.

See the example pack for references on how to create your textures.

Split texture example

The framework normally expects a single texture.png that contains all the variations of the particular object for its respective texture.json.

Individual texture files can be used instead of a single file, if the following rules are observed:

  • Each individual texture file must use the naming scheme of texture_#.png.
  • The first split texture variation of an object should always be the name of texture_0.png or texture_1.png.
  • If you mix both texture.png and split textures (i.e.texture_#.png), the former will be used instead.

See this example of an object with split texture variation files.

The corresponding split texture image files:

texture_1.png

texture_2.png

Animated json example

This is an example texture.json, which shows variations for the animated machine Loom object.

{
  "ItemName": "Loom",
  "Type": "Craftable",
  "TextureWidth": 16,
  "TextureHeight": 32,
  "Variations": 2
}

You can see Variations was given the value of 2. This value reflects the amount of rows within texture.png, which is divided by the given value in TextureHeight.

Animated texture example

The corresponding texture.png

The texture.png should (in most cases) be a "copy" of the original sprite in terms of TextureWidth.

Note: The Loom is one of the exceptions for how texture.png is to be used.

Using seasons

The optional Seasons property accepts an array of season names. If specified, the framework will limit the texture's appearance to only occur during those specified seasons. This is useful if you want to display different textures for different seasons, such as with fences.

If your content pack does not have a match to a season (and you specified other seasons for the object), the framework will display the default vanilla texture.

For example, consider the following summer texture variation:

{
  "ItemName": "Apple Sapling",
  "Type": "FruitTree",
  "Seasons": ["Summer"],
  "TextureWidth": 432,
  "TextureHeight": 80,
  "Variations": 2
}

In the above example, the framework would only use that texture if the sapling was planted during the summer (and if it was picked from the available pool of apple sapling summer textures).

Once the season becomes fall, the framework will temporarily revert it back to the vanilla texture until the summer season reoccurs.

However, if you included another apple sapling texture variation within the same content pack like so:

{
  "ItemName": "Apple Sapling",
  "Type": "FruitTree",
  "Seasons": ["Spring", "Fall", "Winter"],
  "TextureWidth": 432,
  "TextureHeight": 80,
  "Variations": 2
}

The framework would then utilize those texture variations when the seasons changed from summer, instead of the default vanilla textures.

Using manual variations

You'll notice the sunflower example used the Variation property with a given value of 2 with an even chance of occurring for any of the variations.

If you want to give each texture variation a different chance of occurring, then you can utilize the ManualVariation property like so:

{
  "ItemName": "Sunflower Seeds",
  "Type": "Crop",
  "TextureWidth": 96,
  "TextureHeight": 32,
  "ManualVariations": [
    {
      "Id": -1, // Note: -1 is the default vanilla texture. It is not required, but it allows better control of when the vanilla texture appears
      "ChanceWeight": 0.9  // This is an optional value which determines the chance of this variation appearing (see details below)
    },
    {
      "Id": 0,
      "Name": "Custom Name Here", // This is an optional value which overrides how the framework displays its name (see details below)
      "ChanceWeight": 0.1
    },
    {
      "Id": 1,
      "ChanceWeight": 0.5
    }
  ]
}

Note: The Id field is zero-indexed, meaning the first texture has an Id of 0, the second texture is 1 and so on.

Additional Note: If you specify an Id of -1, you can override the probability of the vanilla texture being chosen.

Name

The optional Name property is a text value which will override how the texture's name is displayed in the various UI's available in the framework (Paint Bucket, Scissors).

If the property is not given, the framework will display the name as the content pack's UniqueID and the texture's variation (i.e. it'll be displayed as UniqueID -> Variation #).

ChanceWeight

The optional ChanceWeight property is a decimal value from 0 to 1.0 which determines the likelihood of a texture being selected when the object or entity is created. This property is only available if using ManualVariations.

Each variation under ManualVariations has its own independent probability of appearing via ChanceWeight. This means if two variations use a ChanceWeight of 0.75, then both have a 75% chance of occurring (assuming the vanilla texture isn't picked).

As this property is optional, omitting will result in a ChanceWeight value of 1.0.

Using keywords

The Keywords property is used by the paint bucket tool to allow users to more easily search for specific textures for the selected item.

By default, the Keywords property is populated with the content pack's UniqueId value in manifest.json. Example Keywords usage:

{
  "ItemName": "Sunflower Seeds",
  "Type": "Crop",
  "TextureWidth": 96,
  "TextureHeight": 32,
  "Keywords": [ "Test", "Other test", "Etc." ],
  "Variations": 2
}

Manual variations are also capable of utilizing the Keywords property with some slight differences:

  • The top-level parent Keywords shares its values with all ManualVariations.
  • Keywords listed in ManualVariations aren't shared with the top-level parent Keywords.
  • Keywords listed in ManualVariations aren't shared with other variations.

Example ManualVariations Keywords usage:

{
  "ItemName": "Sunflower Seeds",
  "Type": "Crop",
  "TextureWidth": 96,
  "TextureHeight": 32,
  "Keywords": [ "This is shared with all ManualVariations" ],
  "ManualVariations": [
    {
      "Id": -1, // Note: -1 is the default vanilla texture. It is not required, but it allows better control of when the vanilla texture appears
      "ChanceWeight": 0.9
    },
    {
      "Id": 0,
      "ChanceWeight": 0.1,
      "Keywords": [ "This is not shared with top-level", "This is not shared with other variations" ]
    },
    {
      "Id": 1,
      "ChanceWeight": 0.5
    }
  ]
}

Using animations

The Animation property allows for custom animation of Craftable and Furniture objects. Each Frame should be an adjacent to the sprite within the texture image file.

The Frame field refers to the "column" to use in the texture, with 0 being the leftmost sprite.

The Duration field takes a value in milliseconds, which determines how long that particular frame lasts before moving on.

Example Animation usage:

{
  "ItemName": "Tree of the Winter Star",
  "Type": "Furniture",
  "TextureWidth": 16,
  "TextureHeight": 32,
  "Variations": 1,
  "Animation": [
    {
      "Frame": 0,
      "Duration": 1000
    },
    {
      "Frame": 1,
      "Duration": 1000
    },
    {
      "Frame": 2,
      "Duration": 1000
    }
  ]
}

The associated texture.png for the above texture.json:

Manual variations are also capable of utilizing the Animation property, so each variation can have its own animation (or not at all).

Example ManualVariations Animation usage:

{
  "ItemName": "Recycling Machine",
  "Type": "Craftable",
  "TextureWidth": 16,
  "TextureHeight": 32,
  "ManualVariations": [
    {
      "Id": 0,
      "Animation": [
        {
          "Frame": 0,
          "Duration": 500
        },
        {
          "Frame": 1,
          "Duration": 1500
        },
        {
          "Frame": 2,
          "Duration": 1500
        },
        {
          "Frame": 3,
          "Duration": 1500
        }
      ]
    },
    {
      "Id": 1,
      "Keywords": [ "Blue" ],
      "Animation": [
        {
          "Frame": 0,
          "Duration": 500
        },
        {
          "Frame": 1,
          "Duration": 1500
        },
        {
          "Frame": 2,
          "Duration": 500
        },
        {
          "Frame": 3,
          "Duration": 1000
        }
      ]
    }
  ]
}

The associated texture_0.png and texture_1.png for the above texture.json:

Filtering Frames with FrameType

Frames can be filtered to only play when certain conditions are true.

The full list of FrameTypes are as follows:

Property Description
Default Always plays
MachineIdle Plays when the machine is idle (i.e. when the machine is not processing items).
Only applicable to machines.
MachineActive Plays when the machine is active (i.e. when the machine is processing items).
Only applicable to machines.
{
  "ItemName": "Cask",
  "Type": "Craftable",
  "TextureWidth": 16,
  "TextureHeight": 32,
  "ManualVariations": [
    {
      "Id": 0,
      "Animation": [
        {
          "Frame": 0,
          "Duration": 500,
          "Type": "Default"
        },
        {
          "Frame": 1,
          "Duration": 500,
          "Type": "MachineActive"
        },
        {
          "Frame": 2,
          "Duration": 500,
          "Type": "MachineActive"
        },
        {
          "Frame": 3,
          "Duration": 500,
          "Type": "MachineActive"
        },
        {
          "Frame": 4,
          "Duration": 500,
          "Type": "MachineIdle"
        },
        {
          "Frame": 5,
          "Duration": 500,
          "Type": "MachineIdle"
        }
      ]
    }
  ]
}

The associated texture.png for the above texture.json:

Animation Exceptions

Some objects are not supported for animations, which are listed below:

  • Torch

Using tints

The optional Tints property is used by the framework to determine which overlay to apply to manual variations. It accepts a list of int[] values, which the framework will pick from randomly.

Note: Tints is only usable for ManualVariations and only supports the following Type textures:

  • Crop

Example Tints usage:

{
  "ItemName": "Poppy Seeds",
  "Type": "Crop",
  "TextureWidth": 112,
  "TextureHeight": 32,
  "Variations": 5,
  "ManualVariations": [
    {
      "Id": -1, // Note: -1 is the default vanilla texture. It is not required to give it, though allows user to 
      "ChanceWeight": 0.9
    },
    {
      "Id": 0,
      "Tints": [
        [ 255, 255, 255, 255 ] // Use this color (white) to have the game skip applying a tint to the flower
      ],
      "ChanceWeight": 0.1
    },
    {
      "Id": 1,
      "Tints": [
        [ 100, 125, 255, 255 ]
      ],
      "ChanceWeight": 0.5
    },
    {
      "Id": 2,
      "ChanceWeight": 0.5
    },
    {
      "Id": 3,
      "ChanceWeight": 0.5
    },
    {
      "Id": 4,
      "ChanceWeight": 0.5
    }
  ]
}

Using collective textures

The CollectiveNames or CollectiveIds property can be used in place of ItemName and ItemId respectively to allow textures to be usable across multiple objects.

Note: Items listed in CollectiveNames and CollectiveIds should be of the same size to avoid any display issues.

Example CollectiveNames usage, which makes a texture available to all vanilla chairs:

{
  "CollectiveNames": [
    "Oak Chair",
    "Walnut Chair",
    "Birch Chair",
    "Mahogany Chair",
    "Red Diner Chair",
    "Blue Diner Chair",
    "Breakfast Chair",
    "Pink Office Chair",
    "Purple Office Chair",
    "Green Office Stool",
    "Orange Office Stool",
    "Dark Throne",
    "Dining Chair",
    "Green Plush Seat",
    "Pink Plush Seat",
    "Winter Chair",
    "Groovy Chair",
    "Cute Chair",
    "Stump Chair",
    "Metal Chair",
    "Green Stool",
    "Blue Stool",
    "King Chair",
    "Crystal Chair"
  ],
  "Type": "Furniture",
  "TextureWidth": 48,
  "TextureHeight": 64,
  "Variations": 2
}

Next Step

If you're looking for examples, see the examples page.

If you'd like to utilize Content Patcher to modify the texture.png based on conditions, see Content Patcher integration.

Clone this wiki locally