Getting Started
Set up your development environment and build your first TitanClient plugin.
Prerequisites (Native C++ Plugins)
To build native plugins you need:
- Visual Studio 2022 — with the "Desktop development with C++" workload, MSVC v143 toolset, and Windows SDK
- CMake 3.24+
- Git
- vcpkg — with the
VCPKG_ROOTenvironment variable set
CRT linkage: The client uses static MSVC runtime (/MT / /MTd).
Your plugin DLL must match this setting. Mixing /MT with /MD
causes allocator state divergence across the DLL boundary and will crash.
Prerequisites (JavaScript Plugins)
JS plugins require no build toolchain. You only need a text editor. For TypeScript support, install
tsc (TypeScript compiler) and use the bundled titan-plugin-sdk.d.ts type definitions.
Project Setup (Native C++)
CMakeLists.txt
Create a new directory for your plugin and add a CMakeLists.txt. The SDK provides a
titan_sdk interface library and a titan_add_plugin() CMake helper:
cmake_minimum_required(VERSION 3.20)
project(my_plugin LANGUAGES CXX)
# Point to the SDK (git submodule, downloaded release, etc.)
add_subdirectory(../titan-plugin-sdk _sdk)
add_library(my_plugin SHARED my_plugin.cpp)
target_link_libraries(my_plugin PRIVATE titan_sdk)
# Match the client's static CRT linkage
set_property(TARGET my_plugin PROPERTY MSVC_RUNTIME_LIBRARY
"MultiThreaded$<$:Debug>")
# Output directly to the plugin directory for testing
set_target_properties(my_plugin PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_DEBUG "$ENV{USERPROFILE}/.titanclient/plugins"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "$ENV{USERPROFILE}/.titanclient/plugins")
Plugin Source
A minimal plugin subclasses titan::Plugin, declares identity via TITAN_PLUGIN_META,
and registers with TITAN_REGISTER_PLUGIN:
#include <titan/plugin.h>
#include <titan/client.h>
#include <titan/query.h>
#include <titan/render.h>
#include <titan/setting.h>
#include <titan/utils/inventory.h>
class MyPlugin : public titan::Plugin {
TITAN_PLUGIN_META(
"my_plugin",
"My Plugin",
"Shows how to wire up a native Titan plugin.",
"Your Name",
"1.0.0",
/*defaultEnabled=*/false)
public:
titan::BoolSetting loud{this, "loud", "Verbose logging", false};
MyPlugin() {
onRender(titan::Layer::AboveScene, [this] { drawWorld(); });
}
void onGameTick(int32_t tick) override {
if (loud && tick % 10 == 0) {
titan::logf("tick=%d invFull=%d",
tick,
titan::utils::Inventory::isFull() ? 1 : 0);
}
}
private:
void drawWorld() {
auto local = titan::state::client().localPlayer();
if (!local) return;
titan::queries::npcs()
.nameContains("Chicken")
.forEach([](const titan::Npc& n) {
titan::overlay().entityBox(n, 0xFF00FF00);
});
}
};
TITAN_REGISTER_PLUGIN(MyPlugin, "my_plugin")
Building
cmake --preset default
cmake --build --preset debug
The built DLL lands in %USERPROFILE%\.titanclient\plugins\. Launch TitanClient and your plugin
appears in the controller's plugin list.
Project Setup (JavaScript)
Create a .js file in %USERPROFILE%\.titanclient\plugins\:
/// <reference path="../titan-plugin-sdk.d.ts" />
class MyPlugin extends titan.Plugin {
id = "my_js_plugin";
name = "My JS Plugin";
description = "JS version of the hello-world sample.";
author = "Your Name";
version = "1.0.0";
loud = this.boolSetting({
key: "loud",
name: "Verbose logging",
default: false
});
onGameTick(tick) {
if (this.loud && tick % 10 === 0) {
const full = titan.utils.inventory.isFull ? 1 : 0;
titan.logf("tick=%d invFull=%d", tick, full);
}
}
onRender() {
const local = titan.state.client.localPlayer;
if (!local) return;
titan.queries
.npcs()
.nameContains("Chicken")
.forEach((n) => titan.overlay.entityBox(n, 0xff00ff00));
}
}
titan.register(new MyPlugin());
Save the file and TitanClient picks it up immediately — the file watcher hot-reloads JS plugins on every save. No build step required.
Plugin Identity
Every plugin has a unique string ID (the first argument to TITAN_PLUGIN_META or the id
property in JS). This ID is used by the controller to persist settings and enabled state.
Never change a published plugin's ID. Changing it orphans the user's saved settings and enabled state. Treat the ID as a permanent identifier, not a display name.
Plugin Directories
During development, the plugin host scans these directories for DLLs and JS files (first match wins for duplicate IDs):
- Next to the client DLL / executable (multiple config-relative paths for multi-config builds)
%USERPROFILE%\.titanclient\plugins
The CMake output directory in the quickstart points directly at the user plugins folder so your plugin loads automatically on launch. Published plugins are delivered to end-users automatically through the controller — no manual file placement required.
Next Steps
- C++ SDK Guide — full lifecycle, queries, state facades, overlays, and threading model
- Plugin Settings — declare settings with sections and control types
- JavaScript API Guide — the
_titannamespace, callbacks, and TypeScript types