Skip to content

API Reference

DooDesch edited this page Jun 21, 2026 · 2 revisions

API Reference

For mods that register tattoos in code (procedural designs, dynamic packs, NPCs). If you just want to ship a set of PNGs, use the no-code Pack Format instead.

A complete, buildable project is in the example repo (code-mod/).

The class

namespace Inkorporated
{
    public static class API
    {
        // Register from an already-loaded texture.
        public static bool RegisterTattoo(
            string id, string displayName, TattooPlacement placement,
            UnityEngine.Texture2D texture, float price = 0f, string source = "API");

        // Register from a PNG on disk (loaded lazily when first needed).
        public static bool RegisterTattooFromFile(
            string id, string displayName, TattooPlacement placement,
            string pngPath, float price = 0f, string source = "API");

        // Register from a PNG EMBEDDED in your mod's DLL - no loading boilerplate. The calling assembly is
        // auto-detected; resourceName is the embedded name ("MyMod.Assets.skull.png"); "skull.png" also matches.
        public static bool RegisterTattooFromResource(
            string id, string displayName, TattooPlacement placement,
            string resourceName, float price = 0f, string source = "API");
        // ...plus an overload taking an explicit System.Reflection.Assembly if the PNG is in another assembly.
    }
}

namespace Inkorporated.Model
{
    public enum TattooPlacement { Chest, LeftArm, RightArm, Face }
}
Parameter Meaning
id Unique within your source. Used in the registered resource path.
displayName The label on the shop button (falls back to id).
placement Chest | LeftArm | RightArm | Face.
texture / pngPath Your tattoo image. Must match the body/face UV - see Authoring Tattoos.
price Shop price; 0 shows "Free".
source A stable namespace for your mod (e.g. your mod name). Used for de-duplication and the resource path.

Returns true if added, false if it duplicated an existing (source, id).

When to register (important)

Register early - before the tattoo shop UI is built - e.g. in your OnInitializeMelon. Tattoos registered after that UI exists appear only the next time it is rebuilt. Registration is cheap; the actual texture work happens lazily the first time the shop opens.

Setting up the project

Declare Inkorporated as a hard dependency so it loads first, and reference its DLL:

[assembly: MelonAdditionalDependencies("Inkorporated")]

Reference these (straight from a normal modded install - see the example's .csproj):

  • Mods/Inkorporated.dll - the API
  • Mods/S1API.Il2Cpp.MelonLoader.dll - S1API (texture/NPC helpers)
  • MelonLoader/net6/MelonLoader.dll, Il2CppInterop.Runtime.dll
  • MelonLoader/Il2CppAssemblies/UnityEngine.CoreModule.dll, Il2Cppmscorlib.dll, Il2CppSystem.dll
  • For Thunderstore, list DooDesch-Inkorporated as a dependency.

Loading a texture

S1API ships helpers (recommended over hand-rolling):

using S1API.Rendering;
Texture2D t1 = TextureUtils.LoadTextureFromFile(path);                 // from disk
Texture2D t2 = TextureUtils.LoadTextureFromBytes(pngBytes);            // from bytes (e.g. an embedded PNG)

Tip: if your PNG is embedded in your own DLL, skip this entirely and use API.RegisterTattooFromResource(id, name, placement, "MyMod.Assets.skull.png", source: "MyMod") - it loads the embedded resource for you (the calling assembly is auto-detected).

Minimal example

using Inkorporated;
using Inkorporated.Model;
using S1API.Rendering;
using MelonLoader;
using UnityEngine;

[assembly: MelonAdditionalDependencies("Inkorporated")]

public sealed class Core : MelonMod
{
    public override void OnInitializeMelon()
    {
        Texture2D tex = TextureUtils.LoadTextureFromFile(@"C:\path\to\skull.png");
        API.RegisterTattoo("skull", "Skull", TattooPlacement.Chest, tex, price: 0f, source: "MyMod");
    }
}

The registered resource path

Each tattoo is registered at:

Avatar/Layers/Tattoos/custom/<segment>/<Source>_<Id>

where <segment> is Face for face tattoos (capitalised, so the game routes them to the face mesh) or the lowercase placement (chest / leftarm / rightarm) otherwise. Source and Id have non-alphanumeric characters replaced with _. You need this path only if you want to put the tattoo on an NPC - see Multiplayer Saves and NPCs.

Clone this wiki locally