Getting Started

What is a DeathClient JavaScript plugin?

A DeathClient plugin is a .js file executed by DeathClient's built-in JavaScript runtime. Plugins can register mods, settings, local commands, HUD modules, event handlers, runtime models, client-side entities, runtime items, textures, storage, timers, sounds, and player/world actions.

The JavaScript API is exposed as window.DeathClient. The current bridge identifies itself as JavaScript bridge version 1.5.0 and API version 3.0.0.

Important: This reference documents the API exposed by the current DeathClient bridge. It intentionally does not document older methods that are not present in the current bridge, such as dc.getAllMods(), dc.pickResource(), remote resource fetch helpers, or dc.storage.clear().

Your first plugin

const dc = window.DeathClient;

dc.createMod({
    name: "Hello World",
    displayName: "Hello World",
    description: "My first DeathClient plugin",
    category: "PLAYER",
    isCheat: false,

    onEnable: function() {
        dc.chat("§aHello from my plugin!");
    },

    onUpdate: function() {
        // Called by DeathClient's normal mod update path.
    }
});

Basic plugin workflow

  1. Get the API with const dc = window.DeathClient;.
  2. Register one or more mods with dc.createMod().
  3. Add settings, callbacks, commands, or other APIs as needed.
  4. Use client-side APIs such as dc.chat(), dc.player, dc.storage, and the advanced runtime systems.

JavaScript Basics

Only normal JavaScript is required for the core API.

Variables

let coins = 10;
let playerName = "Steve";
let enabled = true;

Conditions

if (dc.player.health < 5) {
    dc.chat("§cLow health!");
}

Functions

function sayHello(name) {
    dc.chat("Hello " + name);
}

sayHello("Steve");

Loops

for (let i = 0; i < 5; i++) {
    dc.chat("Count: " + i);
}

Objects

const config = {
    damage: 10,
    enabled: true,
    mode: "normal"
};

dc.log(config.mode);

Useful operators

OperatorExampleMeaning
===x === 10Exactly equal.
!==x !== 10Not equal.
>x > 10Greater than.
<x < 10Less than.
&&a && bBoth conditions must be true.
||a || bAt least one condition is true.
!!enabledInvert a boolean.

Plugin Structure

A single plugin file can contain multiple mods, HUDs, commands, global events, settings, runtime assets, and helper functions.

const dc = window.DeathClient;

// Shared state
const state = {
    count: 0
};

// Main mod
dc.createMod({
    name: "Example",
    description: "Example plugin",
    category: "PLAYER",
    settings: [],

    onEnable: function(settings) {},
    onDisable: function(settings) {},
    onUpdate: function(settings) {},
    onChat: function(message) {}
});

// Local command
dc.createCommand({
    name: "example",
    prefix: ".",
    execute: function(args) {}
});
The current command API uses name, not command, when passing the object to dc.createCommand().

Mod Registration CORE

dc.createMod(config)

PropertyTypeDescription
nameStringRequired internal mod name.
displayNameStringOptional GUI display name. Defaults to name.
descriptionStringDescription shown for the mod.
categoryStringCommon categories include PLAYER, MOVEMENT, COMBAT, RENDER, WORLD, HUD.
isCheatBooleanMarks the module as a cheat in the mod system.
settingsArraySettings created with dc.createSetting().
onEnableFunctionRuns when the Java-side module is enabled.
onDisableFunctionRuns when the Java-side module is disabled.
onUpdateFunctionCalled from the Java mod update path.
onRender2DFunctionCalled from the 2D rendering path when wired by the client.
onChatFunctionReceives chat text delivered to the JS mod.

Example

dc.createMod({
    name: "Welcome",
    displayName: "Welcome",
    description: "Shows a message when enabled.",
    category: "PLAYER",
    isCheat: false,

    onEnable: function() {
        dc.chat("§aWelcome!");
    },

    onDisable: function() {
        dc.chat("§cGoodbye!");
    }
});

Settings CORE

Settings are serialized into the mod registration payload and synchronized into the mod's settingsCache.

Toggle / Boolean

const enabled = dc.createSetting(
    "Toggle",
    "Enabled",
    true
);

Slider / Number

const delay = dc.createSetting(
    "Slider",
    "Delay",
    50,
    0,
    1000,
    1
);

Mode

const mode = dc.createSetting(
    "Mode",
    "Mode",
    "Normal",
    ["Normal", "Aggressive", "Passive"]
);

String

const message = dc.createSetting(
    "String",
    "Message",
    "Hello!"
);

Complete example

