# World

A world owns the complete ECS runtime: entities, archetypes, queries, systems,
resources, bundles, event observers, snapshot handlers, and state.

```nupp
local world = tecs.ecs.newWorld({
    timestep = 1 / 60,
})
```

The default world supports about one million concurrent entity slots. A
configuration may raise `maxEntities` to the packed-ID limit of `2^22 - 1`.
The maximum is 4,194,303 live entities; slot zero is reserved.

## Lifecycle

`Application` creates and drives its world. After the entry plugin finishes,
it calls `startup()` once, `update(dt)` every host iteration, and `shutdown()`
at teardown.

Tests, tools, and benchmarks may drive those calls directly:

```nupp
world:startup()
world:update(1 / 60)
world:shutdown()
```

Before phase dispatch, `update` publishes pending structural work. The pipeline
then publishes after each non-empty phase, and `update` clears component dirty
bits only after the pipeline returns. The host then extracts and encodes the
completed world into a render packet.

`getFixedTiming()` returns the timestep, residual accumulator, and clamped
interpolation alpha without allocating. `fixedStepCount()` returns the number
of fixed steps since world construction. The scheduler advances those values
even when callers disable fixed phases.

## Entity IDs

Entity IDs pack a slot and generation into an opaque number:

```nupp
local old = world:spawn()
-- `old` becomes live at the next pipeline barrier.
```

Slot reuse changes the generation, so stale handles fail lookups. Do not
inspect IDs with LuaJIT bit operations; packed values may exceed 32 bits.

Use `EntityKey` for the few authored entities that runtime code must
rediscover:

```nupp
world:spawn(
    tecs.ecs.EntityKey("player"),
    tecs.ecs.Name("Player ship")
)

world:commit()
local player = world:requireKey("player")
```

Callers choose keys. Tecs owns the unique index, releases entries on removal or
despawn, and rebuilds it after snapshot load.

## Spawning entities

`spawn` accepts initial components and returns an ID immediately:

```nupp
local player = world:spawn(
    tecs.ecs.Transform2D(100, 100),
    tecs.gfx.Tint(1, 1, 1, 1),
    tecs.gfx.Renderable2D,
    tecs.ecs.Name("Player")
)
```

The ID is reserved immediately, but the entity occupies no archetype until the
next pipeline barrier. Later `set`, `remove`, or `despawn` calls in the same
transaction may use that ID and edit its final staged result.

`spawnAt` places caller-chosen packed IDs. Snapshot loading
uses them to preserve relationship targets and generations. The caller must
ensure that each chosen slot has no live entity.

## Entity clearing and storage maintenance

`clearEntities()` removes entity data, pending transactions, keys, and
entity-address observers. It preserves registered systems, queries, global
observers, bundles, and component definitions.

Use a new world when systems and queries must also disappear.
`getStats()` returns entity, archetype, component, and system counts, together
with fixed-step overload statistics.

## Structural transactions {#structural-transactions}

Structural mutations always stage. The scheduler publishes at lifecycle and
phase boundaries, so systems in one phase normally share a transaction and see
the same committed archetype membership.

A system that needs an extra boundary declares it in its configuration:

```nupp
world:addSystem({
    name = "game.ResolveDamage",
    phase = tecs.ecs.phases.Update,
    commitBefore = true,
    run = resolveDamage,
})
```

`commitBefore` publishes work from earlier systems in the same phase before
this system runs. `commitAfter` publishes this system's work before the next
system. Prefer normal phase ordering when it expresses the dependency.

`world:commit()` publishes synchronously. Finish query traversal before calling
it, because publication can change archetype storage. In systems, prefer phase
boundaries or `commitBefore` / `commitAfter` to make dependencies explicit.

`world:set` stages replacements as well as additions. Writes through `getMut`
change the committed value immediately and mark its column dirty. Query
iteration owns no transaction scope, so an early `break` is safe. The
[queries guide](/ecs/queries/index.md) covers traversal.

## Plugins and resources

A plugin configures one world. Games, engine features, and reusable mechanics
use ordinary functions for composition:

```nupp
local RATE: nupp.store.Key<number> = nupp.store.newKey("game.spinRate")

local function spinPlugin(exclusive world: tecs.ecs.World): nil
    world.resources:set(RATE, 1.5)
    -- Build queries and register systems here.
end

spinPlugin(world)
```

Callers own resource values and may replace them. Key identity and typed stores
come directly from `nupp.store`. Snapshots omit `world.resources`; register a
[snapshot handler](save-games.md#snapshot-handlers) for durable resource state.

## World subsystems

The world exposes the shared entry points for:

- [Components](/ecs/components/index.md) and [relationships](/ecs/relationships/index.md).
- [Bundles](/ecs/components/bundles.md).
- [Queries](/ecs/queries/index.md) and hierarchy traversal.
- [Systems and phases](/ecs/systems.md), and
  [plugins](/ecs/plugins.md).
- [States](/ecs/states.md).
- [Events](/ecs/events.md).
- [Snapshots](/ecs/save-games.md).

Those pages own their interaction rules; generated Nupp reference owns
individual method signatures and records.
