Skip to main content
Minecraft Creator Tools projects are organized around a core set of abstractions that manage add-ons, worlds, and related content. Understanding this structure is essential for working effectively with the tools.

Core Architecture

The Three Pillars: Carto, Project, and ProjectItem

The codebase is built around three fundamental types that work together:
Carto (Global Container)
  ├── Project (Add-on/World Container)
  │   ├── ProjectItem (Individual File/Resource)
  │   ├── ProjectItem
  │   └── ...
  └── Projects Storage

Carto

The Carto object is the main global container that manages:
  • User Preferences: Stored via the ICartoData interface
  • Storage Locations: Multiple IStorage objects for:
    • Preferences storage (prefsStorage)
    • New projects storage (projectsStorage)
    • Deployment storage (Minecraft target folder)
    • Worlds storage (minecraftWorlds folder)
  • Project Gallery: The loadGallery() function loads starter projects and templates
Carto is designed to be platform-agnostic, insulating the core logic from web vs. Node.js differences.

CartoApp

The CartoApp represents the application layer with platform-specific operations:
  • Platform Detection: hostType property and helper methods like isWeb or isNodeJs
  • Platform Abstraction: Thunk functions for platform-specific operations
  • Special Casing: Source of platform-specific behavior branches

Project

The Project object is the largest type and contains all logic for managing an add-on or world:
  • File Discovery: The _inferProjectItemsFromFolder function recursively identifies and creates ProjectItems based on file types
  • Metadata: Stores project preferences in IProjectData (saved as JSON)
  • Utilities: Logic is moving to static classes like ProjectUtilities, ProjectTools, and ProjectExporter
Example File Type Detection:
// A JSON file in /items/ folder in a behavior pack becomes:
// ProjectItem of type itemTypeBehaviorJson

ProjectItem

Represents a single logical resource (entity definition, script file, etc.):
  • Identification: Identified by canonicalized storagePath relative to project root
  • File Association: Typically associated with an IFile (or IFolder for worlds)
  • Manager Pattern: Uses IFile.manager property to store type-specific managers (e.g., EntityTypeDefinition)
  • Metadata: Stores item data in IProjectItemData (saved in parent project’s JSON)

Variants and Subpacks

ProjectItems support variants for handling subpacks:
RP/particles/fireworks.json              (default variant)
RP/subpacks/fancy/particles/fireworks.json  (variant)
Both files represent the same logical ProjectItem:
  • Default File: .defaultFile points to the main variant
  • Primary File: .primaryFile returns the “foremost” version based on project organization
  • Multiple Variants: One ProjectItem can have multiple file variants
In most projects, one ProjectItem has one file and one variant (""), corresponding to the default file.

File System Abstraction

The project uses a storage abstraction layer located in app/src/storage/:

IStorage Interface

All file operations go through asynchronous abstractions:
// Files and folders must be asynchronously loaded
await folder.load();

Storage Implementations

Implements local storage for browsers by wrapping localForage APIs, which use browser-standard key-value storage.Use case: Web-based project editing
Provides read-only access to files on the web.Use case: Loading samples and templates from web servers
Implements storage on top of Node.js fs API primitives.Use case: Desktop application and CLI toolsReference: app/src/storage/NodeStorage.ts
Provides read-only, non-authenticated access to GitHub repos via OctoKit APIs.Use case: Importing projects from GitHub repositories
A writeable implementation exists but requires server-side token management.
Handles .mcworld, .mcpack, and other ZIP-based formats.Use case: Packaging and reading Minecraft world/add-on archivesReference: app/src/storage/ZipStorage.ts

Manager Pattern

Files and folders have a .manager property for extended logic:
// Example: Entity definition manager attached to file
const entityFile = project.getFile("entities/zombie.json");
const entityManager = entityFile.manager as EntityTypeDefinition;

World Structure

Worlds have a specialized structure for handling Minecraft world data:

NBT Foundation

NBT Binary Parsing (NbtBinary.ts)
  ├── level.dat (World metadata)
  ├── MCStructure files (Structure snapshots) 
  └── LevelDB data (Chunk storage)
Key NBT Components:
  • NbtBinary.ts: Core NBT parsing for hierarchical typed data
  • NbtBinaryTag.ts: Individual tag representation
  • level.dat: World settings and metadata (see app/src/minecraft/NbtBinary.ts:1)

LevelDB and Chunks

World data is stored in LevelDB format:
  • LevelKeyValue pairs: Most are tied to specific chunks or subchunks
  • WorldLevelChunk: Focal point for understanding and unifying world data
  • Chunk Organization: Data organized by dimension, X, and Z coordinates
Reference: app/src/minecraft/MCWorld.ts:1

Project Organization Patterns

Standard Add-on Structure

project/
├── behavior_packs/
│   └── my_pack/
│       ├── manifest.json
│       ├── entities/
│       ├── items/
│       └── scripts/
├── resource_packs/
│   └── my_pack/
│       ├── manifest.json
│       ├── textures/
│       └── models/
└── .mcproject (metadata)

World Project Structure

world_project/
├── worlds/
│   └── my_world/
│       ├── level.dat
│       ├── db/  (LevelDB)
│       ├── behavior_packs/
│       └── resource_packs/
└── .mcproject

Best Practices

1

Use Storage Abstractions

Always use the IStorage interface rather than direct file system access. This ensures cross-platform compatibility.
// Good
const folder = await storage.rootFolder.ensureFolder("entities");

// Bad - platform-specific
const folder = fs.mkdirSync("entities");
2

Load Before Access

Remember that folders must be loaded before accessing their contents:
await folder.load();
const files = folder.files;
3

Work with ProjectItems

Use ProjectItem APIs rather than manipulating files directly when possible:
// Preferred
await projectItem.loadContent();
const content = projectItem.primaryFile?.content;
4

Respect Variants

When working with ProjectItems, use primaryFile to get the active variant:
// Gets the appropriate variant based on project organization
const file = projectItem.primaryFile;

Common Patterns

Loading a Project

const project = await carto.createNewProject(name);
await project.ensureLoadedProjectFolder();
await project.inferProjectItemsFromFiles(true);

Working with Files

const folder = storage.rootFolder.ensureFolder("entities");
await folder.ensureExists();
const file = folder.ensureFile("zombie.json");
file.setContent(jsonContent);
await file.saveContent();

Accessing Managers

if (file.manager instanceof EntityTypeDefinition) {
  const entity = file.manager as EntityTypeDefinition;
  // Work with entity-specific logic
}

Troubleshooting

Remember to call await folder.load() after creating or modifying files.
Call await project.inferProjectItemsFromFiles(true) to refresh the project item list.
Use StorageUtilities.canonicalizeName() to ensure path consistency across platforms.
Ensure await mcworld.loadMetaFiles(false) is called before accessing world properties.

Build docs developers (and LLMs) love