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" 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 field that matters to the game is Id. It is the pack’s identity, and it must be the same as the folder name: the folder is Marina/, so the Id is Marina. The drag-and-drop installer creates the folder from the Id for you; if you copy the pack in by hand, keep the two identical, otherwise the game loads the characters but skips anything addressed by pack id (jobs, buildings). Letters, digits, _, - and . only, no spaces.
RequiresEngine is the minimum game version your pack needs. The game itself does not read it; the pack validator does, to check your files against that version. State the minimum version in your README too, because that is where a player will actually see it.
Everything else (Name, Author, Version, Description, Tags) is metadata shown by the Content Editor; the game lists packs by Id and ignores the rest. Worth filling in, never required. The full list of fields is in the package.xml reference.
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 add tags to specific images with an images.xml manifest, but you don’t need one until your filenames stop telling the truth. Note what a manifest does and does not do: its tags are added on top of what the folder and filename already say, so an image keeps its folder’s category and gains whatever you list. A manifest cannot take a category away. To change what an image is, move the file into the folder you want it in. See image-types for the full rule.
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
triggers.xmland aMeetGirl.luain the girl’s ownCharacters/Marina/folder for a meet-girl scene or a custom event. Seelua-scripting. - A custom job: data-driven, lives under a lowercase
jobs/folder at the pack root. Seejobs-reference. Building packs are not an authoring surface yet; the shippedSample_Building/is an engine sample, not a template.
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 example packs in
examples/packs/in the game folder (from game 1.21; before that, theSample_*folders inresources/packages/):Sample_Full/is the kitchen-sink reference;Sample_GirlsOnly/is a more compact named-and-random girl pack.