Defold 1.14.1
Disclaimer
This is a BETA release, and it might have issues that could potentially be disruptive for you and your team’s workflow. Use with caution. Use of source control for your projects is strongly recommended.
Access to the beta
Download the editor or bob.jar from GitHub: Release v1.14.1 - beta · defold/defold · GitHub
Breaking changes
From this version, we’ve set the OpenGLES 2 and WebGL 1 shaders as opt-in.
We do this in order to more easily push newer shader features (like vector fonts)
You can toggle the settin Exclude GLES 2.0 in the game.project` if you need to enable it again.
Beta notes:
This version contains a number of breaking changes:
Summary
- BREAKING CHANGE: (#13543) Exclude GLES 2.0 shaders by default (by Jhonnyg)
- NEW: (#13048) Add support for Draco/Meshopt compressed glTF files (by JCash, vlaaad)
- NEW: (#9934) Remove GLFW2 from mobile and web backends (by AGulev)
- NEW: (#9320,#12970) Add input source to on_input actions (by AGulev)
- NEW: (#12335) Add OpenAPI discovery for runtime debug services (by AGulev)
- NEW: (#13369) Add graphics backend selection for windows (by Jhonnyg)
- NEW: (#10039) Optimize default particlefx format (by Jhonnyg)
- NEW: (#3178) Optimize the game object transform updates (by JCash)
- NEW: (#8454) Change gain and pan for individual sound voices (by britzl)
- NEW: (#13484) Fix Android gamepad GUIDs, mappings and duplicate button presses (by JCash)
- NEW: (#13457) Send resize events after iOS orientation transitions (by AGulev)
- NEW: (#13431) Fix landscape-only games on iPhone Duo (by AGulev)
- NEW: (#11812) Add configurable iOS Home Indicator modes (by AGulev)
- NEW: (#9887) Add resource loading timings to the profiler (by JCash)
- NEW: (#13509) Add window.get_reserved_areas for iOS and Android (by AGulev)
- NEW: (#8040) Add HTML5 pixel ratio limits (by AGulev)
- NEW: (#13047) Added .ktx2 support for .gltf files (by JCash, vlaaad)
- NEW: (#13078,#11335,#9396,#7750,#7545,#7368) Switch editor Lua debugging to native DAP (by AGulev, vlaaad)
- NEW: (#10665) Support arbitrary tile source animation frames (by AGulev)
- NEW: (#8147) Scene View Axis Gizmo (by JosephFerano)
- NEW: (#13132) Optimize idle Scene View tab VRAM (by JosephFerano)
- NEW: (#13131,#9394,#9363) VRAM Optimization for Editor Code tabs (by JosephFerano)
- NEW: (#5074,#11818,#13318) Remember player window position and size (by AGulev)
- FIX: (#13005) Improved PBR support for glTF models (by JCash, vlaaad, matgis)
- FIX: (#9411) Fix stale touch movement deltas (by AGulev)
- FIX: (#10264) Fix Firefox multitouch movement deltas (by AGulev)
- FIX: (#12755,#12753) Fix HTML5 heap overflow and profiler server sleep (by AGulev)
- FIX: (#13321) Add native Lua DAP debugger to debug engines (by AGulev)
- FIX: (#13341,#10276) Use native color space for OpenGL on OSX (by Jhonnyg)
- FIX: (#13389) Fix HTML5 startup stalls and reduce loader overhead (by AGulev)
- FIX: (#13391) Added model and render optimizations (by JCash)
- FIX: (#13203) Only check framebuffer status on OpenGL when verifying graphics calls (by Jhonnyg)
- FIX: (#13416) Fix HTML5 sound exhaustion when the audio clock stalls (by AGulev)
- FIX: (#13324) Fix streamed sounds in incremental bundles (by AGulev)
- FIX: (#10320) Fix streaming reads from Live Update ZIP archives (by AGulev)
- FIX: (#12673) Sanitize HTML5 bundle directory names (by AGulev)
- FIX: (#10258) Fix Windows audio output switching (by AGulev)
- FIX: (#13421) Fix TLS 1.2 RSA-PSS handshakes and refresh CA certificates (by AGulev)
- FIX: (#11636) Fix physics scale conversion for 3D shape getters and sphere updates (by Jhonnyg)
- FIX: (#13429) Optimize sprite quad vertex generation (by JCash)
- FIX: (#10929) Mismatched skinned model with non-skinned material produces build errors (by Jhonnyg, vlaaad, matgis)
- FIX: (#13436) Fix HTML5 render target resize abort with depth/stencil attachments (by ekharkunov)
- FIX: (#13446) Reject render targets without attachments (by Jhonnyg)
- FIX: (#12748) Defer startup resize messages until the render socket exists (by Jhonnyg)
- FIX: (#13408) Avoid misleading OpenGL depth/stencil storage warnings (by Jhonnyg)
- FIX: (#13447) Fix creating runtime Vulkan render targets without color attachments (by Jhonnyg)
- FIX: (#13470) Upload the shared GUI vertex buffer once per world (by AGulev)
- FIX: (#13469) Add a render item API to dmSDK (by JCash)
- FIX: (#6272) Improved .buffer runtime format storage (by JCash, vlaaad)
- FIX: (#13473) Avoid redundant debug geometry uploads (by AGulev)
- FIX: (#11729) Strip unused Ogg Vorbis metadata during builds (by AGulev, matgis)
- FIX: (#13439) Fix Windows taskbar icon during slow startup (by AGulev)
- FIX: (#8250) Defer GUI layout notifications until initialization completes (by AGulev)
- FIX: (#13504) Fix crashes when GUI text starts with a UTF-8 continuation byte (by JCash)
- FIX: (#13501) Replace VP8 recording with native MP4 capture (by AGulev)
- FIX: (#13526) Add Metal GPU trace capture to the engine service (by JCash)
- FIX: (#13534) Reduced amount of temporary allocations when receiving a large http response (by britzl)
- FIX: (#13503) Added emoji support to fonts (by JCash)
- FIX: (#13487) Optimise Model transform storage and calculations (by JCash)
- FIX: (#13301) Fix texture creation and update deadlocks while streaming audio (by JCash)
- FIX: (#13474) Use a buffered render buffer for text entries (by Jhonnyg)
- FIX: (#13535) Add GUI custom node build callbacks to Bob (by AGulev)
- FIX: (#12167) Flip sprites around the atlas pivot (by ekharkunov)
- FIX: (#3736,#12831,#12684) Optimized resource loader scheduling with our job system (by JCash)
- FIX: (#13197) Added support for runtime vector fonts (by JCash)
- FIX: (#11688) Report missing DLL launch failures (by AGulev, vlaaad)
- FIX: (#13440) Accelerate texture processing with runtime-selected SIMD backends (by JCash)
- FIX: (#13449) Fix editor memory leak caused by deleted or externally changed files (by vlaaad)
- FIX: (#13435) Fix Outline hierarchy not remembering expanded nodes (by JosephFerano)
- FIX: (#13493) Stop tools started by the editor from showing Dock icons on macOS (by rthery)
Engine
NEW: (#13048) ‘Add support for Draco/Meshopt compressed glTF files’ by JCash, vlaaad
This adds support for reading compressed glTF files, it does not yet add compression support in the engine runtime.
NEW: (#9934) ‘Remove GLFW2 from mobile and web backends’ by AGulev
Build the Android, iOS, and HTML5 backends directly into engine/platform, using the existing Defold-maintained implementation. Remove the external GLFW2 sources and packages. Desktop platforms continue to use GLFW3.
NEW: (#9320,#12970) ‘Add input source to on_input actions’ by AGulev
Expose action.source in script and GUI input callbacks so games can distinguish physical mouse clicks from clicks simulated by touch, including the initial press.
action.source is a hash of keyboard, text, mouse, touch, gamepad, or accelerometer.
-- Bind Mouse Button Left to "click".
function init(self)
msg.post(".", "acquire_input_focus")
end
function on_input(self, action_id, action)
if action_id == hash("click") and action.pressed then
if action.source == hash("mouse") then
print("Physical mouse click")
elseif action.source == hash("touch") then
print("Click simulated by touch")
end
end
end
This fix makes changes to Info.plist. If you use a custom one for iOS, please update it by adding:
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
NEW: (#12335) ‘Add OpenAPI discovery for runtime debug services’ by AGulev
Adds GET /openapi.json to debug/headless engines so tools can discover the endpoints, parameters, request bodies, and responses supported by the engine and native extensions. The document reflects the currently registered handlers. The engine prints the full OpenAPI URL at startup, using its actual address and assigned port.
dmWebServer::AddHandler now requires an OpenAPI Paths Object as its fourth argument. The const char* JSON string is retained without copying and must remain unchanged and valid until handler removal or server destruction. A static array with a C++ raw string literal keeps the JSON readable:
static const char EXAMPLE_OPENAPI[] = R"json(
{
"/example": {
"get": {
"summary": "Get extension status",
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": { "type": "string" }
}
}
}
}
}
}
}
)json";
dmWebServer::HandlerParams handler_params;
handler_params.m_Handler = MyHandler;
handler_params.m_Userdata = context;
dmWebServer::Result result = dmWebServer::AddHandler(
server, "/example", &handler_params, EXAMPLE_OPENAPI);
NEW: (#13369) ‘Add graphics backend selection for windows’ by Jhonnyg
The windows graphics backend can now be selected via the app manifest. Supported backends are: OpenGL (default), Vulkan and DirectX12.
NEW: (#10039) ‘Optimize default particlefx format’ by Jhonnyg
Use normalized RGBA8 colors in builtin particle materials, reducing vertex sizes from 40→28 bytes and 44→32 bytes for paged atlases—a 30% and 27% reduction.
This also reduces the time spent generating particle vertices by about 94–95% in our 200k-particle benchmark (on a M1 Pro/Metal): from 40.5→2.4 ms for standard materials and 52.5→2.5 ms for paged materials. Total frame time, including the remaining simulation and rendering work, drops from 48.7→10.1 ms and 60.8→10.5 ms respectively.
NEW: (#3178) ‘Optimize the game object transform updates’ by JCash
Reduces CPU time spent updating game object transforms and animations. In the 100k-object benchmarks, transform-plus-animation time was 1.17×–3.25× faster than 1.14.0 with the matching animation-capacity fix. The 100k-bunny Metal scene improved from 1.743 to 1.495 ms/frame (1.17× faster).
Whole-frame improvements depend on the project: the hierarchy benchmarks improved 2.59×–2.72×. Bunnymark’s whole-frame median changed from 12.472 to 12.152 ms (1.03×); its trial ranges overlap, so this small gain is less conclusive.
NEW: (#8454) ‘Change gain and pan for individual sound voices’ by britzl
It is now possible to change the sound gain and pan for individual voices:
local id = sound.play("#sound")
...
sound.set_gain("#sound", 0.4, { play_id = id })
sound.set_pan("#sound", -0.5, { play_id = id })
NEW: (#13484) ‘Fix Android gamepad GUIDs, mappings and duplicate button presses’ by JCash
Android gamepads could be detected while their mapped controls were missing, incorrect. This fix aligns Android controller GUIDs and raw packets with SDL, consumes handled controller keys to prevent Android navigation fallback events, and provides automatic mappings for controllers without a database entry, such as the Bluetooth 8BitDo Ultimate 2C Wireless. Legacy gamepad bindings remain supported.
NEW: (#13457) ‘Send resize events after iOS orientation transitions’ by AGulev
Send window.WINDOW_EVENT_RESIZED after iOS orientation transitions, including 180° landscape rotations that preserve window size and safe-area insets. Native extensions can use this event to refresh reserved-region geometry when a notch or Dynamic Island moves between sides.
NEW: (#13431) ’ Fix landscape-only games on iPhone Duo’ by AGulev
Prevent landscape-only games from entering letterboxed compatibility mode on iPhone Duo by applying the game’s orientation restrictions at runtime.
Orientation is controlled as before through the Display settings in game.project:
- With Dynamic Orientation unchecked, Width and Height determine the orientation: landscape when width exceeds height, otherwise portrait.
- With Dynamic Orientation checked, the game supports both portrait and landscape.
Projects using a custom iOS Info.plist must update its orientation entries to match the new built-in template to receive this fix. Keep portrait and landscape in the UIKit orientation arrays, and move the generated game orientation list into the new key:
<key>DefoldSupportedInterfaceOrientations</key>
<array>
{{#orientation-support}}
<string>UIInterfaceOrientation{{.}}</string>
{{/orientation-support}}
</array>
Projects using the built-in plist receive this update automatically.
NEW: (#11812) ‘Add configurable iOS Home Indicator modes’ by AGulev
Adds ios.home_indicator_mode to game.project, allowing games to use a single swipe to return Home while preserving the existing two-swipe behavior by default.
NEW: (#9887) ‘Add resource loading timings to the profiler’ by JCash
Resource loading can span worker threads, dependencies, and several frames, making slow resources difficult to identify. This adds per-resource loading logs and a Show load times button in the resource profiler, with sortable Load, Preload, Read, and Create columns in milliseconds.
Enable profiling before launching the project to measure startup loads:
[resource]
profile = 1
Each completed or failed load logs its total and stage timings at INFO level. Click Capture, then Show load times to inspect retained measurements for loaded resources. An em dash indicates that no completed measurement is available.
NEW: (#13509) ‘Add window.get_reserved_areas for iOS and Android’ by AGulev
Adds window.get_reserved_areas() so games can position content around camera cutouts and the Dynamic Island. Supported on iOS 27.1+ and Android 9+; unsupported platforms return an empty table.
The API returns an array of { x, y, width, height } rectangles in window pixels, with a bottom-left origin matching window.get_size(). Query during initialization and after WINDOW_EVENT_RESIZED. Once queried, changes to reserved areas also trigger this event when the window size stays unchanged.
function init(self)
self.reserved_areas = window.get_reserved_areas()
window.set_listener(function(self, event, data)
if event == window.WINDOW_EVENT_RESIZED then
self.reserved_areas = window.get_reserved_areas()
end
end)
end
Folds, system bars, keyboards, and gesture areas are excluded. Use window.get_safe_area() when a safe layout rectangle is needed.
NEW: (#8040) ‘Add HTML5 pixel ratio limits’ by AGulev
Adds minimum and maximum pixel ratios for HTML5 rendering. Games can cap rendering resolution on dense displays or enable supersampling without changing the canvas’s displayed size.
Enable High DPI and configure the limits in game.project. This example caps rendering at 1.5 canvas pixels per CSS pixel:
[display]
high_dpi = 1
[html5]
min_pixel_ratio = 0
max_pixel_ratio = 1.5
Both limits default to 0, which disables that bound. Fractional values below 1 are supported. With High DPI disabled, the rendering ratio remains 1.
FIX: (#13005) ‘Improved PBR support for glTF models’ by JCash, vlaaad, matgis
You can now expand glTF and GLB files in the Assets view to browse their meshes, materials, and images. The editor uses the file’s defined materials and textures when previewing the model, and you can preview or copy individual meshes as Model resources.
When assigning a glTF/GLB file or selecting one of its meshes in a Model component, the editor can automatically assign the corresponding materials and textures. These generated materials use our builtin gltf.vp and gltf.fp shaders. Custom materials can still be used without this dependency.
Editor scripts can use the new editor.resource_children() function to enumerate resources contained inside files such as glTF and GLB. Previously, it was possible to do this reliably with editor.get('/', 'children') while checking if every child is a directory, but now file resources may have children too.
FIX: (#9411) ‘Fix stale touch movement deltas’ by AGulev
After a touch moves, HTML5 builds can keep reporting nonzero touch.dx and touch.dy on later frames even when the position stays unchanged. Consume each touch delta once so frames without a new event report zero movement.
FIX: (#10264) ‘Fix Firefox multitouch movement deltas’ by AGulev
Fixes touch dx/dy and screen_dx/screen_dy reporting zero when two fingers move simultaneously in Firefox HTML5 builds. Duplicate touch events previously overwrote pending movement with zero; deltas now reflect the total movement since the previous input read.
FIX: (#12755,#12753) ‘Fix HTML5 heap overflow and profiler server sleep’ by AGulev
HTML5 heap sizes of 2048–4096 MiB now convert to bytes without overflowing.
The Profiler “Server Sleep” project setting now controls Remotery’s update delay, while an explicit Remotery-specific setting retains precedence.
FIX: (#13321) ’ Add native Lua DAP debugger to debug engines’ by AGulev
Adds a native DAP server so external debugger clients can attach to Defold projects running Lua 5.1 or LuaJIT. Supports breakpoints, stepping, variable inspection, evaluation, and editing across script contexts and coroutines.
The listener is disabled by default. To enable it and wait for client configuration before running startup scripts:
dmengine --config=debugger.enabled=1 --config=debugger.port=8172 --config=debugger.wait=1
Connect a DAP client to 127.0.0.1:8172. The bind address is configurable through debugger.address.
A running project can also enable the listener through debugger.start([port [, address]]):
local port = debugger.start(0)
Passing 0 selects an available port. The call returns the listening port immediately, allowing attachment without restarting or pausing the project.
FIX: (#13341,#10276) ‘Use native color space for OpenGL on OSX’ by Jhonnyg
Explicitly set the OpenGL window’s color space to sRGB so macOS displays rendered colors consistently with Metal and Vulkan. This fixes the brighter appearance of sRGB images.
FIX: (#13389) ‘Fix HTML5 startup stalls and reduce loader overhead’ by AGulev
HTML5 startup could stall when GameArchiveLoader.MAX_CONCURRENT_XHR was configured and a single archive file contained more pieces than that limit. For example, with the default 2 MiB pieces and a concurrency limit of two, an archive file larger than 4 MiB could finish downloading but never signal completion. The default uncapped download mode was unaffected.
This change fixes completion tracking, removes duplicate archive buffers after filesystem preload, and skips WebGPU probing for WebGL-only builds.
FIX: (#13391) ‘Added model and render optimizations’ by JCash
- Reduce CPU work when rendering large numbers of models, especially repeated static models.
- Reduce duplicate custom vertex buffers for compatible instanced models.
- Reduce render-list processing costs when entries are already ordered.
FIX: (#13203) ‘Only check framebuffer status on OpenGL when verifying graphics calls’ by Jhonnyg
Gate the final framebuffer completeness check in OpenGLSetRenderTarget behind m_VerifyGraphicsCalls, avoiding potential WebGL stalls during ordinary render-target binds.
FIX: (#13416) ’ Fix HTML5 sound exhaustion when the audio clock stalls’ by AGulev
Web Audio can report running while its clock stops advancing, leaving the output queue full and preventing sound instances from completing. Detect this condition and switch to silent processing so instances can finish while audio recovery is retried.
It should prevent errors such as:
"DEFOLD:ERROR:GAMESYS: A sound could not be played since all sounds instances are used...
FIX: (#13324) ‘Fix streamed sounds in incremental bundles’ by AGulev
Fix an issue where streamed sounds could fail to load after incremental bundling, preventing games from starting or loading collections.
FIX: (#10320) ‘Fix streaming reads from Live Update ZIP archives’ by AGulev
Streamed sounds loaded from Live Update ZIP archives could receive the resource header as audio data, preventing WAV/OGG type detection. Partial reads now return the resource payload at the requested offset.
FIX: (#12673) ‘Sanitize HTML5 bundle directory names’ by AGulev
Fix HTML5 bundling failures on Windows when project titles contain invalid filename characters. For example, my: Cool&Best Project now produces the directory myCoolBestProject, while preserving the original display title.
FIX: (#10258) ‘Fix Windows audio output switching’ by AGulev
Audio now follows changes to the Windows default output device, even when the previous device remains connected. Active sounds continue on the new output, and changes made while idle take effect before the next playback.
FIX: (#13421) ‘Fix TLS 1.2 RSA-PSS handshakes and refresh CA certificates’ by AGulev
Fixes #13421.
FIX: (#11636) ‘Fix physics scale conversion for 3D shape getters and sphere updates’ by Jhonnyg
Fixed physics.get_shape() returning scaled sphere, box, and capsule dimensions in 3D. Also, physics.scale is now applied when updating sphere radii so get/set round trips remain consistent.
FIX: (#13429) ‘Optimize sprite quad vertex generation’ by JCash
Sprite rendering spends less CPU time generating vertices by preparing shared attributes once per batch and writing standard quad vertices directly. This reduces the cost of drawing large collections of sprites.
FIX: (#10929) ‘Mismatched skinned model with non-skinned material produces build errors’ by Jhonnyg, vlaaad, matgis
Mixing skinned materials with non-skinned causes crashes in runtime for certain graphics adapters (e.g Metal). Since this combination is not supported by the engine, we now produce a build error instead.
FIX: (#13436) ‘Fix HTML5 render target resize abort with depth/stencil attachments’ by ekharkunov
Fixed an HTML5 crash when resizing a render target that has a depth or depth+stencil buffer with render.set_render_target_size. This affected both render targets created with render.render_target() and .render_target resources.
FIX: (#13446) ‘Reject render targets without attachments’ by Jhonnyg
Render targets resources and runtime created render targets without any attachments are now rejected. In some cases where you might want to use a “dummy” render target resource that is modified an recreated in runtime, you will have to create at least one attachment (color or depth/stencil) that is at least 1x1 in size. This is to prevent and simplify logic around using invalid render targets in the engine.
FIX: (#12748) ‘Defer startup resize messages until the render socket exists’ by Jhonnyg
Fixes an issue where the engine posts resize messages to the render socket before the renderer exists. This currently happens when using the Vulkan graphics adapter on some platforms.
FIX: (#13408) ‘Avoid misleading OpenGL depth/stencil storage warnings’ by Jhonnyg
Fixed an incorrect warning emitted from the OpenGL adapter related to render targets with depth texture attachments. Previously, if you create a render target resource and check the “depth texture” property, this warning would always be emitted even though there are no exposed stencil parameters in the render target resource UI:
Creating a RenderTarget with different backing storage, defaulting to the depth buffer type for both.
FIX: (#13447) ‘Fix creating runtime Vulkan render targets without color attachments’ by Jhonnyg
Fixed an issue where creating dynamic render targets via render scripts that has depth attachments but no color attachments will crash the engine.
FIX: (#13470) ‘Upload the shared GUI vertex buffer once per world’ by AGulev
GUI scenes in the same world previously re-uploaded the growing shared vertex buffer after each scene. Upload the completed buffer once per frame to avoid redundant transfers when rendering multiple GUI scenes.
FIX: (#13469) ‘Add a render item API to dmSDK’ by JCash
Adds a persistent render item API for C++ rendering integrations. Engine components now reuse renderer-owned handles instead of allocating and rebuilding render-list entries every frame. Items support enable/disable, transforms, materials, batch keys, and sphere, AABB or OBB bounds.
Note
: The legacy render-list API (RenderListAlloc(), RenderListSubmit() and RenderListMakeDispatch()) is deprecated. Existing integrations continue to work, with a one-time warning from each deprecated API.
It will still work for a short period of time, until the next major release.
Usage
- Create the
HRenderItemDispatchinformation when creating the component world. - For each component/renderable item, create a new
HRenderItem - Update the render item data when the information changes
- Delete the render item/dispatch when their represented objects are destroyed
#include <dmsdk/render/render.h>
dmRender::HRenderItem item = dmRender::NewRenderItem(context, dispatch, user_data);
dmRender::SetMaterial(context, item, material);
dmRender::SetWorldTransform(context, item, world_transform);
dmRender::SetBoundingOBB(context, item, local_min, local_max);
dmRender::Enable(context, item, true);
// Each frame, between RenderListBegin() and RenderListEnd():
dmRender::SubmitRenderListDispatch(context, dispatch);
FIX: (#6272) ‘Improved .buffer runtime format storage’ by JCash, vlaaad
We’ve replaced the generic data storage to a packed runtime format that is smaller on disc and also loads faster as we can map it 1:1 at runtime.
FIX: (#13473) ‘Avoid redundant debug geometry uploads’ by AGulev
Debug geometry was uploaded before every render-list pass, including passes that did not draw it. Upload it when first needed, then reuse the buffer across subsequent passes until the geometry changes.
FIX: (#11729) ‘Strip unused Ogg Vorbis metadata during builds’ by AGulev, matgis
Ogg Vorbis files with large metadata, such as embedded cover art, can exceed the decoder’s initial header buffer and fail to play. Bob and the Editor now strip this metadata when building .oggc files, preserving the encoded audio and source assets.
FIX: (#13439) ‘Fix Windows taskbar icon during slow startup’ by AGulev
Use the executable’s icon as the taskbar fallback when slow startup blocks Windows icon requests. This prevents the generic icon from appearing with either the default icon or a custom windows.app_icon.
FIX: (#8250) ‘Defer GUI layout notifications until initialization completes’ by AGulev
GUI scripts could receive layout_changed before init() when a window resize occurred while a collection proxy was loading. Layout changes now apply immediately, while notifications before or during initialization are combined and delivered after init() succeeds.
FIX: (#13504) ‘Fix crashes when GUI text starts with a UTF-8 continuation byte’ by JCash
GUI text that starts with a stray UTF-8 continuation byte no longer triggers an array-capacity assertion or writes past the codepoint array. The converter grows the array when necessary and returns the actual number of decoded codepoints.
FIX: (#13501) ‘Replace VP8 recording with native MP4 capture’ by AGulev
Replace the VP8/IVF recorder with H.264 MP4 recording for desktop debug engines. Games can control recording through a new Lua module, while external tools can use the engine HTTP service. Supported macOS and Windows versions can also capture application audio; Linux records video only.
Start recording from a script with a writable output path:
local ok, err = recorder.start({
path = sys.get_save_file("my_game", "capture.mp4"),
fps = 30,
audio = false,
}, function(self, event, result)
if event == recorder.EVENT_STARTED then
print("Recording started")
elseif event == recorder.EVENT_STOPPED then
print("Saved:", result.path)
elseif event == recorder.EVENT_ERROR then
print(result.error)
end
end)
if not ok then print(err) end
Call recorder.stop() after EVENT_STARTED to request finalization. The file is ready when the callback receives EVENT_STOPPED. Lua audio capture defaults to false; set audio = true on supported platforms.
FIX: (#13526) ‘Add Metal GPU trace capture to the engine service’ by JCash
Debug builds on macOS can now capture Metal GPU traces through the engine service at /profiler/gputrace, without a native extension. The resulting .gputrace files can be inspected in Xcode or by using gpudebug.
For the agent
Launch the engine with the Metal graphics adapter and METAL_CAPTURE_ENABLED=1. Set ENGINE to the engine service address printed in the log and use a writable absolute path that does not already contain a trace:
ENGINE=http://127.0.0.1:8001
curl -fsS -X POST -H 'Content-Type: application/json' \
--data '{"path":"/tmp/frame.gputrace","frames":1}' \
"$ENGINE/profiler/gputrace"
curl -fsS "$ENGINE/profiler/gputrace"
POST schedules a capture; poll GET until it completes or fails. DELETE cancels a pending capture or stops an active capture after the current rendered frame. The endpoint is listed in /openapi.json only on macOS, and returns HTTP 501 when Metal capture is unavailable.
FIX: (#13534) ‘Reduced amount of temporary allocations when receiving a large http response’ by britzl
This change reduced memory usage when receiving an http response. The response buffer is sized according to the value provided in the Content-Length header. If the response has Transfer-Encoding set to chunked the Content-Length header is ignored and the response buffer will resize as more data is received. Instead of growing the response buffer in fixed increments the response buffer will now double in size each time it has to be resized. This may significantly reduce temporary allocations while receiving a large response.
FIX: (#13503) ‘Added emoji support to fonts’ by JCash
Vector fonts now render colored emojis through Slug in Labels and GUI text, including palette colors and linear/radial gradients. Color rendering is limited to Vector fonts.
To add emojis to an existing font, use Dynamic glyph generation, Vector mode and the matching built-in Vector material. Enable Use full text layout system in the App Manifest and Shader → Exclude GLES 2.0 in game.project.
Copy an emoji font (COLRv1) to fonts/NotoColorEmoji-Regular.ttf in your project. Include it in the bundle through game.project → Project → Custom Resources (append to any existing entries):
[project]
custom_resources = /fonts/NotoColorEmoji-Regular.ttf
The Lua path alone does not include the font in the bundle. Once bundled, add it to your existing font from Lua (Label example):
function init(self)
local font_resource = go.get("#label", "font")
font.add_font(font_resource, "/fonts/NotoColorEmoji-Regular.ttf")
label.set_text("#label", "Hello 😀 🍎 🚀")
end
For a GUI text node named text, use this in its .gui_script:
function init(self)
local node = gui.get_node("text")
local font_resource = gui.get_font_resource(gui.get_font(node))
font.add_font(font_resource, "/fonts/NotoColorEmoji-Regular.ttf")
gui.set_text(node, "Hello 😀 🍎 🚀")
end
Call font.add_font once per shared font resource. Ordinary text continues using the original font.
FIX: (#13487) ‘Optimise Model transform storage and calculations’ by JCash
This fix reduces the CPU transform work and memory use when rendering large model populations by reusing the matrices already prepared for each mesh. Meshes enabled after late update receive fresh transforms before rendering.
FIX: (#13301) ‘Fix texture creation and update deadlocks while streaming audio’ by JCash
Creating or updating textures from Lua no longer freezes the engine while streamed audio is playing. This covers texture updates and synchronous texture creation, including the corresponding GUI texture operations.
FIX: (#13474) ‘Use a buffered render buffer for text entries’ by Jhonnyg
Rendering text with multiple render.draw() calls in the same frame previously uploaded all accumulated text vertices on every pass. Each pass now uploads only the vertices it generated, reducing redundant GPU uploads while preserving earlier draws.
FIX: (#13535) ‘Add GUI custom node build callbacks to Bob’ by AGulev
Allow GUI extensions to migrate source formats, declare dependencies, and validate nodes after template and layout overrides are resolved. Spine-specific migration moves into the extension, so building legacy Spine GUIs requires an updated Spine plugin.
Spine extension update is needed.
FIX: (#12167) ‘Flip sprites around the atlas pivot’ by ekharkunov
sprite.set_hflip() and sprite.set_vflip() now flip a sprite around the pivot set in the atlas, the same way a negative scale.x / scale.y does. Previously, sprites with a non-centered pivot shifted position when flipped.
FIX: (#3736,#12831,#12684) ‘Optimized resource loader scheduling with our job system’ by JCash
We’ve updated our resource loader to more efficiently use a shared dependency graph together with the job system.
This simplifies the code, and keeps number of resource specific threads down to a minimum.
Native resource updates can return RESULT_PENDING during PostCreate or an ongoing recreation, including reload notifications. No update is applied in that case; retry after the operation returns.
Editor
BREAKING CHANGE: (#13543) ‘Exclude GLES 2.0 shaders by default’ by Jhonnyg
Enable Exclude GLES 2.0 in game.project files by default, skipping shader compilation for OpenGL ES 2.0 and WebGL 1.0.
BREAKING CHANGE ![]()
This means that current projects that target ES2 and WebGL1 will need to uncheck this setting (if not previously changed). ES2 / WebGL1 is now considered opt-in rather than opt-out.
NEW: (#13047) ‘Added .ktx2 support for .gltf files’ by JCash, vlaaad
Adds support for .ktx2 textures. They are often used by .gltf/.glb files.
Texture profiles control the compiled output. Either choose “Keep KTX2 Format” or select the format you wish to recompress to.
Note: Note that this may apply another lossy compression! For best result on all platforms, make sure your original .ktx2 format supports the platforms you are using/targeting.
NEW: (#13078,#11335,#9396,#7750,#7545,#7368) ‘Switch editor Lua debugging to native DAP’ by AGulev, vlaaad
Moves the editor’s Lua debugger from MobDebug to the native DAP server introduced in Add native Lua DAP debugger to debug engines by AGulev · Pull Request #13321 · defold/defold · GitHub. Debug launches install breakpoints before startup scripts run. The editor can also attach, detach, and reattach to running local and remote targets.
The variables view adds an expandable _G entry and preserves expanded tables, selection, and scroll position across stops and frame changes. Console evaluation uses the selected stack frame and displays nested table contents.
Fix Engine option to wait for a debugger connection · Issue #7368 · defold/defold · GitHub
NEW: (#10665) ’ Support arbitrary tile source animation frames’ by AGulev
Tile source animations can now use individual tiles in any order, including repeated tiles, without rearranging the source image. The new Frames property replaces Start Tile and End Tile and accepts comma-separated tile numbers and inclusive ranges in either direction, such as 1, 3-5, 8, 3 or 4-2.
The editor displays consecutive runs of at least three frames as ranges: 1, 2, 3 becomes 1-3, and 3, 2, 1 becomes 3-1. Pairs stay as 1, 2 or 2, 1; frame order and repetitions are preserved.
Editor scripts read and write frames as a Lua array of integers through editor.get(), editor.tx.set(), and editor.tx.add():
editor.transact({
editor.tx.add("/main/character.tilesource", "animations", {
id = "walk",
frames = {1, 3, 4, 5, 8, 3},
}),
})
-- Edit an existing animation node.
local frames = editor.get(animation, "frames")
table.insert(frames, 2)
editor.transact({editor.tx.set(animation, "frames", frames)})
NEW: (#8147) ‘Scene View Axis Gizmo’ by JosephFerano
NEW: (#13132) ‘Optimize idle Scene View tab VRAM’ by JosephFerano
When switching tabs, the previous one now has their GPU resources freed, which now lowers VRAM usage considerably.
NEW: (#13131,#9394,#9363) ‘VRAM Optimization for Editor Code tabs’ by JosephFerano
When switching away from a code editor tab in the editor, we now free the GPU resources to conserve VRAM.
NEW: (#5074,#11818,#13318) ‘Remember player window position and size’ by AGulev
Remember the placement of desktop player windows launched from the editor across runs and reboots. Each project and player instance keeps its own placement. Reset Resolution clears saved sizes while preserving positions.
FIX: (#13197) ‘Added support for runtime vector fonts’ by JCash
This feature allows us to render text with sharp features, by utilizing vector graphics.
Another benefit is that It also uses less texture resources.
The vector algorithm chosen was Slug.
Along with this feature, we also made the available settings for fonts much more dynamic, allowing for better developer control.
Outline/Shadow Bitmap Size
Since the vector graphics doesn’t lend itself to performant rendering of outlines or shadows, we’re still using bitmap rasterization (SDF) for these features. it affects the texture memory being used.
This also affects shadows, which are now a rasterized gaussian blur which makes it much smoother than before.
The font property name is Outline/Shadow Bitmap Size
- Vector fonts:
- The size of the bitmaps are taken from the
.fontin this case - If no outline/shadow is configured, the
Outline/Shadow Bitmap Sizeproperty of the .font is read-only (default 15)
- The size of the bitmaps are taken from the
- SDF Font:
- The size is used as before, to generate the SDF bitmaps
- Bitmap fonts, the font size property is read-only, as it is inferred from the
.fntfile.
Mode
SDF- Select this for the old sdf rendering pipeline. Useslabel-df.materialVector- Uses the vector graphics rendering. Useslabel-vector.material
Glyph generation
-
Staticgeneration means that all the glyphs are generated during the build of the game. TheCharactersfield of the .font files is used to populate the textures. The source.ttf/.otfwon’t be bundled with the game. -
Dynamicgeneration means that the glyphs are generated at runtime. When loading such a font, it uses thePrewarm textproperty to do text shaping in order to load the correct glyphs. The source.ttf/.otf will be bundled with the game.
Migration
The idea is that it should not affect existing project, they’ll still use the SDF rendering if that’s what they’ve chosen.
If you create new .font files though, they’ll default to the Vector rendering.
Switching between the two modes is only a few steps:
- Select
Mode→Vector - Select
Glyph generation→Dynamic
Feature Support
This implementation uses shader features that are not available for WebGL1 or GLES 2.
The feature requires texture formats RGBA16F and R32UI. There is no automatic SDF fallback for unsupported devices.
FIX: (#11688) ’ Report missing DLL launch failures’ by AGulev, vlaaad
The editor now reports non-zero engine exits in the console. On Windows, missing-DLL failures trigger one diagnostic relaunch so the system dialog identifies the missing DLL.
FIX: (#13440) ‘Accelerate texture processing with runtime-selected SIMD backends’ by JCash
Bob builds texture-heavy projects faster with CPU-specific SIMD optimizations for image processing. In a single-threaded benchmark containing twenty 8K×8K and forty 1K×1K textures, texture-build time fell by 25% (35.86 s → 26.96 s), and the complete content build took 22% less time (39.40 s → 30.66 s). Gains depend on texture formats, sizes, and compression settings.
FIX: (#13449) ‘Fix editor memory leak caused by deleted or externally changed files’ by vlaaad
Previously, the editor always kept some internal metadata about deleted files and files that were changed externally and then reloaded in the editor. On large projects, reloading some highly referenced resources could add up to 20MiB of metadata per reload. Now, the editor no longer retains that metadata.
FIX: (#13435) ‘Fix Outline hierarchy not remembering expanded nodes’ by JosephFerano
We now persist the state when switching tabs
FIX: (#13493) ‘Stop tools started by the editor from showing Dock icons on macOS’ by rthery
On macOS, opening a project in the editor no longer flashes a Defold icon in the Dock for every glTF model. Tools that the build pipeline starts, such as the glTF validator, now run in the background without a Dock icon.