Skip to main content

Overview

BetterModel follows a clean, layered architecture that separates concerns and enables multi-platform support. The codebase is organized into four main layers: API, Core, Platform, and NMS.

Module Structure

Location: api/ and api/bukkit-api/The API layer defines contracts and interfaces without implementation details:
  • Pure interfaces and data classes
  • No platform-specific dependencies
  • Stable public API surface
  • Published to Maven Central
Key packages:
  • kr.toxicity.model.api - Core API classes
  • kr.toxicity.model.api.tracker - Tracker interfaces
  • kr.toxicity.model.api.animation - Animation system
  • kr.toxicity.model.api.bone - Bone manipulation
  • kr.toxicity.model.api.bukkit - Bukkit-specific adapters
Location: core/ and core/bukkit-core/The core layer implements the API contracts:
  • Business logic and orchestration
  • Model loading and parsing
  • Animation processing
  • Resource pack generation
  • Platform-agnostic implementation
Responsibilities:
  • BlockBench .bbmodel file parsing
  • Animation keyframe interpolation
  • Packet bundling and optimization
  • Resource management
Location: platform/paper/, platform/spigot/, platform/fabric/Platform-specific implementations and integrations:
  • Server lifecycle management
  • Plugin/mod loading
  • Platform-specific optimizations
  • Event system integration
Platform modules:
  • Paper - Modern async scheduler, optimized packet handling
  • Spigot - Legacy scheduler compatibility
  • Fabric - Mod loader integration, Polymer resource packs
Location: nms/v1_21_R1/, nms/v1_21_R3/, etc.Version-specific Minecraft internals access:
  • Packet manipulation
  • Entity spawning
  • Display entity control
  • Network protocol handling
Supported versions: 1.21 through 1.21.11

Data Flow

1

Model Loading

Core layer reads .bbmodel files from disk and parses the JSON structure into internal data models.
2

Resource Generation

Core layer generates optimized resource pack with custom model data and textures.
3

Tracker Creation

API user creates a tracker through ModelRenderer. Core layer instantiates the appropriate tracker type (Entity/Dummy).
4

Rendering

NMS layer spawns item display entities and sends packets to connected players. Platform layer handles scheduling.
5

Animation

Core layer interpolates animation keyframes. NMS layer sends transformation packets at 40Hz (TRACKER_TICK_INTERVAL).

Design Principles

Separation of Concerns

Each layer has a single responsibility and doesn’t leak implementation details.

Dependency Direction

Dependencies flow one way: API ← Core ← Platform ← NMS

Platform Abstraction

Platform-specific code is isolated, allowing easy addition of new platforms.

Version Isolation

NMS version differences are contained in separate modules.

Key Components

BetterModelPlatform

The platform singleton provides access to all managers:
BetterModelPlatform platform = BetterModel.platform();

// Access managers
ModelManager models = platform.modelManager();
PlayerManager players = platform.playerManager();
ProfileManager profiles = platform.profileManager();

Model Manager

Loads and manages model renderers:
  • Discovers .bbmodel files in BetterModel/models/ and BetterModel/players/
  • Caches parsed models
  • Provides lookup by name
  • Handles hot-reloading

Tracker System

Manages model instances (see Trackers):
  • EntityTracker - Attached to entities, follows movement
  • DummyTracker - Standalone at fixed locations
  • EntityTrackerRegistry - Per-entity tracker collection

Render Pipeline

Orchestrates rendering for a single model instance:
  • Manages bone hierarchy
  • Coordinates packet sending
  • Handles player visibility
  • Processes animations

Thread Safety

BetterModel uses asynchronous design for performance. Most operations are thread-safe, but tracker modification should happen on the main thread or within scheduled tasks.

Async Operations

  • Model loading and parsing
  • Resource pack generation
  • Profile resolution (player skins)

Sync Operations

  • Tracker creation and modification
  • Entity manipulation
  • Player-specific operations

Folia Considerations

On Folia, operations are region-specific:
// Use region-safe task scheduling
tracker.location().task(() -> {
    // This runs in the correct region
    tracker.animate("attack");
});

Extension Points

Implement RenderSource to create custom model sources beyond entities and locations.
Use Molang expressions in animations for dynamic, data-driven behavior.
Implement TrackerUpdateAction for custom display modifications.
Subscribe to BetterModel events through BetterModelEventBus for lifecycle hooks.

Best Practices

Follow the existing module boundaries when contributing. API changes require careful consideration of backward compatibility.
For detailed architectural guidelines, see the AGENTS.md file in the repository.

See Also

Models & Renderers

Learn about the model loading system

Trackers

Understand tracker lifecycle and types

API Reference

Explore the complete API

Build docs developers (and LLMs) love