Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
G4 - Pack Folder Structure
Updated a week agoPack Folder Structure
This page is for creators. By the end you'll know exactly where to put a file so Stitchwork picks it up.
If you're a player, you don't need to read this — pack authors handle the structure for you.
Explore the layout
Click through a real pack — and your own workspace — below. Switch pack type along the top; pick any folder or file to see what it's for, an example path (real Silksong assets), and the page that explains it.
The basic shape
A pack is a folder. Inside the folder, you have subfolders for each type of asset you're replacing:
my-cool-pack/
Sprites/ ← image replacements (most common)
Spritesheets/ ← whole-atlas image replacements (advanced)
Sounds/ ← audio: SFX and music
Videos/ ← cutscene replacements
Text/ ← dialogue, item names, UI text
pack.json ← optional: pack name/author/version (shown in the Pack Manager)
manifest.json ← required for Thunderstore distribution
README.md ← what your pack does, optional but recommended
icon.png ← Thunderstore display icon, 256×256
You don't need every folder — only the ones for asset types you're
actually replacing. A pack that only changes music has a Sounds/
folder and skips the rest.
Naming your pack — pack.json
Optional, but it's how your pack shows up in the Pack Manager. A small
JSON file that sits next to your asset folders — inside Stitchwork/ for
a Thunderstore pack, or at the pack root for a local Packs/{name}/ pack:
{ "name": "Crystal Hornet", "author": "You", "version": "1.0.0", "description": "A crystalline reskin of Hornet." }
All four fields are optional; without pack.json (or without a name), the
Pack Manager just shows the folder name. Don't confuse it with manifest.json
— that's Thunderstore's packaging file (store listing, dependencies), which
Stitchwork itself never reads. See Distributing Your Pack.
Where the pack folder lives
Two valid locations:
Option A: as a Thunderstore package (recommended for distribution)
BepInEx/plugins/your-pack-name/Stitchwork/
Sprites/
Sounds/
...
Notice the Stitchwork/ subfolder inside the plugin folder. That
matters — Stitchwork specifically looks for that name (and also accepts
the older name Patchwork/ for backwards compatibility with older
packs).
This is the format Thunderstore expects. Your pack ships as a single
folder under BepInEx/plugins/ and Stitchwork discovers it
automatically.
Option B: as a local pack (good for development)
BepInEx/plugins/Stitchwork/Packs/your-pack-name/
Sprites/
Sounds/
...
Same internal structure, lives inside Stitchwork's own folder. Useful when you're iterating quickly and don't want to deal with Thunderstore's manifest yet.
You can also drop files directly into BepInEx/plugins/Stitchwork/Sprites/
(without a pack folder around them). This is the root workspace —
fastest for prototyping but not recommended for shipping. Files in the
root workspace can't be turned off via the Pack Manager because they
aren't a pack; they always apply.
Sprites: the five different paths
This is the part that confuses new creators. There isn't ONE place to put a sprite — there are several, each for a slightly different purpose. Here are all of them, with when to use each.
1. Individual tk2d sprite — the most common case
Sprites/{CollectionName}/{MaterialName}/{SpriteName}.png
Use when: you're replacing one specific frame of an animated character, enemy, or UI element. This covers most skin work.
Example: replacing one frame of Hornet's idle animation.
Sprites/Knight/atlas2/idle0000.png
Knight is the collection (the in-game art group — the game's internal
name for Hornet, which trips everyone once), atlas2 is the material (the
texture sheet inside the collection), idle0000 is the specific sprite name
(the frame).
You find the right names in the Animation tab of the Dev Hub (tk2d sprites live there; the T2D Textures tab is the other system) — see Finding Any Sprite.
2. Whole tk2d atlas at once — bulk replacement
Spritesheets/{CollectionName}/{MaterialName}.png
Use when: you've redrawn ALL the sprites in an atlas as one big PNG, with the same layout as the original. Faster than shipping individual frames if you're doing a complete rework.
Example:
Spritesheets/Knight/atlas2.png
The PNG must match the dimensions and sprite layout of the original atlas. This tier is the porting door for finished sheet-based work (Custom Knight Creator exports and older skins) — not an authoring path; there's deliberately no tk2d atlas dump. See Porting Prior Work.
3. Individual T2D sprite
Sprites/T2D/{AtlasName}/{SpriteName}.png
Use when: the sprite you want to replace lives in Silksong's newer T2D system (different rendering pipeline from tk2d, used for some HUD and UI elements). The Dev Hub will tell you which system a sprite uses.
Example:
Sprites/T2D/HUD/health_pip.png
4. Whole T2D atlas
Spritesheets/T2D/{AtlasName}.png
Use when: bulk-replacing an entire T2D atlas, same idea as #2 but for the T2D system.
5. Instance-specific sprite (for advanced cases)
Sprites/{CollectionName}/{VanillaTextureName}/{SpriteName}.png
Use when: the game has TWO collections with the same name but different content (rare but happens). The fourth-from-last folder lets you specify which atlas instance you mean by its raw texture name instead of its material name.
If you're not sure whether you need this, you don't. Stick with #1.
tk2d versus T2D — what's the difference?
The short answer: it's two different ways the game stores 2D art internally. tk2d is older and used for most character art. T2D is newer and used for some HUD and UI elements.
You don't need to understand the technical difference. What you DO need to know:
- The T2D Browser in the Dev Hub (Graphics tab → T2D Textures) shows you sprites in the T2D system.
- The Animation Inspector (Graphics tab → Animation) shows you sprites in the tk2d system.
- If a sprite shows up in one but not the other, that tells you which pipeline to use.
When you're starting out, just look at where the sprite appears and match the file path accordingly.
Sounds folder
Sounds/{ClipName}.{ext}
Supported extensions: .ogg, .wav, .mp3, .aiff.
Find clip names via the Dev Hub Audio tab — clips that play populate the Live Log on the right side. Click a name to copy it.
Example: replacing the title music.
Sounds/title_music.ogg
Looped tracks (music) need to actually loop in the file format — otherwise they'll play once and stop. OGG with proper loop tags is the safest format for music.
Videos folder
Videos/{CinematicName}.{ext}
Supported extensions: .mp4, .webm, .ogv, .mov, .avi, .m4v,
.mpg, .mpeg, .wmv.
.mp4 with H.264 video and AAC audio is the most reliable format
across systems. Other formats may work but have less testing.
Find cinematic names by playing the cutscene with the Dev Hub Video tab open — recently-triggered cinematics show up there.
Text folder
Text/{SheetName}/{LANG}.yml
SheetName is the name of a localization sheet (e.g. Prompts,
Quests, Wanderers). LANG is a language code (EN, ZH, FR,
DE, JA, etc.).
Example: replacing the English version of one quest's dialogue.
Text/Wanderers/EN.yml
YAML files are simple key-value pairs. See the Text and Dialogue page for the format and how to discover sheet/key names.
Naming case-sensitivity
Stitchwork is mostly case-insensitive on filenames — Knight/atlas2/Idle0000.png
and knight/atlas2/idle0000.png both work. But it's still good practice
to match the case the game uses, because:
- Some external tools (especially on Linux or macOS-via-Wine setups) ARE case-sensitive at the filesystem level.
- It makes your pack easier to compare against vanilla dumps.
- It shows up cleaner in conflict reports.
When in doubt, use the case the dump produced.
File formats
| Asset type | Recommended format | Also works |
|---|---|---|
| Sprite PNG | PNG with alpha | PNG with no alpha |
| Audio (SFX) | OGG | WAV, MP3, AIFF |
| Audio (music, looping) | OGG with loop tags | WAV (large files) |
| Video | MP4 (H.264 + AAC) | WEBM, MOV, others |
| Text | UTF-8 YAML | UTF-8 with BOM (works but not preferred) |
PNGs can be any size for individual sprites — Stitchwork will scale the atlas to fit if your replacement is bigger than the vanilla slot. For whole-atlas replacements (Spritesheets path), match the original dimensions exactly.
What files Stitchwork ignores
Inside your pack folder, Stitchwork will quietly skip:
- Files whose names don't match what the game references (typo'd filenames). They sit on disk doing nothing.
- Hidden files (starting with
.) - Editor metadata files (
.DS_Store,Thumbs.db,*.psdPhotoshop source files, etc.) - Files in folders that don't match the expected structure (e.g.
a stray PNG in the root of
Sprites/).
This means it's safe to drop your Photoshop source files alongside the exported PNGs in the same folder — they'll just be ignored. Helpful when you want to ship a pack that includes editable sources.
What's next
- Starting a Skin Pack — concrete walkthrough.
- Finding Any Sprite — finding the right names.
- Bigger Art: Anchors — for enlarged sprites.
- Distributing Your Pack — Thunderstore shipping.
Pages
- A-0 Wikis
- A1 - Getting Started
- A2 - Installing Packs
- A3 - The Pack Manager
- A4 - How Stitchwork Works
- A5 - When Something Looks Wrong
- AEx1 - Conditional Activation
- B0 - Choosing a Workflow
- B1 - Starting a Skin Pack
- B2 - Finding Any Sprite
- B3 - Porting Prior Work — Spritesheets & CKC
- B4 - Texture2D (T2D) Sprites
- B5 - Bigger Art — Anchors
- B6 - Animation Canvas Workflow
- B7 - Sprite Paths Reference
- B8 - The Animation Controller
- BEx1 - Reused frames — one sprite, many animations
- BEx2 - Instance-specific paths — same name, different art
- BEx3 - Appliqué: Per-Clip Art
- C1 - Text & Dialogue
- D1 - Audio
- E1 - Video
- F1 - Priority & Conflicts
- F2 - Distributing Your Pack
- G1 - Dumping & Full Dump
- G2 - Companion Mods
- G3 - Hotkeys
- G4 - Pack Folder Structure
- G5 - Testing With Savestates (DebugMod)
- G6 - Troubleshooting