Skip to main content
The .zzar format is a ZIP-based package format for distributing audio replacement mods for Zenless Zone Zero. It contains mod metadata, replacement audio files, and optional assets like thumbnails.

Package Structure

A .zzar file is a ZIP archive with the following structure:
mod_name.zzar
├── metadata.json          # Required: Mod information and replacements
├── thumbnail.png          # Optional: Mod thumbnail image
└── wem_files/            # Required: Replacement audio files
    ├── 134133939.wem
    ├── 86631895.wem
    └── ...

metadata.json

The metadata.json file contains all mod information and replacement mappings.

Required Fields

{
  "format_version": "1.0",
  "name": "Mod Name",
  "author": "Author Name",
  "version": "1.0.0",
  "replacements": {...}
}
format_version
string
required
Package format version. Current: "1.0"
name
string
required
Human-readable mod name.
author
string
required
Mod author or creator name.
version
string
required
Mod version in semantic versioning format (e.g., "1.0.0", "2.1.3")
replacements
object
required
Map of PCK files to replacement definitions. See Replacements Structure.

Optional Fields

description
string
default:"''"
Mod description or notes.
thumbnail
string
default:"undefined"
Relative path to thumbnail image (e.g., "thumbnail.png").
created_date
string
default:"undefined"
ISO 8601 timestamp of mod creation (e.g., "2024-01-15T10:30:00").
zzar_version
string
default:"undefined"
Version of ZZAR used to create the mod (e.g., "1.0.0").

Replacements Structure

The replacements object maps PCK files to their file replacements:
{
  "replacements": {
    "Streamed_SFX_1.pck": {
      "134133939": {
        "wem_file": "wem_files/134133939.wem",
        "sound_name": "player_jump",
        "lang_id": 0,
        "bnk_id": null,
        "file_type": "wem"
      },
      "86631895": {
        "wem_file": "wem_files/86631895.wem",
        "sound_name": "enemy_attack",
        "lang_id": 0,
        "bnk_id": null,
        "file_type": "wem"
      }
    },
    "SoundBank_SFX_1.pck": {
      "100000": {
        "wem_file": "wem_files/100000.wem",
        "sound_name": "ui_click",
        "lang_id": 0,
        "bnk_id": 2471637648,
        "file_type": "wem"
      }
    }
  }
}

PCK Level

"Streamed_SFX_1.pck": {...}
Keys are PCK filenames. These are the game audio packages being modified. Common PCK Files:
  • Streamed_SFX_1.pck, Streamed_SFX_2.pck - Streamed sound effects
  • SoundBank_SFX_1.pck, SoundBank_SFX_2.pck - Soundbank files
  • Streamed_English_1.pck - English voice lines
  • Streamed_Japanese_1.pck - Japanese voice lines
  • Streamed_Chinese_1.pck - Chinese voice lines

File Level

"134133939": {...}
Keys are file IDs (as strings). These are unique identifiers for audio files within the PCK.

Replacement Object

wem_file
string
required
Relative path to replacement WEM file within the package (e.g., "wem_files/12345.wem").
sound_name
string
default:"''"
Human-readable name or description of the sound.
lang_id
integer
required
Language ID for this replacement:
  • 0 = SFX (sound effects)
  • 1 = English
  • 2 = Chinese
  • 3 = Japanese
  • 4 = Korean
bnk_id
integer | null
required
BNK soundbank ID if file is inside a soundbank, otherwise null.
file_type
string
default:"'wem'"
File type, currently always "wem" for audio files.

Complete Example

{
  "format_version": "1.0",
  "name": "Custom Voice Pack",
  "author": "ModAuthor123",
  "version": "1.2.0",
  "description": "Replaces character voice lines with custom audio",
  "thumbnail": "thumbnail.png",
  "created_date": "2024-01-15T10:30:00",
  "zzar_version": "1.0.0",
  "replacements": {
    "Streamed_English_1.pck": {
      "1053247613": {
        "wem_file": "wem_files/1053247613.wem",
        "sound_name": "Ellen_Greeting_01",
        "lang_id": 1,
        "bnk_id": null,
        "file_type": "wem"
      },
      "1053247614": {
        "wem_file": "wem_files/1053247614.wem",
        "sound_name": "Ellen_Greeting_02",
        "lang_id": 1,
        "bnk_id": null,
        "file_type": "wem"
      }
    },
    "SoundBank_SFX_1.pck": {
      "100000": {
        "wem_file": "wem_files/100000.wem",
        "sound_name": "UI_Menu_Select",
        "lang_id": 0,
        "bnk_id": 2471637648,
        "file_type": "wem"
      }
    }
  }
}

Creating .zzar Packages

Using ModPackageManager

from src.mod_package_manager import ModPackageManager
from pathlib import Path

manager = ModPackageManager()

