Matter v0.9.0-beta.0
Pre-releaseWe’re excited to announce the beta release of Matter v0.9.0-beta.0! This release introduces powerful new features, significant performance improvements, and some breaking changes to pave the way for a smoother developer experience and a more robust system overall. We’ve also deprecated old functionality, giving you time to transition your code before these features are fully removed in future versions.
This beta release is designed for testing in real-world projects. Your feedback is critical to ensuring the stability and usability of these changes before the final release. Be sure to read the migration guide below for detailed instructions on updating your code.
What is a beta release?
Beta releases allow developers to try out new features and changes before they’re finalized. v0.9.0-beta.0 is a pre-release version, meaning it includes features, including breaking changes, for the next update but may still have bugs or edge cases that need refinement.
To use this beta release, you’ll need to explicitly specify the beta version in your project’s dependencies (e.g., Matter = "matter-ecs/matter@0.9.0-beta.0"
). This ensures that your v0.8 and earlier projects don’t unintentionally pick up experimental changes.
Why use the beta?
- Access new features and performance improvements early.
- Help identify bugs or issues in your specific workflows.
- Influence the final version by providing feedback.
Your feedback directly shapes the quality of the final release. Please report any bugs or concerns you encounter while using the beta.
Highlights of this release
Added
- A new
Loop:setWorlds({ World })
method which simplifies managing worlds in theLoop
. - A new deferred command mode for the registry which prevents iterator invalidation and optimizes command handling. This is now the default for
Loop
. - Debugger enhancements:
- Nested worlds within
Loop
are now fully supported. - Systems can be sorted by run time for better performance profiling.
- Nested worlds within
Changed
- A breaking change: the
Loop
now requires a call tosetWorlds
before it can be used. TheDebugger
inherits this requirement. - Significant Performance Improvements:
- Queries now run 7.5-15x faster thanks to a reworked storage layout.
- Archetypes are now more cache-friendly.
- System names in
Loop
are now cached, reducing overhead fromdebug.info
.
Deprecated
World:remove()
return values no longer reliably indicate component removal status.World:optimizeQueries()
has been deprecated as it no longer serves a purpose thanks to new storage changes.
Fixed
- Resolved an issue where archetypes were skipped in queries.
- Fixed
World:queryChanged
incorrectly omitting entities.
For more details, view the full changelog, or check out our documentation.
Migrating
Update your Loop
initialization
Loop
now requires a setWorlds({ World })
call before use. Update your setup code as follows:
Before:
local world = World.new()
local debugger = Debugger.new(Plasma)
local loop = Loop.new(world)
-- World is naively inferred from the loop parameter.
debugger:autoInitialize(loop)
loop:begin({
default = RunService.Heartbeat,
})
After:
local world = World.new()
local debugger = Debugger.new(Plasma)
local loop = Loop.new(world)
-- World is explicitly set.
loop:setWorlds({ world })
debugger:autoInitialize(loop)
loop:begin({
default = RunService.Heartbeat,
})
See the docs for more information.
Review deprecated methods
- Replace any reliance on the return value of
World:remove()
.- If the return value is necessary you can call
World:get()
immediately beforeWorld:remove()
, but keep in mind that this can still be misleading with command buffering (be sure to understand carefully how buffering affects what is currently in the world and what will change later).
- If the return value is necessary you can call
- Potentially remove calls to
World:optimizeQueries()
.- This can be done at a later time since it's now a no-op.
Prepare for deferred command mode
The registry now defaults to deferred command mode. This change is usually seamless but ensure your workflows don’t rely on immediate command execution.
The command buffering fundamentally changes how your actions interact with the underlying world data structure. This can result in different or unexpected behavior, particularly for edge cases involving entity lifecycle management, deferred commands, and query assumptions.
Why this change affects queries
The new deferred mode may:
- Change the order in which entities are returned by queries.
- Modify the visibility of entities in queries.
- Surface subtle bugs in query logic that relied on undocumented or implicit behaviors.
For example, queries that previously assumed a consistent order across iterations or relied on immediate execution of commands (e.g., insert
, remove
) may exhibit unexpected results.
Example: Deferred command mode batches modifications to entities and flushes them between systems. This means entities created or modified during a system may not appear in queries until the next system call.
Before:
world:insert(entity, ComponentA)
for entity in world:query(ComponentA) do
print(entity) -- Entity with ComponentA appears immediately
end
After:
world:insert(entity, ComponentA)
for entity in world:query(ComponentA) do
print(entity) -- The entity won't appear yet
end
Solution: Adjust your expectations or use deferred-safe workflows. For example, if immediate visibility is required, flush the command buffer explicitly with world:commitCommands()
. Alternatively, move the behavior to a system that runs after
your current system (this is preferred for new systems, but may be cumbersome for existing systems).
world:insert(entity, ComponentA)
world:commitCommands()
for entity in world:query(ComponentA) do
print(entity) -- Entity with ComponentA appears immediately again
end
Tips for testing systems and queries
With the new storage layout, archetype improvements, and command buffering your queries may exhibit different performance characteristics. Test critical code paths to verify and maximize performance gains.
- Validate Query Results: After updating, confirm that all queries return the expected results. Pay special attention to cases involving entity creation, deletion, or modification within the same frame.
- Check Deferred Command Dependencies: If your systems depend on immediate execution, use
world:commitCommands()
to apply changes early, but sparingly, to maintain performance. - Profile Your Queries: Use the new runtime sorting feature in the Debugger to identify bottlenecks and ensure your queries are optimized for the new layout.
- Iterate on Small Datasets: Start with a reduced set of entities and components to verify correctness before scaling up.
- Handle Query Order Explicitly: Avoid assumptions about the natural order of query results. Use sorting or explicit filtering if order is critical.
How to provide feedback
Your input is invaluable to the final release of v0.9.0. Here’s how you can contribute:
- Report Bugs: Submit issues with detailed reproduction steps.
- Share Feedback: Tell us what you like and what could be improved.
- Test Use Cases: Try integrating the beta into your projects and let us know about any pain points.
- Get Involved: We welcome new contributors. Check our contribution guide or come talk to us.
Join the conversation in our GitHub issues or reach out through our discord server.
We can’t wait to hear your thoughts and see what you build with v0.9.0-beta.0!