This repository is a Defold library (physics_tools) that provides editor scripts and native Zig tools for generating physics shapes from 2D images. It includes an example project demonstrating library usage. The project root is the folder containing game.project.
- Root config:
game.project - Library source:
physics_tools/— the distributable library (included viainclude_dirsingame.project)editor_scripts/— Defold editor scripts (.editor_script) and Python scripts (.py)plugins/bin/— prebuilt native Zig binaries per platform
- Native tools:
native/— Zig source for physics shape generation tools (main implementation)src/— Zig source files (gen_convexshape.zig,gen_silhouette_chain.zig,geometry.zig,image_loader.zig,format.zig)build.zig— build system (cross-compiles to all platforms, installs tophysics_tools/plugins/bin/)test_assets/— test images for verification
- Old Python scripts:
python_old/— legacy Python implementation, kept as reference only. Do NOT use for new development. - Example project:
example/— a demo project that uses the librarymain.collection— bootstrap collectionmain.script— example entry scriptassets/— example assets (images, fonts, app icons)modules/— example helper modules
- Custom skills:
.agents/skills/
Key Defold settings from game.project:
- Bootstrap collection:
/example/main.collection - Library include dirs:
physics_tools
- Library code (
physics_tools/) is the primary product of this repo. Changes here affect all consumers of the library. - Example code (
example/) exists only to demonstrate and test the library. It is NOT shipped as part of the library.
- The
physics_toolsfolder is the library's include directory (set ingame.project [library] include_dirs). - NEVER modify any files inside
.deps/— these are downloaded dependencies provided strictly as read-only context.
- Lua scripts:
.lua,.script,.gui_script,.render_script,.editor_script. - Metadata assets (Protocol Buffer Text Format):
.collection,.go,.sprite,.tilemap,.tilesource,.atlas,.font,.particlefx,.sound,.label,.gui,.model,.mesh,.material,.collisionobject,.texture_profiles,.display_profiles. - Manifests (YAML):
.appmanifest,.manifest- platform-specific libraries and build flags. - Buffers (JSON):
.buffer- streams of data (positions, colors, etc.) used as input for Mesh components. - Shaders (GLSL):
.vp,.fp,.glsl. - Project config (INI):
game.project. - Properties (INI):
game.properties,ext.properties- parameters available ingame.project. - 2D assets:
.png,.jpg. - 3D assets (GTLF):
.gltf,.glb. - Sound assets:
.ogg,.wav,.opus(OPUS requires modification of the appmanifest).
When creating or editing Defold asset files, use the corresponding defold-*-editing skill to get the correct file format and structure. Always load the skill before writing or modifying the file.
- Write for Python 3.11. Do NOT write code to support earlier versions.
- Use full type annotations, generics, and other modern practices.
- Only
pillow(PIL) is an allowed external dependency. Keep dependencies minimal. - Scripts must be runnable both from Defold editor scripts and from the command line.
- Indentation: 1 tab (4 spaces).
- Naming:
snake_casefor variables, functions, files, and folders. Keep resource paths absolute (/assets/...) where Defold expects them. - Comments:
- Use LuaCATS (
---@...) annotations for types, module/public API docs.
- Use LuaCATS (
- Whitespace:
- Empty lines must be truly empty (no spaces/tabs).
- Avoid trailing whitespace.
- Defold API: strictly follow the Defold API - always verify against the official documentation using the
defold-api-fetchskill. There are no hidden or undocumented APIs - only use functions, messages, and properties that are explicitly described in the docs. For conceptual guidance on how Defold features work (components, physics, rendering, input, etc.), use thedefold-docs-fetchskill. - Defensive checks: Do NOT assume data is missing or constantly re-check field existence in tables. If YOU set a field, it EXISTS. Similarly, do NOT check for standard Lua API availability (e.g.,
ioandio.openalways exist in standard Lua). Avoid unnecessary defensive programming. - Paradigm: do not use metatables or imitate classes. Use functional, data-based structures only.
- Logging: use
print()to look at the game state. Add logs for transactions, initializations, important events. - Script instance state: In
.script,.gui_script,.render_scriptfiles, store instance-specific state in theselftable, NOT in local module variables. Local variables at the module level are shared across ALL instances of the script, which causes bugs when multiple instances exist. Useself.my_variableinstead oflocal my_variable. Not applicable for local functions - keep them local. If you need to call local function that it's defined below, to use forward declarations or reorganize the functions. - Local functions: NEVER create local functions inside other functions. Local functions are only allowed at module scope. Anonymous lambda functions (inline callbacks) are acceptable.
- require:
- Always call
requirewith parentheses:require("module"), NOTrequire "module". - Use dot notation for module paths:
require("physics_tools.some_module"), NOTrequire("/physics_tools/some_module"). - Module paths are relative to the project root and use dots (
.) instead of slashes (/) as separators. - Do NOT use leading slashes in require paths.
- Always call
- Hash values:
hash("...")can be left inline without premature optimization. It's acceptable to usemessage_id == hash("trigger_response")directly. If you need to reuse a hash value multiple times, you can declare it as a module-level constant inUPPER_CASEformat:local TRIGGER_RESPONSE = hash("trigger_response"). - Constants: Module-level constants can be declared as local variables in
UPPER_CASEformat:local TRIGGER_RESPONSE = hash("trigger_response"),local MAX_HEALTH = 100. - msg.url format: Always remember the format
[socket:][path][#fragment]:socket- collection name (world)path- game object instance id (can be relative or global)fragment- component id- Shorthands:
"."for current game object,"#"for current component - Examples:
msg.url("#my_component"),msg.url("collection:/path/to/go#component"),msg.url(socket, path, fragment),msg.url(nil, hash("id"), hash("script")),msg.url(nil, go.get_id("physics"), "collisionobject")
- Windows: use PowerShell.
- Linux: use bash.
- macOS: use zsh.
All commands run from the project root (the folder with game.project).
- Build & Run via editor - use the
defold-project-buildskill. Requires the Defold editor to be running with the project open. Builds the project, returns compilation errors, and launches the game if the build succeeds.
- Build via the running editor succeeds (
defold-project-buildskill).
- Git commit messages: use the following format:
Short descriptionin English language ONLY. - Contributing guidelines: All scripts must be written in Python or native platform shell (bash, PowerShell) — no additional software dependencies beyond Python + Pillow.