# Prepare metadata
metadata = {
    "name": "My Voice Mod",
    "author": "YourName",
    "version": "1.0.0",
    "description": "Custom voice replacements"
}

# Define replacements
replacements = {
    "Streamed_English_1.pck": {
        "1053247613": {
            "wem_path": "/path/to/1053247613.wem",
            "sound_name": "Ellen_Greeting",
            "lang_id": 1,
            "bnk_id": None,
            "file_type": "wem"
        }
    }
}

# Create package
package = manager.create_mod_package(
    output_path="my_mod.zzar",
    metadata=metadata,
    current_replacements=replacements,
    thumbnail_path="thumbnail.png"
)

print(f"Created: {package}")

Manual Creation

import zipfile
import json
from pathlib import Path

# Create metadata
metadata = {
    "format_version": "1.0",
    "name": "My Mod",
    "author": "Author",
    "version": "1.0.0",
    "replacements": {
        "Streamed_SFX_1.pck": {
            "134133939": {
                "wem_file": "wem_files/134133939.wem",
                "sound_name": "jump_sound",
                "lang_id": 0,
                "bnk_id": None,
                "file_type": "wem"
            }
        }
    }
}

# Create ZIP
with zipfile.ZipFile("my_mod.zzar", 'w', zipfile.ZIP_DEFLATED) as zf:
    # Add metadata
    zf.writestr("metadata.json", json.dumps(metadata, indent=2))
    
    # Add WEM files
    zf.write("path/to/134133939.wem", "wem_files/134133939.wem")
    
    # Add thumbnail (optional)
    zf.write("thumbnail.png", "thumbnail.png")

print("Package created: my_mod.zzar")

Validation

The ModPackageManager.validate_mod_package() method checks:
  1. File is valid ZIP
  2. metadata.json exists at root
  3. Required fields present:
    • name
    • author
    • version
    • replacements
  4. All referenced WEM files exist in archive
  5. format_version present (defaults to "1.0" if missing)
from src.mod_package_manager import ModPackageManager, InvalidModPackageError

manager = ModPackageManager()

try:
    metadata = manager.validate_mod_package("mod.zzar")
    print(f"Valid package: {metadata['name']} v{metadata['version']}")
except InvalidModPackageError as e:
    print(f"Invalid package: {e}")

Version Handling

When installing a mod with the same name:
  1. Newer version: Replaces existing installation
  2. Same version: Replaces existing installation
  3. Older version: Installation is skipped
Version comparison uses semantic versioning:
"2.0.0" > "1.5.0" > "1.5" > "1.0.0"

File Paths

All paths in metadata are relative to package root:
{
  "wem_file": "wem_files/12345.wem",
  "thumbnail": "thumbnail.png"
}
Valid:
  • wem_files/12345.wem
  • audio/sfx/sound.wem
  • thumbnail.png
Invalid:
  • /absolute/path/file.wem (absolute paths)
  • ../outside/package.wem (parent directory)
  • C:\\Windows\\file.wem (Windows absolute)

Thumbnail Guidelines

Recommended:
  • Format: PNG or JPEG
  • Size: 512x512 pixels
  • Aspect ratio: 1:1 (square)
  • File size: < 500 KB
Example:
from PIL import Image

# Resize image for thumbnail
img = Image.open("original.png")
img = img.resize((512, 512), Image.LANCZOS)
img.save("thumbnail.png", "PNG", optimize=True)

Best Practices

Naming

  • Use descriptive mod names
  • Include character/feature in name
  • Example: "Ellen Voice Pack", "Custom UI Sounds"

Versioning

  • Use semantic versioning: MAJOR.MINOR.PATCH
  • Increment MAJOR for breaking changes
  • Increment MINOR for new features
  • Increment PATCH for bug fixes

Organization

  • Group related WEM files together
  • Use subdirectories in wem_files/ if needed
  • Include descriptive sound_name values

Documentation

  • Use description field to explain changes
  • List compatibility requirements
  • Credit original audio sources

Distribution

Share .zzar files directly:
  • Upload to GameBanana, Nexus Mods, etc.
  • Share via direct download links
  • Users install via ZZAR GUI or CLI
Installation:
from src.mod_package_manager import ModPackageManager

manager = ModPackageManager()
result = manager.install_mod("downloaded_mod.zzar")

if result:
    print(f"Installed: {result['mod_name']} v{result['version']}")

Compatibility

  • Forward compatible: Older ZZAR can read newer formats (within same major version)
  • Backward compatible: Newer ZZAR can read older formats
  • format_version allows future format changes

Notes

  • Package files are standard ZIP archives
  • Can be opened with any ZIP tool
  • WEM files must be valid Wwise audio
  • File IDs must match game files
  • Use ZZAR audio browser to find file IDs
  • BNK-embedded files require correct bnk_id

Build docs developers (and LLMs) love