Files
tekton/wiki/skin_creation_workflow.md
T
god 114748a54f experimental: remove Tekton Doors entirely
- Delete portal_mode_manager.gd, portal_door.gd, portal_door.tscn
- Strip all Tekton Doors logic from main.gd, player.gd, lobby.gd,
  lobby_room.gd, lobby_manager.gd, camera_context_manager.gd,
  music_manager.gd, tekton.gd, enhanced_gridmap.gd,
  playerboard_manager.gd, special_tiles_manager.gd
- Remove TK enum (TEKTON_DOORS=2), mode_config schema, arena area
- Update tests: 3 modes instead of 4
- Strip HowToPlay tab from main.tscn
2026-07-06 00:18:59 +08:00

9.8 KiB

Skin Creation Workflow

How to author a new character skin, register it in the game's shop/gacha catalog, and ship it to players.


Overview

Each skin is defined in two places that must stay in sync:

Layer File What it stores
Client (visual) scripts/managers/skin_manager.gd Mesh slots, material paths, override/overlay mode
Server (shop) server/nakama/lua/economy.lua Item ID, name, category, price (gold/star)

The item id in economy.lua must match the dictionary key in skin_manager.gd SKIN_CATALOG exactly -- the Godot client looks up the item ID from the wallet/inventory and applies the matching skin data.

Back to top


Step 1: Create the Skin Material

Open the Skin Shader Generator at res://scenes/tools/skin_shader_generator.tscn.

  1. Run the scene (F6).
  2. Import your base albedo and mask textures (PNG with color/alpha channels).
  3. Use the UI to visualize UV overlays and adjust color channels (Red, Green, Blue, Alpha).
  4. Export the configured material as a .tres file into assets/materials/skins/ or a subfolder:
    • assets/characters/skins/hat/
    • assets/characters/skins/clothing/
    • assets/characters/skins/gloves/

Material path conventions (Oldpop character):

Category Example path
hat res://assets/characters/skins/hat/oldpop_mat_hat_blue.tres
costume/clothing res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres
glove res://assets/characters/skins/gloves/oldpop_mat_gloves_blue.tres
accessory res://assets/characters/skins/accessory/

Back to top


Step 2: Register the Skin in SkinManager (Client)

Open res://scripts/managers/skin_manager.gd and add a new entry inside SKIN_CATALOG (between [BEGIN_SKIN_CATALOG] and [END_SKIN_CATALOG] markers).

Entry format

"item_id": {
    "category":  "head",           # head | costume | glove | accessory
    "character": "Oldpop",         # node name under CharacterRoot
    "slots": [
        {
            "mesh":     "oldpop-hat1",       # MeshInstance3D child name
            "mode":     "override",          # "override" | "overlay"
            "material": "res://path/to/material.tres"
        },
    ]
}

Slot modes

  • override -- set_surface_override_material(0, mat). Replaces the base material entirely. Preserves the outline shader (next_pass) automatically.
  • overlay -- material_overlay = mat. Transparent layer on top of the base material. Good for costume/pant patterns.

Multi-slot skins (costume example)

Costumes typically touch 3 meshes:

"oldpop-grey-pant": {
    "category":  "costume",
    "character": "Oldpop",
    "slots": [
        { "mesh": "oldpop-body",    "mode": "overlay",  "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" },
        { "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" },
        { "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" },
    ]
},

