# kit
The vale's surfaces and its ground — the two things every other `vale`
submodule needs.
## Exports
- `kit.mintMaterials()` — mints the fourteen vale materials (ragstone,
limestone, lichen, slate, iron, brass, yew, bark, turf, gravel, water, void,
distance, rook) from `film.PAL`. Idempotent.
- `kit.id(name)` — the dotted identity of one of them, which is how a `Model`
wears it. `kit.has(name)` asks whether it has been minted yet.
- `kit.ground(x, z)` — **the** height function. The terrain mesh, the path, the
monuments and the yews all sample this one function, so nothing in the vale
floats or sinks. Banks rise quadratically either side of the avenue, the
floor lifts toward the lodge gate, and there is a crest behind the chapel as
well as the far one at 900 m.
- `kit.pathY(z)`, `kit.gutterY(z, t)` — the metalled avenue and the water
standing in its gutter.
- `kit.qAxis`, `kit.qYaw`, `kit.qMul` — an entity's `rotation` is a quaternion
table; these are the three constructors the vale needs.
## Anchors it honours
`kit.ground(0, 0)` is 0 (`film.PLACES.chapelDoor`) and `kit.ground(0, 96)` is
1.2 (`film.PLACES.lodgeGate`) exactly — the far shoulder and ridge terms are
held off the vale floor so those two stay true.
# geom
The mesh lathe the `vale` slice of *Sexton's Bell* is built with. A builder
accumulates one triangle stream — positions, normals, uvs, indices — under a
transform stack, and mints it as a `.mesh` asset.
One merged mesh per material is the unit of geometry here: four hundred
monuments become three draws rather than four hundred entities.
## Exports
- `geom.builder()` — a fresh builder.
- `geom.trs(tx, ty, tz, yaw, pitch, roll, sx, sy, sz)` / `geom.compose(a, b)` —
transforms; `b:push(m)` / `b:pop()` / `b:at(...)` stack them.
- `geom.ring(n, r, rot)` — a regular n-gon in the XZ plane, for lofts.
On a builder: `vert`, `face`, `tri`, `quad`, `box`, `pier`, `polyFan`,
`extrudeZ`, `extrudeY`, `loft`, `grid`, `tris`, `mint`.
## Conventions
- Emitters are **flat-shaded** by default: every face owns its vertices, which
is what dressed stone wants. `loft` takes `smooth = true` (the yews, the
urns, the ridge treeline) and `grid` is always smooth.
- A face's front is the side its three vertices turn counter-clockwise as seen
from. `quad`/`tri`/`box` derive the normal from the winding they are given,
so those two can never disagree; `polyFan`, `loft(smooth)`, `grid` and the
`extrudeY` caps write normals of their own, so their winding is chosen from
the outline's signed area rather than assumed.
- `extrudeZ` and `polyFan` take an outline wound either way and still come out
facing outward.
- `mint(identity, name, folder, force)` asks `asset.exists` rather than
resolving a handle from a computed name, so a mesh identity built by
concatenation never becomes an unpublishable reference on the content that
wears it.
# stones
Four hundred monuments in the field either side of the avenue: headstones
(round-headed, gothic, shouldered and plain, each with a sunk panel so a
raking flash finds an edge), chest tombs, obelisks, wheel crosses, pedestal
urns and railed enclosures — plus one weeping angel bowed over a pedestal on
the avenue's west side, and the chest tomb shot 3's dolly passes, placed
rather than scattered so the sheet of water off its lid has something to come
off.
The film's whole contrast structure is bone limestone against wet ragstone, so
the field is deliberately mixed: forty-six per cent limestone, eleven per cent
lichen-stained, the rest ragstone. A stroke raking across it lights the
dressings and leaves the ragstone where it was.
## Exports
- `stones.plan()` — the field as a deterministic list of placements, from
`film.rand` alone.
- `stones.mint(force)` / `stones.spawn(parent)`
- `stones.ANGEL`, `stones.TOMB` — the two placed monuments, for anything that
needs to find them.
## Notes
Everything merges into four meshes by material plus the angel's own, so the
field is five draws. Placement keeps the path corridor and the chapel platform
clear, thins outward from the avenue, and leans about one stone in six.
# chapel
The ragstone mortuary chapel and its 34 m broach spire — the exterior only;
the waiting mortuary's interior belongs to the `vigil` slice.
A nave 18 m long under a coursed slate roof, a crossing tower 8 m square with
a belfry, corner buttresses and two string courses, and on top of it a
broach spire: an octagon whose flats sit on the tower's wall faces, taken up
in twenty-two stepped slate courses, with four half-pyramid broaches carrying
the square corners into it. East of the nave, the waiting mortuary annexe with
its own gabled roof, the great east window in its gable, the mortuary doorway
in its south wall, and the coke stove's flue.
Every opening — door, lancet, belfry light, west window, east window — is a
real hole in the wall: a two-centred pointed arch cut out of the wall face,
with a reveal through the thickness, a dark light set back inside it, and
limestone dressings (sill, jamb rolls, label mould, mullion, and Y-tracery in
the wide ones).
## Exports
- `chapel.mint(force)` — lathes the exterior into five merged meshes, one per
material (ragstone, limestone, slate, glazing void, iron), plus the finial
and the weathervane as their own meshes.
- `chapel.spawn(parent)` — spawns `ChapelRoot` and its five parts,
`SpireFinial` at `film.PLACES.spireTip` (0, 34, -9) where stroke 12 lands,
and `SpireVane` on top of it.
## Notes
- The finial and the vane are minted separately because they are the only
parts of the chapel that move, and because the strike takes them.
- Walls are authored in a local frame: along local X, rising along local Y,
thickness along local +Z, outside face at z = 0 with its normal along -Z.
yaw `pi` faces world +Z, `0` faces -Z, `pi/2` faces +X, `-pi/2` faces -X.
# film
The shared clock, the storm and the slice registry for Sexton's Bell —
the 95-second, 14-shot demo in this world. Every build slice requires this
module; it is the only place the film's time, weather, palette and storm
table are written down.
## Exports
- `film.FPS` / `film.DT` / `film.DURATION` / `film.FRAMES` — 24, 1/24, 95.0, 2280.
- `film.now()` / `film.frame()` / `film.isPlaying()` — where the film is.
- `film.seekTo(t)` / `film.seekToFrame(n)` / `film.reset()` / `film.play()` /
`film.pause()` / `film.run()` / `film.step()` — the transport. `step()` is
called once per rendered frame by the `FilmDirector` component and by
nothing else.
- `film.register(slice)` / `film.buildAll()` / `film.built(name)` /
`film.missing()` / `film.slices()` — the registry.
- `film.SHOTS` / `film.shotAt(t)` — the fourteen shots and their boundaries.
- `film.STROKES` / `film.strobe(t)` / `film.thunderAt(i)` / `film.gap(i)` /
`film.strokeAt(t)` — the storm. `strobe(t)` is the single lightning
envelope everything reads; nobody writes their own.
- `film.rain(t)` / `film.wind(t)` / `film.windDir(t)` / `film.wetness(t)` /
`film.gas(t)` / `film.lantern(t)` — the shared weather and practical ramps.
- `film.rand(seed, i)` / `film.noise(seed, x)` — the only randomness a slice
may use.
- `film.PAL` / `film.NAMES` / `film.PLACES` — palette, shared entity names,
world anchors.
## Usage
```luau
local film = require("demo.film")
local function update(t)
local level, stroke = film.strobe(t)
-- ... a pure function of t, and of nothing else
end
```
## Notes
- Every slice's `update(t)` is a pure function of absolute film time. No
accumulation, no `dt`, no `math.random`, no wall clock. That purity is what
makes `seekTo(t)` reproduce a frame exactly, which is what lets the film be
recorded twice for the same result.
- Guard a slice's `build()` on its sentinel entity being alive, never on a
module-local flag: module state survives an edit/play flip and entities do
not.
- The full design is `/zero/source/design/spec.md`.
# land
The chalk vale itself.
The ground — a fine grid down the avenue corridor for shot 13's 0.30 m
station, two coarser flanks, and a far field carrying the shoulder at 430 m
and both ridge crests. The metalled avenue with its dressed kerb stones laid
one at a time, and the gutter shot 2 lies in. Standing water: fifty-six pools
whose rims ride the ground they lie on, and the sheet at the foot of the
chapel steps. The avenue railing shot 3 dollies along. The lodge gate at 96 m.
The treeline on both crests.
## Exports
- `land.mint(force)` / `land.spawn(parent)`
- `land.update(t)` — a pure function of film time: the flood rises with
`film.wetness`, and the near gate leaf works on its hinge on `film.wind`.
- `land.gutterFloor(z)`, `land.POOLS`, `land.GATE_Z`
## What moves
`Vale_Gutter` lifts as the vale floods; `LodgeGateL` swings through about
sixteen degrees at full wind while `LodgeGateR` barely stirs against its
catch.
# flora
The avenue of Irish yews, and the rook that lifts off an obelisk in shot 3.
Thirty fastigiate yews, fifteen a side, on 5.9 m centres from z = 9 to z = 92.
Each is two entities on one pivot: the lower half bends at the base and the
crown whips on top of it. Both come out of a single pure function of film
time, so the avenue thrashes at 24 m/s through the strike and settles in Act
III without anybody keyframing it.
Three mesh variants, each a unit tree 1 m tall that the entity's `localScale`
sizes. The jitter is a per-angle flute held constant up the trunk plus a fine
vertical ripple, so the column reads as ribbed foliage rather than as shards,
and eighteen sprays stand out of each crown to break the silhouette.
## Exports
- `flora.trees()` — the avenue as a deterministic list.
- `flora.mint(force)` / `flora.spawn(parent)`
- `flora.update(t)` — pure in film time.
- `flora.PERCH` — where the rook sits until t = 15.55.
## What moves
Every yew leans downwind on `film.wind` in the direction `film.windDir` is
backing, out of phase with its neighbours. The bend is stated in world terms
and carried into each tree's own frame before it is applied, or the avenue
leans thirty different ways. The rook fidgets on its obelisk, then climbs away
north-east from t = 15.55 with its wings beating.