A complete pack, end to end
This page walks through the smallest pack that actually does something useful: one named girl, a handful of images, and the wrapper file that tells the engine “this folder is a pack.” Read it once and you’ll know where every file goes and why.
We’ll build a pack called Marina containing a single girl of the same name. By the end you’ll have a folder you can drop into resources/packages/ and see show up in the Slave Market on the next new game.
The folder tree
Section titled “The folder tree”Here’s everything we’re going to create:
resources/packages/Marina/ package.xml Girls.girlsx Characters/ Marina/ Profile/ portrait.png Sex/ normal_01.png normal_02.pngFive files in three folders. That’s the whole pack.
File 1: package.xml
Section titled “File 1: package.xml”Every structured pack needs this file at its root. It’s the marker that says “this folder is a pack, please load it.” A folder without package.xml is ignored.
<?xml version="1.0" encoding="utf-8"?><Package Name="Marina" Id="marina_pack" Author="Your Name" Version="1.0" Description="A former fisherwoman from a coastal village." RequiresEngine="1.14.7"> <Tags> <Tag>girls</Tag> </Tags></Package>The two fields that matter are Name (what players see) and Id (the unique identifier the engine uses internally). The Id must be unique across every installed pack, otherwise loading order decides who wins. Pick something specific to your pack.
RequiresEngine is the minimum game version this pack needs. If a player on an older engine installs your pack, they’ll get a warning instead of silent breakage. Set it to the lowest version that has the features you use.
Everything else (Author, Version, Description, Tags) is metadata for the Content Manager, the in-game pack browser, and future tooling. Worth filling in but never required.
File 2: Girls.girlsx
Section titled “File 2: Girls.girlsx”This is where Marina actually lives as a character. One file can hold many girls; here we ship just one.
The canonical shape keeps identity (Name, Desc, Status) as attributes on <Girl> and puts everything numeric — stats, skills, traits, starting gold — into typed child elements:
<Girls> <Girl Name="Marina" Desc="A former fisherwoman from a coastal village. Strong arms, stronger opinions." Status="Slave"> <Stat name="Age" value="25" /> <Stat name="Charisma" value="30" /> <Stat name="Happiness" value="80" /> <Stat name="Libido" value="20" /> <Stat name="Constitution" value="70" /> <Stat name="Intelligence" value="30" /> <Stat name="Confidence" value="60" /> <Stat name="Agility" value="50" /> <Stat name="Beauty" value="40" /> <Stat name="Spirit" value="70" /> <Stat name="Health" value="100" /> <Stat name="Obedience" value="20" />
<Skill name="NormalSex" value="15" /> <Skill name="Service" value="20" /> <Skill name="Combat" value="25" />
<Trait name="Strong" /> <Trait name="Tough" />
<Gold value="20" /> </Girl></Girls>Anything you omit defaults to a sensible baseline, so you only need to set the values you care about. The full list of stat names, skill names, and every element lives in girlsx-schema.
Three things to know:
- Identity vs. data.
Name,Desc, andStatusdescribe who she is and stay on the<Girl>line. Stats (<Stat>), skills (<Skill>), traits (<Trait>), and starting gold (<Gold>) describe what she has and can do, and are child elements. Note thatAgeis a stat, not an identity attribute. Status="Slave": this is what makes Marina available in the Slave Market. Without it she’s a unique girl who never appears in any pool and effectively never spawns. If you want a “wild” recruit-from-the-streets girl, setStatus="Normal"and use her in a Lua hook instead. For most authors,Status="Slave"is what you want.<Trait name=...>: traits are referenced by name. The engine ships a long list of core traits; grep them before inventing a new one. Custom traits live in your pack’sTraits.traitsx(covered intraits-reference).
The older flat format, and the converter
Section titled “The older flat format, and the converter”You may have seen packs — including older versions of this very walkthrough — that write every stat and skill as an attribute directly on <Girl>:
<!-- legacy flat form: still loads, but don't write new packs this way --><Girl Name="Marina" Beauty="40" Charisma="30" Age="25" Service="20" Status="Slave"> <Trait Name="Strong" /></Girl>The loader still accepts this, and every other historical variant, so old packs keep working untouched — see Accepted variants in the schema for the full list. But the typed-child shape above is the canonical one for anything new: it’s what the snippets, samples, and validator expect, and it’s the only shape that extends cleanly to random-girl ranges (min/max) and starting inventory.
You don’t have to hand-convert an existing flat-format pack. The kit ships a converter:
python3 tools/pack-authoring-kit/tools/migrate-girlsx.py resources/packages/YourPack/It’s a dry-run by default (prints what it would change); add --write to apply the rewrite in place, with .bak backups. And if you’re starting a pack from scratch, scaffold-new-pack.py (or the VS Code New pack… task) drops a canonical-shape Girls.girlsx skeleton straight into a fresh pack folder. Both are covered on the Tools page.
File 3+: the images
Section titled “File 3+: the images”Images live under Characters/Marina/, in subfolders named for the category. The folder name has to match the Name attribute of the girl.
Characters/Marina/ Profile/ portrait.png Sex/ normal_01.png normal_02.pngTwo categories here:
- Profile: shown on the girl’s detail screen and anywhere the engine needs a “default” picture of her. Always ship at least one Profile image, otherwise she displays as a blank silhouette.
- Sex: shown during sexual scenes. Filename hints (the
normaltoken innormal_01.png) tell the engine which act this image fits. The inference is forgiving: split tokens on_,-,., or whitespace, sonormal_anal_01.pngis read as both “normal” and “anal.”
That’s it for a starter pack. The full taxonomy of categories (Combat, Strip, BDSM, Beast, etc.) and per-image tagging lives in image-types and filename-cheatsheet. You can also override inference for specific images via an images.xml manifest, but you don’t need one until your filenames stop telling the truth.
Loading and testing
Section titled “Loading and testing”Drop the whole Marina/ folder into resources/packages/. Start a new game. Marina should appear in the Slave Market within the first few weeks (she’s part of the random rotation now, not always week one).
If she doesn’t show up:
- Check the game log for pack-loader errors. A missing
Id, malformed XML, or unknown trait name will get logged there. - Run
pack-validator.exeagainst your pack folder. It catches the common authoring mistakes before the engine does. - Confirm
Status="Slave"is on the<Girl>line. Forgetting this is the most common reason a girl never appears.
What to add next
Section titled “What to add next”This pack works. To grow it:
- More girls: add more
<Girl>blocks toGirls.girlsx, one matching folder underCharacters/each. - Random-girl templates: ship
RandomGirls.rgirlsxwith archetypes the engine rolls into procedurally generated girls. Same XML shape, different file extension. - Custom traits or items: drop
Traits.traitsxorItems.itemsxnext toGirls.girlsx. Schemas are intraits-referenceanditems-reference. - A short script: a
Lua/folder with a meet-girl scene or a custom event. Seelua-scripting. - A custom job or building: data-driven, lives under
Jobs/or as a building pack. Seejobs-referenceand the shippedSample_Building/for examples.
Each of these is additive. You can ship a girls-only pack forever and it’s a complete pack. The new format exists so that when you do want traits, items, or scripts in the same drop, they have a place to go.
See also
Section titled “See also”- Where packs go: the two valid drop locations and the loader rules.
- The shipped sample packs under
resources/packages/:Sample_Full/is the kitchen-sink reference;Sample_GirlsOnly/is a more compact named-and-random girl pack.