Configuration
Koja Appearance reads three config files:
| File | What is in it |
|---|---|
shared/koja_config.lua | Everything added by the redesign: Config.Locale and Config.Koja.* |
shared/koja_shops.lua | Shopkeepers: Config.Koja.Shops |
shared/config.lua | The upstream illenium-appearance options (prices, stores, clothing rooms, outfits, blacklists) |
Restart the resource after changing any of them.
General
| Option | Default | What it does |
|---|---|---|
Config.Locale | "en" | Language: ar, bg, cs, de, en, es-ES, fr, hu, id, it, nl, pl, pt-BR, ro-RO, zh-CN, zh-TW. The convar illenium-appearance:locale wins when set |
Config.Koja.AutoMigrateESXSkins | true | ESX: converts old esx_skin / skinchanger skins in users.skin on start. Originals are kept in koja_appearance_skin_backup |
Config.Koja.SkinCommands | { "skin" } | Extra admin commands that open the full character creator, like /pedmenu |
Branding and theme
Config.Koja.ServerName = "YOUR SERVER NAME"
Config.Koja.Logo = nil -- url or nil
Config.Koja.Currency = "$"
Config.Koja.PedImageUrl = "https://docs.fivem.net/peds/%s.webp"
Config.Koja.Theme = {
accent = "#FF9B00",
background = "#121212",
corners = "rounded", -- "rounded" | "sharp"
}| Option | What it does |
|---|---|
ServerName, Logo | Shown at the top of the left rail. ServerName is also the title of notifications |
Currency | Symbol in front of every price |
PedImageUrl | Preview image of each ped model. %s is replaced by the model name |
Theme | The default colours and corner style. Players can change them in the Studio; their choice is saved on their PC |
Studio
Config.Koja.Studio = {
Enabled = true,
PrivateBucket = true,
Default = 1,
Locations = {
{ label = "Civil", coords = vec4(-797.6995, 328.4894, 190.7158, 2.3068) },
{ label = "Gangster", coords = vec4(71.1171, -1399.3535, 29.3761, 315.9135) },
{ label = "Exclusive", coords = vec4(-703.8611, -151.9658, 37.4151, 159.8186) },
},
}| Option | What it does |
|---|---|
Enabled | Shows the studio locations in the Studio panel |
PrivateBucket | Moves the player to their own routing bucket while at a studio. The bucket is StudioBucketBase + server id |
Default | Fallback location (index in Locations), used only when the player's old coords are missing. Opening the menu never teleports on its own |
Locations | Studios players can pick. "Your old coords" is always the first entry |
Config.Koja.StudioBucketBase | 7000 — base of the private bucket numbers |
Config.Koja.PrefsKvp | "koja_appearance_prefs" — client KVP key of the per-player Studio settings |
Studio light
Config.Koja.Light = {
enabled = false,
power = 4.0,
x = 0.0, y = 1.6, z = 0.6, -- offset from the ped
color = "#FFFFFF",
}The default light. Players change it in the Studio panel.
Showcase tools
| Option | Default | What it does |
|---|---|---|
Showcase.BackdropColor | "#1A1A1A" | Default backdrop colour |
Showcase.BackdropSize | 5.0 | Half size, in metres, of the backdrop box drawn around the ped |
Showcase.SpinSpeed | 30.0 | Turntable speed in degrees per second |
Showcase.KeepArms | jackets, undershirts, vests, arms | Item view keeps the arms for these categories, so tops do not float over a bare body |
Showcase.KeepHair | hair, hats, masks, glasses, ears, beard | Item view keeps the hair for these categories |
Showcase.Weathers | 13 weathers | Weathers offered in Time & weather. Set one to false to hide it |
Safety while customising
Config.Koja.Safety = {
Enabled = true,
FreezeNeeds = true,
Statuses = { "hunger", "thirst", "stress" },
}While the menu or studio is open the player takes no damage (no drowning or falling) and the statuses in Statuses do not drop.
On ESX they are frozen through esx_status on the client; on QBCore and QBox through player metadata on the server.
Mask clipping fix
Config.Koja.MaskFix = {
Enabled = true,
Threshold = 0.1,
Interval = 500,
IgnoreDrawables = { male = {}, female = {} }, -- e.g. male = { [51] = true }
}Face features (nose, brows, cheeks, jaw) push the face through masks. While a mask is worn the face shape is flattened to neutral and it comes back when the mask comes off — also for masks put on by other resources. The saved appearance always keeps the real face.
| Option | What it does |
|---|---|
Threshold | The fix only kicks in when at least one face feature is further than this from 0 |
Interval | Milliseconds between checks for masks changed by other resources |
IgnoreDrawables | Mask drawables that never clip (bandanas, small mouth masks). Flattening is skipped for them |
Inheritance faces
Config.Koja.ExtraFaces = {
-- { gender = "female", id = 46, label = "Anna", image = "https://..." },
}Extra parent faces streamed by another resource. They are shown after the GTA faces.
Shop basket and prices
Config.Koja.Shop = {
Basket = true,
DefaultPrice = 0,
PaymentMethods = { "cash", "bank" },
AutoPrices = {
Enabled = true,
Step = 5,
FreeFirst = true,
Categories = {
masks = { 80, 600 },
jackets = { 150, 1200 },
-- ...
},
},
}| Option | What it does |
|---|---|
Basket | Pay per item in clothing shops. With false, the flat upstream Config.ClothingCost is charged |
DefaultPrice | Price of an item with no saved price and no auto price. 0 = FREE |
PaymentMethods | "cash" and / or "bank" |
AutoPrices.Enabled | Gives every item without a saved price a fixed price between min and max of its category. The same item always gets the same price |
AutoPrices.Step | Generated prices are rounded to this |
AutoPrices.FreeFirst | Drawable 0 (usually "none" or the basic item) is free |
AutoPrices.Categories | category = { min, max }. A category not listed uses DefaultPrice |
The price of an item is, in this order:
- The price saved in the Capture panel for that texture (
drawable_texture). - The price saved for the drawable.
- The auto price of the category.
DefaultPrice.
Barber, tattoo and surgeon shops keep the upstream Config.BarberCost, Config.TattooCost and Config.SurgeonCost.
Clothing as items
Config.Koja.ClothingItems = {
Enabled = false,
Item = "clothing",
}With Enabled = true, every paid piece bought in the basket is also given as one ox_inventory item. See Features for the item definition.
Wardrobe hub
Config.Koja.Hub = {
Enabled = true,
Prompt = true,
CloseOnWear = false,
}| Option | What it does |
|---|---|
Enabled | The NUI wardrobe hub replaces the ox_lib menus and dialogs of clothing shops, /pedmenu, clothing rooms, outfit rooms and boss managed outfits. false brings the ox_lib menus back |
Prompt | A styled key-cap pill instead of lib.showTextUI in zones. Works without the hub too |
CloseOnWear | Closes the hub after putting on an outfit |
Camera and Bones 3D
Config.Koja.CameraLimits = {
minDistance = 0.35,
maxDistance = 3.5,
yawSpeed = 0.35, -- degrees per dragged pixel
pitchSpeed = 0.004, -- metres of camera height per dragged pixel
minHeight = -1.0,
maxHeight = 1.0,
smoothing = 12.0, -- higher = snappier
}Config.Koja.BoneMarkers.Interval (ms) sets how often the Bones 3D markers update.
Config.Koja.BoneMarkers.Offsets moves the marker of a category away from its bone (vec3, x right, y forward, z up), so categories that share a bone get separate markers.
Capture panel
Config.Koja.Capture = {
Enabled = true,
AdminGroup = "group.admin",
FrameworkGroups = { "admin", "superadmin", "owner", "god", "dev" },
ScreenshotResource = "screenshot-basic",
Coords = vec4(-1000.0, -1000.0, 1000.0, 0.0),
GreenScreenColor = { 0, 255, 0 },
DefaultOffsets = { fov = 30.0, height = 0.0, rotation = 0.0, distance = 1.2 },
ImageSize = 256,
SettleMs = 150,
TextureSettleMs = 60,
-- InvisibleBody, Models, Pose, Ghost ...
}| Option | What it does |
|---|---|
Enabled | Shows the Admin Panel button to admins |
AdminGroup | Ace that counts as admin |
FrameworkGroups | ESX group / QBCore permission that also counts as admin |
ScreenshotResource | Name of the screenshot-basic resource |
Coords | Where the ped is shot. High in the sky; the green screen is drawn around the ped |
GreenScreenColor | RGB of the green screen |
DefaultOffsets | Camera of a category with no saved preset |
ImageSize | Output size in pixels (square) |
SettleMs / TextureSettleMs | Wait after a new drawable / texture before the shot. Raise them if images come out blurry or half loaded |
InvisibleBody | Empty slots (drawable -1) during shots, so a shirt shows no arms, legs or feet around it. head = { drawable, texture } if you stream an invisible head |
Models | The Select ped list. gender is the image set the shots go to. Any freemode-compatible add-on ped works |
Pose | Animations held during shots. The first one that plays is used |
Ghost | Ghost shots: clothes only, no body. See below |
Ghost shots
| Option | Default | What it does |
|---|---|---|
Ghost.Default | true | Ghost toggle state when the panel opens |
Ghost.ReferenceSettleMs | 150 | Wait after emptying the slot before the reference shot |
Ghost.Threshold | 24 | Colour difference (0–255) still treated as the same pixel |
Ghost.CacheReference | false | One reference per category. Faster, but GTA's auto exposure can drift |
Ghost.KeepHead | hair, beard | Categories shot with the head |
Ghost.ToneTest | false | Extra light / dark skin shot to cut out the body. Off by default; it left outlines |
Ghost.SkinLight, SkinDark, ToneThreshold | 0, 19, 28 | Settings of the tone test |
Ghost.Face | "mood_sleeping_1" | Facial idle while shooting (closed eyes, no eyeballs in mask holes) |
Ghost.Debug | false | Saves the raw frames of every shot to capture_debug/. Tuning only, 1–2 MB per shot |
Upload limits
Config.Koja.CaptureExtra = {
FivemanageUploadUrl = "https://api.fivemanage.com/api/v3/file/base64",
FivemanageDeleteUrl = "https://api.fivemanage.com/api/v3/file/",
MaxPngBytes = 1500000,
HttpTimeoutMs = 20000,
StoresPerSecond = 20,
}MaxPngBytes rejects bigger images, StoresPerSecond limits stored images per admin per second.
Tattoo capture
| Option | Default | What it does |
|---|---|---|
TattooCapture.Enabled | true | Tattoo zones in the Capture panel. The editor still shows existing images when false |
TattooCapture.SkinTone | 12 | Skin tone while shooting (0–45). nil keeps the player's skin |
TattooCapture.Layers | 1 | How many times the tattoo is applied. More = darker ink |
TattooCapture.Naked | per gender | Components of the naked body used while shooting |
TattooCapture.BaldHead | true | No hair while shooting, so head and neck tattoos are visible |
TattooCapture.Views | {} | Camera views per zone, e.g. ZONE_TORSO = { 0 } for the front only |
TattooCapture.ViewSettleMs | 40 | Wait after moving the camera to the next view |
TattooCapture.InkOnly | true | "Flash" images: only the ink, no body |
TattooCapture.InkThreshold | 10 | Colour difference still treated as bare skin |
TattooCapture.InkSettleMs | 60 | Wait after removing / re-applying the tattoo |
TattooCapture.Paper | nil | Background colour of flash images, e.g. "#FFFFFF". nil = transparent |
Shopkeepers
shared/koja_shops.lua:
Config.Koja.Shops = {
Enabled = true,
Interaction = "auto", -- "auto" | "target" | "marker"
Prompt = "hub", -- "hub" | "koja-lib" | "ox_lib"
Key = 38,
KeyLabel = "E",
SpawnDistance = 45.0,
InteractDistance = 1.6,
TargetDistance = 2.5,
-- Marker, Talk, Types, Locations ...
}| Option | What it does |
|---|---|
Enabled | Shopkeepers replace the zones, target boxes and blips of Config.Stores |
Interaction | auto = ox_target / qb-target on the ped when one runs, otherwise a marker. target = always target (marker when no target resource runs). marker = floor marker and key prompt |
Prompt | Key prompt of marker mode: hub (built-in pill), koja-lib (koja-lib Text UI) or ox_lib (lib.showTextUI) |
Key, KeyLabel | Control id and label of the interaction key |
SpawnDistance | Clerks are spawned locally only while the player is this close |
InteractDistance, TargetDistance | How close the player must be in marker / target mode |
Marker | Type, Size, Color, DrawDistance, Offset (metres in front of the clerk) |
Talk | The short greeting before the menu: Enabled, Camera (over the shoulder), DurationMs, Speech |
Types | Per shop type (clothing, barber, tattoo, surgeon): clerk model, idle scenario, target icon, optional label |
Locations | { type, label, ped = vec4(...) }. Optional per location: model, scenario, blip = false, interact = vec3 |
Prompt texts and blip names come from the locale (UI.koja.shops.talk.<type>, UI.koja.shops.blip.<type>).
Upstream options
The options of shared/config.lua work as in illenium-appearance. A few the redesign relies on:
| Option | Note |
|---|---|
Config.ClothingCost | Charged only when Config.Koja.Shop.Basket = false |
Config.ChargePerTattoo | false by default in this fork: applying tattoos in the menu is free. true = Config.TattooCost per tattoo, or cost in shared/tattoos.lua |
Config.EnablePedMenu, Config.PedMenuGroup | /pedmenu. Access is checked with the admin rights above |
Config.EnableJobOutfitsCommand | Enables /joboutfits and /gangoutfits |
Config.BossManagedOutfits | Boss managed job / gang outfits, shown in the wardrobe hub |
Config.Stores | Not used while Config.Koja.Shops.Enabled = true |