dc.createMod({
    name: "Message Mod",

    settings: [
        dc.createSetting("Toggle", "Spam", false),
        dc.createSetting("Slider", "Delay", 1000, 100, 5000, 100),
        dc.createSetting("Mode", "Style",
            "Friendly",
            ["Friendly", "Funny", "Serious"]
        ),
        dc.createSetting("String", "Message", "Hello!")
    ],

    onUpdate: function(settings) {
        if (!settings["Spam"].value) {
            return;
        }

        const delay = settings["Delay"].value;
        const style = settings["Style"].value;
        const message = settings["Message"].value;

        // Plugin logic here.
    }
});

Commands CURRENT

DeathClient commands are local client commands. They are intercepted before ordinary chat handling when the typed message begins with the command prefix.

dc.registerCommand(name, prefix, execute)

dc.registerCommand(
    "hello",
    ".",
    function(args) {
        dc.chat("§aHello!");
        dc.chat("Arguments: §f" + args);
    }
);

dc.createCommand(config)

This is the object-style equivalent.

dc.createCommand({
    name: "hello",
    prefix: ".",
    execute: function(args) {
        dc.chat("§aHello " + (args || "world"));
    }
});

Typing:

.hello test something

passes this string to the callback:

args === "test something"

Command with multiple arguments

dc.createCommand({
    name: "teleport",
    prefix: ".",
    execute: function(args) {
        const parts = String(args || "").trim().split(/\s+/);

        if (parts.length < 3) {
            dc.chat("§cUsage: .teleport <x> <y> <z>");
            return;
        }

        const x = Number(parts[0]);
        const y = Number(parts[1]);
        const z = Number(parts[2]);

        if (!Number.isFinite(x) ||
            !Number.isFinite(y) ||
            !Number.isFinite(z)) {
            dc.chat("§cInvalid coordinates.");
            return;
        }

        dc.player.x = x;
        dc.player.y = y;
        dc.player.z = z;
    }
});

Unregistering the JavaScript callback

dc.unregisterCommand("hello");
Local command interception is part of the client-side command system. A registered command uses its prefix exactly as provided, so a command registered with "." responds to .hello.

Callbacks CORE

CallbackPurpose
onEnable(settings)Runs when the mod is enabled.
onDisable(settings)Runs when the mod is disabled.
onUpdate(settings)Runs from the normal mod update path.
onRender2D(settings)Runs from the 2D render path when used by the client.
onChat(message)Receives incoming chat text.
Do not perform expensive work every tick. Avoid large allocations, repeated JSON parsing, huge entity loops, or unnecessary resource operations in update callbacks.

HUD Mods CORE

dc.createHudMod(config)

dc.createHudMod({
    name: "My HUD",
    displayName: "My HUD",
    description: "A custom HUD element",
    category: "HUD",

    width: 120,
    height: 24,

    onRender2D: function() {
        // HUD position is exposed through this.x / this.y / this.scale.
    }
});
HUD propertyDescription
this.xCurrent X position.
this.yCurrent Y position.
this.scaleCurrent HUD scale.
The bridge synchronizes HUD position and scale between JavaScript and the Java HUD system. The current bridge does not expose a JavaScript drawString() helper.

Chat API CORE

APIDescription
dc.chat(message)Displays local client-side chat text. It is not sent to the server.
dc.sendChat(message)Sends chat text through the normal client send-chat path.
dc.sendCommand(command)Sends a slash command. A leading / is added automatically.
dc.chat("§aLocal message");
dc.sendChat("hello server");
dc.sendCommand("spawn");
dc.sendCommand("/spawn");

Mod Control CORE

APIDescription
dc.enableMod(name)Requests that a mod be enabled.
dc.disableMod(name)Requests that a mod be disabled.
dc.toggleMod(name)Toggles a mod.
dc.isEnabled(name)Reads the JavaScript-side toggle state.
dc.getMods()Returns names from the JavaScript mod registry.
dc.getMod(name)Returns the JavaScript mod object or null.
dc.createCommand({
    name: "flight",
    prefix: ".",
    execute: function() {
        if (dc.isEnabled("Fly")) {
            dc.disableMod("Fly");
            dc.chat("§cFly disabled.");
        } else {
            dc.enableMod("Fly");
            dc.chat("§aFly enabled.");
        }
    }
});

Player & World CORE

Player properties

PropertyReadWrite
dc.player.xYesYes
dc.player.yYesYes
dc.player.zYesYes
dc.player.motionXYesYes
dc.player.motionYYesYes
dc.player.motionZYesYes
dc.player.yawYesYes
dc.player.pitchYesYes
dc.player.nameYesNo
dc.player.healthYesNo
dc.player.maxHealthYesNo
dc.player.onGroundYesNo

