defold-native-extension-editing
Defold native extension development. Use when creating or editing C/C++ (.c, .cpp, .h, .hpp), JavaScript (.js), or manifest files in native extension directories (src/, include/, lib/, api/).
Best use case
defold-native-extension-editing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Defold native extension development. Use when creating or editing C/C++ (.c, .cpp, .h, .hpp), JavaScript (.js), or manifest files in native extension directories (src/, include/, lib/, api/).
Teams using defold-native-extension-editing should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/defold-native-extension-editing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How defold-native-extension-editing Compares
| Feature / Agent | defold-native-extension-editing | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Defold native extension development. Use when creating or editing C/C++ (.c, .cpp, .h, .hpp), JavaScript (.js), or manifest files in native extension directories (src/, include/, lib/, api/).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Defold Native Extension Structure
A native extension is a folder containing `ext.manifest` and native code for extending the Defold engine.
## Required structure
```
my_extension/
├── ext.manifest # Extension manifest (YAML)
├── src/ # Source code (C/C++/ObjC/JS)
│ ├── extension.cpp # Main extension entry point
│ └── ...
├── include/ # Public headers (optional)
├── lib/ # Platform libraries (optional)
│ ├── x86_64-win32/
│ ├── x86_64-linux/
│ ├── arm64-ios/
│ └── ...
├── api/ # Script API definitions (optional)
│ └── my_extension.script_api
└── res/ # Platform resources (optional)
└── android/
```
## ext.manifest format
```yaml
name: "MyExtension"
platforms:
x86_64-win32:
context:
defines: ["MY_DEFINE"]
libs: ["user32"]
arm64-ios:
context:
frameworks: ["UIKit"]
```
## Extension entry point (C++)
```cpp
#define EXTENSION_NAME MyExtension
#define LIB_NAME "MyExtension"
#define MODULE_NAME "myextension"
#include <dmsdk/sdk.h>
static int MyFunction(lua_State* L)
{
// Implementation
return 0;
}
static const luaL_reg Module_methods[] =
{
{"my_function", MyFunction},
{0, 0}
};
static void LuaInit(lua_State* L)
{
int top = lua_gettop(L);
luaL_register(L, MODULE_NAME, Module_methods);
lua_pop(L, 1);
assert(top == lua_gettop(L));
}
static dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params)
{
return dmExtension::RESULT_OK;
}
static dmExtension::Result InitializeMyExtension(dmExtension::Params* params)
{
LuaInit(params->m_L);
return dmExtension::RESULT_OK;
}
static dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
{
return dmExtension::RESULT_OK;
}
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeMyExtension, 0, InitializeMyExtension, 0, 0, FinalizeMyExtension)
```
## HTML5/JavaScript extension
For web platform, use `.js` files in `src/`:
```javascript
var MyExtension = {
MyFunction: function() {
// Implementation
}
};
mergeInto(LibraryManager.library, MyExtension);
```
## Platform library paths (lib/)
- `x86_64-win32/` - Windows 64-bit
- `x86-win32/` - Windows 32-bit
- `x86_64-linux/` - Linux 64-bit
- `arm64-osx/` - macOS ARM
- `x86_64-osx/` - macOS Intel
- `arm64-ios/` - iOS ARM64
- `armv7-android/`, `arm64-android/` - Android
- `js-web/`, `wasm-web/` - HTML5
## Prefer dmSDK over Lua API calls
**Always use direct C++ dmSDK functions instead of calling Lua API wrappers** (e.g. `lua_getglobal(L, "go")` + `lua_call`). The dmSDK provides efficient C++ equivalents for most Lua game object operations.
### Key dmSDK patterns
**Getting game object instances from Lua:**
```cpp
// Get the calling script's game object instance
dmGameObject::HInstance caller = dmScript::CheckGOInstance(L);
// Get the collection from any instance
dmGameObject::HCollection collection = dmGameObject::GetCollection(caller);
// Resolve a hash identifier (from Lua stack) to an instance
dmhash_t id = dmScript::CheckHash(L, index);
dmGameObject::HInstance target = dmGameObject::GetInstanceFromIdentifier(collection, id);
```
**Manipulating game objects directly in C++:**
```cpp
// Position (uses dmVMath::Point3)
dmVMath::Point3 pos = dmGameObject::GetPosition(instance);
dmGameObject::SetPosition(instance, dmVMath::Point3(x, y, z));
// Rotation (uses dmVMath::Quat)
dmVMath::Quat rot = dmGameObject::GetRotation(instance);
dmGameObject::SetRotation(instance, rot);
// Scale
float scale = dmGameObject::GetUniformScale(instance);
dmGameObject::SetScale(instance, scale);
dmGameObject::SetScale(instance, dmVMath::Vector3(sx, sy, sz));
```
**Math types — create once, reuse in loops:**
```cpp
dmVMath::Point3 pos(0.0f, 0.0f, 0.0f);
for (int i = 0; i < count; ++i)
{
pos.setX(computed_x);
pos.setY(computed_y);
dmGameObject::SetPosition(instance, pos);
}
```
**Extracting Lua types via dmScript:**
```cpp
dmVMath::Vector3* v = dmScript::CheckVector3(L, index);
dmVMath::Vector4* v4 = dmScript::CheckVector4(L, index);
dmVMath::Quat* q = dmScript::CheckQuat(L, index);
dmVMath::Matrix4* m = dmScript::CheckMatrix4(L, index);
dmhash_t hash = dmScript::CheckHash(L, index);
dmhash_t hash = dmScript::CheckHashOrString(L, index);
```
### Async Lua callbacks via dmScript
When a native extension needs to asynchronously invoke a user-provided Lua callback (e.g. after a platform event, timer, or async operation), use `dmScript::LuaCallbackInfo`. Reference: https://github.com/indiesoftby/defold-page-visibility/tree/main/page_visibility/src
**Storing a callback from Lua:**
```cpp
static dmScript::LuaCallbackInfo* g_Callback = 0;
static int SetCallback(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);
// Destroy previous callback to avoid leaks
if (g_Callback)
{
dmScript::DestroyCallback(g_Callback);
g_Callback = 0;
}
if (lua_isfunction(L, 1))
{
g_Callback = dmScript::CreateCallback(L, 1);
}
return 0;
}
```
**Invoking the callback later (from any native event):**
```cpp
static void OnAsyncEvent(int result_code)
{
if (!g_Callback || !dmScript::IsCallbackValid(g_Callback))
return;
lua_State* L = dmScript::GetCallbackLuaContext(g_Callback);
DM_LUA_STACK_CHECK(L, 0);
if (!dmScript::SetupCallback(g_Callback))
{
dmScript::DestroyCallback(g_Callback);
g_Callback = 0;
return;
}
// Push arguments after self (self is already on stack from SetupCallback)
lua_pushnumber(L, result_code);
dmScript::PCall(L, 2, 0); // 2 = self + 1 user argument
dmScript::TeardownCallback(g_Callback);
}
```
**Cleanup in Finalize (prevent leaks on extension unload):**
```cpp
static dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
{
if (g_Callback)
{
dmScript::DestroyCallback(g_Callback);
g_Callback = 0;
}
return dmExtension::RESULT_OK;
}
```
**Lifecycle:** `CreateCallback` → `SetupCallback` → `PCall` → `TeardownCallback` → `DestroyCallback` (when done).
For one-shot callbacks, call `DestroyCallback` right after `TeardownCallback`. For persistent listeners, keep the callback and only destroy on replacement or finalize.
### When Lua API calls are acceptable
Only fall back to `lua_getglobal`/`lua_call` patterns when:
- The functionality has **no dmSDK C++ equivalent** (e.g. `go.animate`, `msg.post` to arbitrary URLs)
- You need to call a **user-defined Lua callback** without the `dmScript::LuaCallbackInfo` pattern (rare)
## Defold engine source as reference
The Defold engine source at https://github.com/defold/defold/tree/dev/engine contains extensive dmSDK usage examples. When implementing native extensions, actively study the engine source to find correct API usage patterns, especially:
- `engine/gameobject/` — game object manipulation (`dmGameObject::*`)
- `engine/gamesys/` — component systems (sprite, collision, factory, etc.)
- `engine/script/` — script bridge utilities (`dmScript::*`)
- `engine/dlib/` — math, hashing, logging, buffers (`dmVMath::*`, `dmLog*`, `dmBuffer::*`)
- `engine/render/` — render pipeline (`dmRender::*`)
Additionally, the Spine extension at https://github.com/defold/extension-spine/tree/main/defold-spine is an excellent real-world reference for dmSDK usage — it demonstrates component registration, game object manipulation, rendering, resource management, and script bindings.
Use the Librarian tool or `defold-api-fetch` skill to fetch specific API docs. Browse engine source and extension-spine on GitHub for real-world usage when the API docs are insufficient.
## Code formatting
When working with native extensions, ensure `.clang-format` exists in project root for consistent C/C++ formatting. If missing, fetch from Defold repository:
```
https://raw.githubusercontent.com/defold/defold/refs/heads/dev/.clang-format
```
**Important**: This `.clang-format` is from the official Defold repository and ensures code style consistency with the engine.
## API reference
For C++ SDK documentation, use `defold-api-fetch` skill with C++ Native Extension APIs section (dmExtension, dmScript, dmBuffer, etc.).Related Skills
cursor-extension-integration
Integrate VS Code extensions with Cursor IDE: compatibility, Open VSX registry, VSIX installation, conflict resolution, and essential extensions. Triggers on "cursor extensions", "cursor vscode extensions", "cursor plugins", "cursor marketplace", "open vsx", "vsix install".
defold-skill-maintain
Maintains Defold agent skills. Use when asked to update link lists in api-fetch/docs-fetch/examples-fetch skills, create or update proto file references, or fetch proto schemas.
defold-shaders-editing
Creates and edits Defold shader files (.vp, .fp, .glsl). Use when asked to create, modify, or configure any Defold vertex shader, fragment shader, or GLSL include file.
defold-scripts-editing
Creates and edits Defold Lua script files (.script, .gui_script, .render_script, .editor_script) and plain Lua modules (.lua). Use when asked to create, modify, or configure any Defold script or Lua module.
defold-proto-file-editing
Creates and edits Defold resource and component files that use Protobuf Text Format (.collection, .go, .atlas, .sprite, .gui, .collisionobject, .convexshape, .label, .font, .material, .model, .mesh, .particlefx, .sound, .camera, .factory, .collectionfactory, .collectionproxy, .tilemap, .tilesource, .objectinterpolation). Use when asked to create, modify, or configure any Defold proto text format file.
defold-project-setup
Downloads Defold project dependencies into .deps/ folder. Also provides recommended game.project settings. Use FIRST before any other task when .deps/ folder is missing or empty, or after editing dependency URLs in game.project. Also use when creating a new project, configuring game.project, or asking about recommended project settings.
defold-project-build
Builds the project using the running Defold editor, returns build errors, and launches the game if build succeeds.
defold-examples-fetch
Fetches Defold code examples by topic. Use when looking for practical implementation patterns, sample code, or how to do something specific in Defold.
defold-docs-fetch
Fetches Defold manuals and documentation. Use when looking up how Defold features work, understanding concepts, components, workflows, platform setup, or needing guidance beyond API reference.
defold-assets-search
Searches the Defold Asset Store for community libraries and extensions. Use BEFORE writing custom modules for pathfinding, RNG, UI, save/load, localization, tweening, input handling, etc. Helps find, compare, and install Defold dependencies.
java-add-graalvm-native-image-support
GraalVM Native Image expert that adds native image support to Java applications, builds the project, analyzes build errors, applies fixes, and iterates until successful compilation using Oracle best practices.
upgrading-react-native
Upgrades React Native apps to newer versions by applying rn-diff-purge template diffs, updating package.json dependencies, migrating native iOS and Android configuration, resolving CocoaPods and Gradle changes, and handling breaking API updates. Use when upgrading React Native, bumping RN version, updating from RN 0.x to 0.y, or migrating Expo SDK alongside a React Native upgrade.