Manifest Specification (pack.json)

Detailed specification of pack.json Format 1, localization, material classification rules, and parameter definitions.

Overview

The pack.json file declares the identity, localized descriptions, compatible model recommendations, material classification rules, and user-adjustable parameters for a shader pack. When MMDX12 scans pack directories, it reads and validates this file first.

{
  "format": 1,
  "id": "my_pack",
  "version": "1.0.0",
  "apiVersion": 1,
  "minAppVersion": "1.2.0",
  "name": { "ko": "내 팩", "en": "My Pack", "ja": "マイパック", "zh": "我的着色器" },
  "description": { "ko": "원신 풍 툰 셰이딩입니다.", "en": "Cel shading for anime models." },
  "recommendedFor": { "ko": "Genshin, Star Rail 공식 모델", "en": "Official HoYoverse MMD models" },
  "authors": [ { "name": "YourName", "role": "Shader", "url": "https://github.com/..." } ],
  "license": "MIT",
  "homepage": "https://...",
  "repository": "https://github.com/...",
  "tags": ["toon", "anime"],
  "classes": [
    { "class": "eye",  "match": ["目", "眼", "瞳", "eye", "Eye"] },
    { "class": "face", "match": ["顔", "颜", "face", "Face", "表情"] },
    { "class": "hair", "match": ["髪", "髮", "hair", "Hair"] },
    { "class": "skin", "match": ["肌", "皮肤", "skin", "Skin"] }
  ],
  "params": [
    { "key": "softness", "label": { "ko": "부드러움", "en": "Softness" }, "default": 0.1, "min": 0.0, "max": 1.0 }
  ]
}

Field Specification

Required Fields

  • version (string): Semantic version string (e.g. "1.0.0"). Used for update detection and gallery indexing.
  • name (string or localized object): Human-readable name of the pack.

Identity and Compatibility

  • format (integer): Manifest schema version. The current schema version is 1.
  • id (string): Lowercase alphanumeric characters a-z, digits 0-9, underscores _, and hyphens -, up to 64 characters. If omitted, it defaults to the parent folder name. For installed packs, the folder name must match id.
  • apiVersion (integer, default 1): The target shader API contract version. If greater than the engine’s supported version (currently 2), the pack is marked Incompatible and skipped.
  • minAppVersion (string, optional): Minimum MMDX12 version required to run this pack (e.g. "1.2.0").

Metadata and Localization

  • Localized Fields: name, description, recommendedFor, and parameter label can be either a plain string or an object with locale keys (ko, en, ja, zh).
    • Fallback resolution order: Current UI locale -> en -> Plain string -> ko -> Any available text.
  • authors (array): Author entries. Each item contains name (required), role (optional text such as “Shader” or “Translation”), and url (optional, http:// or https:// only). The legacy "author": "Name" format is also supported for backwards compatibility.
  • license (string): SPDX identifier or license description (e.g. "MIT", "CC-BY-4.0").
  • homepage, repository (string): Web links (http:// or https:// only).
  • tags (array of strings): Lowercase search keywords (maximum 12 tags).

Material Classification Rules (classes)

MMD models (PMX) use diverse naming conventions across creators. The classes table maps materials to one of six standard categories based on name substrings:

  1. body (default fallback whenever no rule matches)
  2. skin
  3. face
  4. eye
  5. hair
  6. weapon

Rule Evaluation

  • Rules are evaluated strictly from top to bottom.
  • The first matching rule wins.
  • Each string in the match array is tested as a case-sensitive substring against both the Japanese name and English name of the PMX material.
"classes": [
  { "class": "eye",  "match": ["目", "眼", "瞳", "eye", "Eye"] },
  { "class": "face", "match": ["顔", "颜", "face", "Face", "表情"] },
  { "class": "hair", "match": ["髪", "hair"] },
  { "class": "skin", "match": ["肌", "skin"] }
]

In surface.hlsl, the resolved class is passed as s.materialClass (PACK_BODY, PACK_SKIN, PACK_FACE, PACK_EYE, PACK_HAIR, PACK_WEAPON), allowing targeted shading logic.

Parameter Sliders (params)

Defines user-adjustable floating-point controls in the app UI:

  • Limit: Up to 16 parameters (PackParam(0) through PackParam(15)).
  • Indexing: The array order directly defines the parameter index in HLSL.
  • Properties:
    • key (string): Stable identifier used to persist user overrides. Keep this key stable across pack updates so existing user presets remain valid.
    • label (string or localized object): Label rendered in the UI.
    • default (float): Initial value.
    • min, max (float): Slider bounds.
  • Persistence Logic: Only values explicitly altered by the user are saved into character profiles. Unmodified sliders automatically inherit updated default values when new pack versions are released.

Pack Textures (textures, API 2)

Some looks cannot be built from the model’s own textures: game-style toon shading needs light maps, cool/warm ramps, face SDF maps, matcaps or parameter LUTs. A pack declares such textures in pack.json and samples them with PackSampleTex (see Shader API). Packs that use textures set "apiVersion": 2.

"apiVersion": 2,
"textures": [
  { "file": "textures/body_lightmap.png", "address": "clamp", "srgb": false },
  { "file": "textures/body_ramp.png",     "address": "clamp", "srgb": true }
]
  • file: path relative to the pack folder; png, jpg, jpeg only; no .., no absolute paths.
  • address: "wrap" (default) or "clamp". Ramps must use clamp: their lit end sits at u = 1.0, and wrap would sample the shadow end there.
  • srgb (default true): colour textures. They sample as linear values (do not apply SrgbToLinear again). Use false for data maps (light maps, SDFs, LUTs), which return the stored values.
  • Limits: at most 16 textures, each at most 4096 × 4096; the whole pack stays within 32 MB.
  • The array order is the index in HLSL (PackSampleTex(0, uv) is the first entry).

User texture folder

Textures extracted from games belong to their publishers and must not be redistributed. A pack can therefore ship only pack.json and surface.hlsl and leave the textures to the user: in the shader manager, each pack that declares textures has a texture folder setting. Textures are looked up in this order:

  1. the user’s texture folder, at the same relative path (textures/body_ramp.png), then by file name (body_ramp.png);
  2. the pack folder;
  3. a white 1 × 1 fallback. The pack still compiles and renders; the manager shows how many textures are missing.

Packs published to the gallery must only contain textures you are allowed to redistribute.

Per-character folders and file-name endings

Game texture sets differ per character, so the texture folder can also be set per character (library panel, play bar or studio inspector: the “texture folder” row under the pack’s sliders). It wins over the pack-level folder. In a user folder, a texture is found by the same relative path, then the same file name, then any file whose name ends with _ + the declared name (case-insensitive; the shortest match wins). Declare the common ending and the files keep their original names: Body_Lightmap.png finds Avatar_Girl_Pole_Hutao_Tex_Body_Lightmap.png.

Class rules by texture

A classes rule can also match the material’s diffuse texture path with "texture". Game maps follow the texture sheet, not the material name (a hat drawn on the hair sheet needs the hair light map), so this is the reliable way to pick them:

{ "class": "hair", "texture": ["发", "髮", "髪", "hair"] }

A rule matches when any match string is in the material’s names or any texture string is in its texture path; the first matching rule still wins.