Jump

dc.player.jump();

Movement

dc.player.motionX = 1.0;
dc.player.motionY = 0.0;
dc.player.motionZ = 0.0;

Rotation

dc.player.yaw += 45;
dc.player.pitch = 10;

World properties

PropertyReadWrite
dc.world.timeYesYes
dc.world.rainingYesNo
dc.world.time = 6000;
Player position and motion writes are client actions. Server-side movement correction, anti-cheat checks, or rubberbanding can still override them.

Events CORE

dc.on(event, callback)

dc.on("chat_receive", function(data) {
    dc.chat("Received: " + data.message);
});

dc.off(event, callback)

function handleChat(data) {
    dc.log(data.message);
}

dc.on("chat_receive", handleChat);
dc.off("chat_receive", handleChat);

dc.once(event, callback)

dc.once("chat_receive", function(data) {
    dc.chat("This callback runs once.");
});

dc.emit(event, data)

Plugins can emit local JavaScript events to listeners registered through the same JavaScript event registry.

dc.on("my_event", function(data) {
    dc.log("Value: " + data.value);
});

dc.emit("my_event", {
    value: 42
});

Event names used by the current system

EventPayloadDescription
tickState objectClient tick event when emitted by the Java side.
chat_receive{ message }Incoming chat text.
mod_enableModule dataModule enable event when emitted.
mod_disableModule dataModule disable event when emitted.
Custom namesAny valueUsable entirely within the JavaScript event system.
Event availability depends on whether the Java client path emits that event. dc.on(), dc.off(), dc.once(), and dc.emit() themselves are part of the bridge.

Persistent Storage CORE

The current bridge exposes browser local-storage persistence under dc.storage.

Save

dc.storage.set("coins", 250);

Objects and arrays

dc.storage.set("settings", {
    price: 10,
    enabled: true,
    modes: ["A", "B", "C"]
});

Load

const coins = dc.storage.get("coins", 0);
dc.chat("Coins: " + coins);

Remove

dc.storage.remove("coins");
APIPurpose
dc.storage.get(key, fallback)Reads JSON data, returning the fallback when absent or invalid.
dc.storage.set(key, value)Serializes and stores a value.
dc.storage.remove(key)Removes a stored key.
The current bridge does not expose dc.storage.clear(). Remove keys individually with dc.storage.remove().

In-Memory Resources CORE

The current bridge provides an in-memory resource cache. It does not expose the older remote fetch helpers.

APIDescription
dc.resources.set(id, value)Stores a value in the JavaScript resource cache and returns it.
dc.resources.get(id)Returns the cached value or undefined.
dc.resources.has(id)Returns whether the cache contains the ID.
dc.resources.remove(id)Deletes the cached ID.
dc.resources.set("score", 100);

const score = dc.resources.get("score");

if (dc.resources.has("score")) {
    dc.chat("Score: " + score);
}

dc.resources.remove("score");
The current bridge does not expose fetchText(), fetchJSON(), fetchBlob(), image(), or pickResource() under dc.resources.

Timers CORE

Timeout

const id = dc.setTimeout(function() {
    dc.chat("Two seconds passed.");
}, 2000);

dc.clearTimeout(id);

Interval

const id = dc.setInterval(function() {
    dc.chat("Repeating...");
}, 1000);

dc.clearInterval(id);
APIDescription
dc.setTimeout(fn, ms)Runs a function once.
dc.clearTimeout(id)Cancels a timeout.
dc.setInterval(fn, ms)Runs a function repeatedly.
dc.clearInterval(id)Cancels an interval.

Audio & Titles CORE

Sound

dc.playSound(
    "random.orb",
    1.0,
    1.0
);
ParameterDescription
soundNameSound resource identifier.
volumeVolume. Defaults to 1.
pitchPitch. Defaults to 1.

Title

dc.showTitle(
    "§cWARNING",
    "§7Something happened!"
);

Debugging CORE

APIDescription
dc.log(message)Writes a normal console log.
dc.warn(message)Writes a warning console log.
dc.error(message)Writes an error console log.
dc.log("Plugin started");
dc.warn("Something may be wrong");
dc.error("Something failed");

Runtime Models ADVANCED

The current bridge exposes runtime model registration through dc.models.register(). Models are supplied as JSON strings.

dc.models.register(id, json)