Tips

  • Leave "material" as "" if the .tres file is not ready yet. The slot is skipped gracefully.
  • Use the Skin Catalog Editor (res://scenes/tools/skin_catalog_editor.tscn) to avoid manual edits. Click Save & Generate to rewrite both skin_manager.gd and economy.lua.

Back to top


Step 3: Register the Skin in Economy (Server)

Open server/nakama/lua/economy.lua and add a new entry to SHOP_CATALOG_DEFS.

Catalog entry format

{ id = "oldpop-blue-hat", name = "Oldpop Blue Hat", category = "head", gold = 100, star = 0, rarity = "Common", character = "Oldpop" },
Field Type Description
id string Must match the SKIN_CATALOG key in skin_manager.gd exactly
name string Display name shown in shop
category string head / costume / glove / accessory
gold number Gold coin price (0 = not sold for gold)
star number Star gem price (0 = not sold for stars)
rarity string "Common" / "Uncommon" / "Rare" -- cosmetic label only
character string Character this skin belongs to (e.g. "Oldpop")

Existing catalog (12 items)

oldpop-blue-hat      head     100 gold    Common    Oldpop
oldpop-green-hat     head     100 gold    Common    Oldpop
oldpop-red-hat       head     100 gold    Common    Oldpop
oldpop-yellow-hat    head     100 gold    Common    Oldpop
oldpop-og-pant       costume  0 gold      Common    Oldpop  (free)
oldpop-grey-pant     costume  150 gold    Common    Oldpop
oldpop-red-pant      costume  150 gold    Common    Oldpop
oldpop-yellow-pant   costume  150 gold    Common    Oldpop
oldpop-blue-gloves   glove    75 gold     Common    Oldpop
oldpop-green-gloves  glove    75 gold     Common    Oldpop
oldpop-red-gloves    glove    75 gold     Common    Oldpop
oldpop-yellow-gloves glove    75 gold     Common    Oldpop

Back to top


Step 4 (Optional): Add Skin as Gacha Prize

Gacha-only skins are registered in server/nakama/lua/gacha.lua inside GACHA_DATA.real_prize_catalog.

Existing gacha skins (4 items)

skin_gacha_rainbow_suit   = { name = "Rainbow Suit",     category = "costume",   rarity = "real_prize", character = "" }
skin_gacha_dragon_hat     = { name = "Dragon Hat",       category = "head",      rarity = "real_prize", character = "" }
skin_gacha_phantom_gloves = { name = "Phantom Gloves",   category = "glove",     rarity = "real_prize", character = "" }
skin_gacha_neon_acc       = { name = "Neon Accessory",   category = "accessory", rarity = "real_prize", character = "" }

Gacha skins also need a skin_manager.gd entry (same step 2 format) and a skin_catalog_editor entry so SkinManager.apply_loadout() can render them. The server catalog is optional -- gacha skins are not sold in the shop directly.

The gacha pulls these IDs from GACHA_DATA.pools.real_prize, so add your item_id there too.

pools = {
    common = {"frag_common"},
    uncommon = {"frag_uncommon"},
    rare = {"frag_rare"},
    real_prize = {
        "skin_gacha_rainbow_suit",
        "skin_gacha_dragon_hat",
        "skin_gacha_phantom_gloves",
        "skin_gacha_neon_acc",
        -- add new skin here
    }
},

Back to top


Step 5: Deploy

  1. Commit changes to experimental branch:

    • scripts/managers/skin_manager.gd
    • server/nakama/lua/economy.lua (if shop item)
    • server/nakama/lua/gacha.lua (if gacha prize)
    • Material .tres files
  2. Push to experimental.

  3. Trigger deploy_patch.yml via Gitea UI workflow dispatch.

    • CI runs --export-pack to build patch.pck.
    • CI force-pushes patch.pck + version.json to patches branch.
    • Existing players auto-download on next boot via GameUpdateManager.

Full binary release (if engine/templates changed)

Tag a version (e.g. v2.5.0) and push. CI builds all platform binaries and uploads to the release.

Back to top


Full Flow Diagram

┌──────────────────────┐
│ 1. Create Material    │
│ skin_shader_generator │
│  ──────────────────   │
│  Export .tres file    │
└────────┬─────────────┘
         v
┌──────────────────────────────┐
│ 2. Register in SkinManager   │
│    skin_manager.gd            │
│    ──────────────────         │
│    Add SKIN_CATALOG entry     │
│    (mesh slots + material)    │
└────────┬─────────────────────┘
         v
┌──────────────────────────────┐
│ 3. Register in Economy       │
│    economy.lua                │
│    ──────────────────         │
│    Add SHOP_CATALOG_DEFS      │
│    (price, name, category)    │
└────────┬─────────────────────┘
         v  (optional)
┌──────────────────────────────┐
│ 4. Gacha Prize                │
│    gacha.lua                  │
│    ──────────────────         │
│    real_prize_catalog + pools │
└────────┬─────────────────────┘
         v
┌──────────────────────┐
│ 5. Git Push & CI      │
│ deploy_patch.yml      │
│  ──────────────────   │
│  patch.pck → players  │
└──────────────────────┘

Back to top


Troubleshooting

Symptom Cause Fix
Skin visible in editor but not in-game Material path wrong or .tres not exported Verify res:// path in SKIN_CATALOG, run --export-pack
Skin purchase fails: "NotEnoughFunds" Wallet balance insufficient Check gold/star prices in economy.lua
Skin visible on all characters character field wrong Set correct character node name
Skin purchase fails: "ItemNotFound" Item ID not in SHOP_CATALOG_DEFS Add entry matching SKIN_CATALOG key
Player downloads patch but skin missing econmy.lua change didn't reach server Nakama hot-reload: restart Nakama container or wait for next restart
Outline shader lost on skin next_pass not preserved SkinManager preserves it automatically -- verify with latest skin_manager.gd

Back to top