---
title: "population"
description: "A hardware-instanced population at rest: one mesh drawn at every transform of a baked placement, as ONE draw call per variant at any instance count."
section: "Types"
slug: "types-population"
canonical: "https://origozero.ai/docs/types-population"
updated: "2026-10-10T16:24:25.550508684+00:00"
tags: ["asset-type", "reference"]
---

# population

The asset is the recipe — which `.mesh` and material each variant draws with,
plus the instance matrices as bytes. Its `instantiate` method is what turns
that recipe back into a live draw, so a scene records ONE entity for a
population of a million instances instead of a million entities.

## Layout

```
<name>.population/
  population.json  { version, total, variants: [ { mesh, material | materialKey, count, offset } ] }
  transforms.bin   total × 64 B — little-endian f32, column-major mat4 per instance
```

`offset` counts INSTANCES, not bytes: variant *k*'s matrices start at
`offset × 64` bytes of `transforms.bin` and run for `count × 64`. Each matrix
is column-major, which puts its translation at floats 13/14/15 of the block —
the layout the engine reads a transform buffer as `array<mat4x4<f32>>`. The
matrices are taken in the space of the entity drawing the population, so it
draws where the recipe placed it relative to that entity and moves with it.

`mesh` and `material` are asset references (`{ "__ref": "<guid>" }`), so the
geometry and material a population draws travel with it in the dependency
graph. A variant drawing with a material the renderer's registry holds but no
asset backs names it in `materialKey` instead.

## Putting one in a scene

```lua
local pop = asset.resolve("forest", "population")
pop:instantiate(nil, { position = { 0, 0, 0 } })     -- one entity, one draw call
```

That spawns an entity carrying the `Population` component, which owns the live
GPU buffers and draw registrations for as long as the entity lives — a reload
replaces them rather than stacking a second set. The same contract is what
`Asset { source = <population> }` drives, which is how a baked procgen bundle
carries a population: a root record plus one child holding the reference.

## Building one

`proc`'s `population.write` sink persists a `Population` value:

```lua
local pop = proc.registry.get("instances.draw").eval({}, { instances = iset }, {}).population
proc.registry.get("population.write").eval({}, { population = pop }, { name = "forest" })
```

Or through `asset.create` directly, with each variant's matrices as a flat
`count × 16` column-major float array:

```lua
asset.create("population", "forest", {
    variants = { { mesh = meshGuid, material = materialGuid, transforms = flat } },
})
```

## Reading and drawing one by hand

```lua
local recipe = pop:spec()        -- { version, total, variants }
local live   = pop:draw()        -- allocate buffers + register draws
print(live:count(), live:drawCalls())
live:destroy()                   -- drop the registrations, free the buffers
```

The value `:draw()` returns OWNS those resources. Hold it and release it —
a registration nobody holds can be neither enumerated nor dropped afterwards.

## In the Inspector

Selecting a population opens its **Population** section: how many instances it places, across how many variants, and a table of each variant's mesh, material, instance count and offset, with a link to each variant's mesh.