const model = {
    texture_size: [64, 32],
    elements: [
        {
            from: [-4, 0, -3],
            to:   [ 4, 10, 3]
        },
        {
            from: [-3, 10, -3],
            to:   [ 3, 16, 3]
        }
    ]
};

dc.models.register(
    "beast",
    JSON.stringify(model)
);

Alias

dc.entities.registerModel(
    "beast",
    JSON.stringify(model)
);

The alias above forwards to the same model registration queue.

Model structure

FieldDescription
texture_sizeTexture width and height.
elementsArray of cuboid model elements.
fromMinimum corner of the cuboid.
toMaximum corner of the cuboid.
facesOptional per-face texture/UV information supported by the runtime parser.
rotationOptional rotation information for an element.
originOptional rotation point for a rotated element.
The runtime model parser is intended for Blockbench-style cuboid model data, but the exact JSON accepted is determined by the Java runtime model parser.

Runtime Entities ADVANCED

The bridge exposes a runtime entity system built around registered entity configurations and queued Java-side spawning/removal/query operations.

dc.entities.create(config)

The canonical creation API is an alias of dc.entities.register().

const e = dc.entities.create({
    id: "beast",
    displayName: "Death Beast",
    width: 1.0,
    height: 2.0,
    health: 100,
    damage: 8,
    speed: 0.30,
    gravity: true,
    ai: true,
    model: "beast",
    texture: "beast"
});

Entity configuration

FieldDefaultDescription
idRequiredUnique entity identifier within the plugin.
displayNameidDisplay name.
width0.8Entity width.
height1.8Entity height.
health20Maximum/runtime health configuration.
damage2Configured damage value.
speed0.2Configured movement speed.
gravitytrueWhether the runtime entity uses gravity.
aitrueWhether runtime AI is requested.
modelidRuntime model identifier.
textureidRuntime texture identifier.

Spawn

dc.entities.spawn(
    e,
    dc.player.x + 5,
    dc.player.y,
    dc.player.z + 5
);

Equivalent method on the returned entity configuration:

e.spawn(
    dc.player.x + 5,
    dc.player.y,
    dc.player.z + 5
);

Get an entity

const entity = dc.entities.get(nativeEntityId);

if (entity) {
    dc.chat("Found runtime entity.");
}

Remove an entity

dc.entities.remove(entity);

or:

dc.entities.remove(nativeEntityId);

An entity configuration also exposes:

e.remove();

Entity tick callback

dc.entities.onTick(entity, function(runtimeEntity) {
    dc.log("Runtime entity tick");
});

Or through the entity object:

e.onTick(function(runtimeEntity) {
    dc.log("Ticking " + runtimeEntity.id);
});

Nearby entity query

const nearby = dc.entities.nearby(
    dc.player.x,
    dc.player.y,
    dc.player.z,
    16
);

Alias:

const nearby = dc.entities.getNearby(
    dc.player.x,
    dc.player.y,
    dc.player.z,
    16
);
Runtime entity methods are an advanced bridge feature. They depend on the Java-side queue consumers and runtime entity manager being present in the client build. The JavaScript methods themselves are exposed by the current bridge.

Runtime Textures ADVANCED

Runtime textures are loaded from an image URL and converted into ARGB pixel data for the Java-side runtime texture system.

dc.entities.registerTexture(id, url, callback)

dc.entities.registerTexture(
    "beast",
    "https://example.com/beast.png",
    function(error, success) {
        if (error) {
            dc.error(String(error));
            return;
        }

        dc.chat("§aEntity texture submitted.");
    }
);

The browser loads the image asynchronously. The callback is invoked after the image is successfully decoded or after an image loading error.

Requirements

Typical runtime asset sequence

const model = {
    texture_size: [64, 32],
    elements: [
        { from: [-4, 0, -3], to: [4, 10, 3] }
    ]
};

dc.models.register(
    "beast",
    JSON.stringify(model)
);

dc.entities.registerTexture(
    "beast",
    "https://example.com/beast.png",
    function(error) {
        if (error) {
            dc.error(error);
            return;
        }

        const entity = dc.entities.create({
            id: "beast",
            displayName: "Death Beast",
            model: "beast",
            texture: "beast"
        });

        dc.entities.spawn(
            entity,
            dc.player.x + 5,
            dc.player.y,
            dc.player.z + 5
        );
    }
);
Cross-origin restrictions can affect image loading. A URL that exists does not guarantee that the browser will allow the image to be read through canvas.

Runtime Items ADVANCED

The current bridge exposes a runtime item registry with item configuration, model registration, and texture registration.

