Add composition.get_container(entity) -> table or nil. Returns the
container block from the entity's template (e.g. {kind="list"}), or
nil if the template declared no container block. Loud-Error if the
entity was not created by composition.
The internal storage (tpl.container) was already present since v0.2.0
(stashed on the template record with a comment "B.2 reads this") but
had no public getter. This fills the oversight without any semantic
change to v0.2.0.
lib-core.composition
Template + Instantiation + Tag-Index over engine.entity. Templates define
property defaults; create spawns an engine.entity with template
defaults + per-instance overrides; entities are indexed by template-id
and tag for cheap reverse-lookup.
Version: 0.2.0
Lib-ID: lib-core.composition
Requires: (none — uses engine entity.*, domain.contribute only)
Tags: composition, entity, template, tag-index
Topology
graph LR
this["lib-core.composition"]
engine["engine.*"]
this --> engine
Scope (v0.2.0)
Template-Only-Subset + set_tag + container declaration.
Supported:
define_template{id, properties, tags}define_template{..., container={kind="list"}}— v0.2:kind="list"acceptedcreate{template, properties}list_by_template(id),list_by_tag(tag)destroy(entity)set_tag(entity, tag, present)— v0.2: runtime tag add/removeget_container(entity)— v0.2: read back the container block from entity's template
Deferred (Loud-Error if attempted):
slotsblock → Phase D trigger (Composite Items with Sub-Items)containerconstraint fields (weight_max,volume_max,grid,accepts_fluid,accepts_gas,restrictions) → Phase F/G triggerquality,condition→ Phase J trigger (Damage / Wear)parent:template-inheritance → no consumer yet
API
composition.define_template(def)
Syntax: composition.define_template({id: string, properties?: table, tags?: array}) -> void
Example:
composition.define_template{
id = "sign",
properties = {
sprite_path = "sprites/sign.png",
text = "default sign text",
position = {x = 0, y = 0}, -- auto-flattened to position.x + position.y
},
tags = {"renderable"},
}
Description: Registers a template under id. All properties are
auto-declared as inert via domain.contribute with type inferred
from the default-value. Nested tables in properties are flattened
to dotted scalar keys (e.g. position = {x, y} → declares position.x
and position.y as separate number properties). Tag-list registers
the template in the tag-index used by list_by_tag.
The optional container block declares this template as an item container.
Only kind = "list" is supported in v0.2. Any constraint field
(weight_max, volume_max, grid, accepts_fluid, accepts_gas,
restrictions) loud-errors at template-load time (Capability-by-Declaration:
no constraint is silently ignored).
Example with container:
composition.define_template{
id = "backpack",
properties = {
sprite_atlas = "sprites/items.png",
sprite_uv = "0 0 32 32",
position = {x = 0, y = 0},
},
tags = {"renderable"},
container = { kind = "list" },
}
Loud error(...) on: missing/non-string id, duplicate id,
non-table properties, malformed tags, attempted slots /
quality / condition / parent: block (each pointing to its
re-entry phase); container.kind other than "list"; any
unimplemented constraint field in container.
composition.create(spec)
Syntax: composition.create({template: string, properties?: table}) -> entity
Example:
local sign = composition.create{
template = "sign",
properties = {
position = {x = 144, y = 200},
text = "Hier steht: Willkommen im Spine.",
},
}
Description: Spawns an engine.entity, applies template-defaults
shallow-overridden by per-instance properties. Nested-table
overrides (like position = {x, y}) are flattened the same way as in
define_template. Per-instance properties that weren't declared by
the template get declared on-the-fly as inert. Entity is registered
in the template-index + tag-index of the template. Returns the
engine.entity handle.
Loud error(...) on: non-table spec, missing/unknown template,
non-table properties.
composition.list_by_template(id)
Syntax: composition.list_by_template(id: string) -> {entity, ...}
Example:
for _, sign in ipairs(composition.list_by_template("sign")) do
engine.print(sign:get_property("text"))
end
Description: Returns a shallow-copied list of all currently-alive entities created with the given template-id. Empty list if template is unknown or has no instances.
composition.list_by_tag(tag)
Syntax: composition.list_by_tag(tag: string) -> {entity, ...}
Example:
for _, e in ipairs(composition.list_by_tag("renderable")) do
local x = e:get_property("position.x")
local y = e:get_property("position.y")
-- ... render
end
Description: Returns all currently-alive entities whose template
declared tag in its tags array. Used by lib-core.render
draw_entities{tag="..."} (see A.2). Empty list if tag has no entities.
composition.set_tag(entity, tag, present)
Syntax: composition.set_tag(entity, tag: string, present: boolean) -> void
Example:
-- Remove from renderable index (e.g. item picked up into inventory)
composition.set_tag(item_entity, "renderable", false)
-- Restore renderable index (e.g. item dropped back into world)
composition.set_tag(item_entity, "renderable", true)
Description: Adds or removes entity from the tag-index for tag.
present=true inserts the entity (idempotent — calling again with the
same tag is a no-op). present=false removes it (idempotent — calling
again when already absent is a no-op). Both entity_meta and
index_by_tag are updated atomically. Loud-Error if entity was not
created by composition (e.g. a raw entity.create() handle). Used by
lib-core.inventory add/remove to flip the "renderable" tag
when items move between world and inventory.
composition.destroy(entity)
Syntax: composition.destroy(entity) -> void
Description: Removes entity from template-index + tag-index +
destroys via engine.entity.destroy. Idempotent. If entity wasn't
composition-created, falls through to entity.destroy.
composition.get_container(entity)
Syntax: composition.get_container(entity) -> table or nil
Description: Returns the container block from the entity's template
(e.g. {kind="list"}), or nil if the template declared no container
block. Loud-Error if entity was not created by composition. Used by
lib-core.inventory-list to validate container entities at runtime.
composition.list_templates()
Syntax: composition.list_templates() -> {id, ...}
Description: Debug/introspection — returns set of declared template-ids.
Conventions
- Property-Value-Types: number, string, boolean (engine §PROPERTY_*
catalog). Tables are flattened to dotted scalar keys; arrays inside
properties→ loud error. - Position-Format: stored as two scalar properties
position.xandposition.y(per Phase-A Spec §5 A-Q5 revision 2026-06-09 — engine has no PROPERTY_TABLE). - Tag-Index: maintained in lib, not in engine. Tag-lookup is O(1) by tag, list iteration is O(n) per tag.
composition.reg_id: internal book-keeping property on each created entity; used bydestroyto find the meta-record. Do not set or read manually.
Future Phases
| Phase | Triggers in Template | Spec |
|---|---|---|
| B (Items) | container={kind="list"} — accepted in v0.2; constraint fields deferred to F/G |
inventory-model.md |
| D (Composites) | slots = {...} |
composition-model.md (full Slot-System) |
| F/G (Constraints) | weight_max, volume_max, grid, accepts_fluid, accepts_gas, restrictions |
constraint-model.md |
| J (Damage/Wear) | quality, condition |
damage-model.md |