dc.items.register(config)

const item = dc.items.register({
    id: "death_blade",
    name: "Death Blade",
    maxStackSize: 1,
    model: "death_blade",
    texture: "death_blade"
});
FieldDefaultDescription
idRequiredRuntime item identifier.
nameidItem name.
displayNameUsed as fallbackAccepted as the name source.
maxStackSize64Configured maximum stack size.
modelidRuntime item model identifier.
textureidRuntime item texture identifier.

Get an item

const item = dc.items.get("death_blade");

Register an item model

dc.items.registerModel(
    "death_blade",
    JSON.stringify(model)
);

Register an item texture

dc.items.registerTexture(
    "death_blade",
    "https://example.com/death_blade.png",
    function(error, success) {
        if (error) {
            dc.error(error);
            return;
        }

        dc.chat("§aItem texture submitted.");
    }
);
Registering an item through the JavaScript bridge queues the runtime item registration. Full in-game behavior depends on the Java runtime item manager and item renderer being present in the client build.

Working Examples

Example: Health Alert

const dc = window.DeathClient;

dc.createMod({
    name: "Health Alert",
    description: "Warns when health is low.",
    category: "PLAYER",
    isCheat: false,

    settings: [
        dc.createSetting(
            "Slider",
            "Threshold",
            5,
            1,
            20,
            1
        )
    ],

    onUpdate: function(settings) {
        const threshold = settings["Threshold"].value;

        if (dc.player.health > 0 &&
            dc.player.health <= threshold) {

            dc.playSound("random.orb", 1.0, 1.0);
        }
    }
});

Example: Local command

const dc = window.DeathClient;

dc.createCommand({
    name: "where",
    prefix: ".",
    execute: function() {
        dc.chat(
            "X: " + dc.player.x +
            " Y: " + dc.player.y +
            " Z: " + dc.player.z
        );
    }
});

Example: Persistent counter

const dc = window.DeathClient;

let count = dc.storage.get("count", 0);

dc.createMod({
    name: "Counter",

    onEnable: function() {
        count++;

        dc.storage.set("count", count);

        dc.chat(
            "§eLoaded count: §f" + count
        );
    }
});

Example: Runtime model + entity

const dc = window.DeathClient;

const model = {
    texture_size: [64, 32],
    elements: [
        { from: [-4, 0, -3], to: [4, 10, 3] },
        { from: [-3, 10, -3], to: [3, 16, 3] },
        { from: [-6, 3, -2], to: [-4, 12, 2] },
        { from: [4, 3, -2], to: [6, 12, 2] }
    ]
};

dc.createMod({
    name: "Death Beast",
    displayName: "Death Beast",
    description: "Runtime entity example",
    category: "WORLD",
    isCheat: false,

    onEnable: function() {
        dc.models.register(
            "beast",
            JSON.stringify(model)
        );

        const entity = dc.entities.create({
            id: "beast",
            displayName: "Death Beast",
            width: 1.0,
            height: 2.0,
            health: 100,
            damage: 8,
            speed: 0.30,
            gravity: true,
            ai: true,
            model: "beast",
            texture: "beast"
        });

        entity.onTick(function(runtimeEntity) {
            dc.log("Death Beast tick");
        });

        dc.entities.spawn(
            entity,
            dc.player.x + 5,
            dc.player.y,
            dc.player.z + 5
        );
    }
});

Troubleshooting

My local command does nothing

Check all three parts:

dc.createCommand({
    name: "test",
    prefix: ".",
    execute: function(args) {
        dc.chat("Command fired: " + args);
    }
});

Then type:

.test hello

The callback registration uses name. Using the older command property with dc.createCommand() will not create the expected command.

The API capability scanner says something is unavailable

That means the exact JavaScript property or function does not exist in the currently installed bridge. Check the exact spelling and namespace.

dc.entities exists but spawning fails

The entity JavaScript API is queue-based. The bridge can expose creation, spawning, removal, ticking, and queries while the Java-side runtime queue consumers are missing or incompatible. Check the Java entity manager/plugin manager integration.

Texture registration fails

Check the URL, image format, browser loading restrictions, and cross-origin access. The current bridge decodes the image through an HTML canvas before queueing its pixels.

Storage values disappear

Use dc.storage.set() and dc.storage.get() consistently. Values are JSON serialized. Unsupported circular objects cannot be serialized.

A mod does not receive updates

Make sure the mod was registered successfully and the client-side mod manager is calling its update path. JavaScript callbacks are not a replacement for the Java mod lifecycle; they are invoked by it.