·
scene · drop-in viewer
What it does
No description provided yet.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
This asset doesn't declare a schema or structured payload.
Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Showing up to 3 levels deep. Open a part to see what it holds further down.
87+items
▲ 0↑ born
▲ 0↑ born
# Mesh
Mesh asset. `data.zmsh` is the engine-native geometry payload (`renderer.mesh.encode`); consumers reference the asset's guid.
▲ 0↑ born
# Mesh
Mesh asset. `data.zmsh` is the engine-native geometry payload (`renderer.mesh.encode`); consumers reference the asset's guid.
▲ 0↑ born
# Mesh
Mesh asset. `data.zmsh` is the engine-native geometry payload (`renderer.mesh.encode`); consumers reference the asset's guid.
▲ 0↑ born
▲ 0↑ born
▲ 0↑ born
# Mesh
Mesh asset. `data.zmsh` is the engine-native geometry payload (`renderer.mesh.encode`); consumers reference the asset's guid.
▲ 0↑ born
▲ 0↑ born
▲ 0↑ born
# Mesh
Mesh asset. `data.zmsh` is the engine-native geometry payload (`renderer.mesh.encode`); consumers reference the asset's guid.
▲ 0↑ born
# firstlight.rules
The one module every part of First Light requires: `require("firstlight.rules")`.
It holds the game's numbers (day length, temperatures, calorie burn, stove fuel
rates, bear ranges, starting stores), the layout of the station and the sites
around it, the shared blackboard `M.state`, the event bus `M.events`, and the
clock.
## The clock
`M.tick(dt)` is called once per play frame by the scene entrypoint. It advances
`M.state.run.elapsed`, derives `M.state.clock` (day, fraction of day, hour, sun
elevation, twilight openness) and emits `day`, `noon` and `firstLight`.
`M.sleepToMorning()` jumps to 07:00 next day; `M.restore(elapsed)` rebuilds the
clock from a persisted run.
Pure helpers: `sunElevation(day, t)`, `twilightSeconds(day)`, `airC(day, t)`,
`windChill(airC, windMs)`, `progress(day)`, `rng(seed, salt)`, `dist2d`.
## The blackboard
`M.state` has one section per slice. A slice writes its own section and reads
the others: `run`, `clock`, `weather`, `body`, `hut`, `stores`, `bear`,
`journal`.
## Events
`M.events.on(name, fn)` returns an unsubscribe function; `M.events.emit(name,
payload)` calls every listener. The names and payloads are listed at the top of
`init.luau`. `M.say(text, seconds)` emits `say` for the HUD.
▲ 0↑ born
# firstlight.hut
The living hut as a place to stay alive in. Attached to `living_hut` by the
scene build. At awake it spawns the interior as temporary children under
`fl_hut_interior`: the bunk along the west wall, the table and stool against
the east wall with the barometer and thermometer above them, two rafters
under the roof, the lamp bracket and lamp on the north wall — and, once a
survivor has died here, the roof cache (`fl_roof_cache`), a canvas bundle
roped to the east rafter holding a quarter of their stores.
## What it runs
`Rules.state.hut.insideC` settles toward
airC + (shelterC + stoveHeat * stoveC) / (1 + gaps * (0.35 + 0.02 * windMs))
capped at `maxInsideC`, with the lag of a timber room. Unpatched wind gaps
(`Rules.state.hut.gaps`, starting at `Rules.HUT_GAPS_START`) are what let
the stove's warmth out; a patched gap outlasts the run.
## Methods (call with a colon on `entity.find("living_hut").component.get("hut")`)
| Method | Does | Returns |
|---|---|---|
| `hut:sleep()` | Sleep in the bunk until 07:00 tomorrow (`Rules.sleepToMorning()`). Refused while the hut is below -25 C with the stove cold. The night burns fuel and warms or chills the body by the hut's warmth. | HUD line (string) |
| `hut:patchGap()` | Patches one wind gap; persists across runs. | gaps still open (number) |
| `hut:state()` | `{ insideC, gaps, targetC, cache }` | table |
| `hut:bunkPosition()` | Hut-local position of the bunk, for the prompt. | `{ x, y, z }` |
## Fields
- `shelterC` (12) — degrees the hut rises above the air on shelter alone.
- `stoveC` (75) — degrees a high burn adds in a tight hut before gap losses.
- `maxInsideC` (26) — the warmest the hut gets.
▲ 0↑ born
# outings
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputMap provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputMap.
▲ 0↑ born
# bear
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this component provides and who
consumes it, then delete both comment lines. -->
TODO: describe this component.
▲ 0↑ born
# firstlight.body
The survivor's body, and the record of the run. Attached to `GameDirector`
by the scene build.
## What it runs, every play frame
- Where the local player stands: `Rules.state.body.indoors` is true inside
the living hut's footprint; `nearFire` (0..1) is the stove's warmth
reaching the body, full within a metre of the firebox and gone at
`fireReachM`.
- `coreC`: loses `lossPerDegree` per second per degree the felt temperature
sits below `comfortC` — the hut's `insideC` indoors, the weather's `chillC`
outdoors — multiplied by `1 + 2.5 * wet`; gains `fireGain * nearFire`. At
-40 C in still air a warm body dies in about 15 real minutes (1.5 in-game
days); by a high stove it is back to normal in three.
- `kcal`: `Rules.KCAL_PER_DAY_REST` per day at rest indoors, toward
`Rules.KCAL_PER_DAY_WORK` moving outdoors.
- `wet`: snow and storm soak clothes outdoors; the fire dries them.
- `frostbite` below `Rules.CORE_C_FROSTBITE`: the avatar's
`CharacterController.moveSpeed` is scaled by `frostbiteSpeed` until the core
recovers.
- Death at `Rules.CORE_C_DEATH` or `Rules.KCAL_DEATH`, through
`firstlight.legacy`: the run ends, the last journal line is written, the
cache is stashed, the save is written and `death { cause, day }` is emitted.
A `death` another slice emits (the bear) is handled the same way.
- Sleep (`sleep` event): eight hours of rest at the hut's warmth.
- The journal: a line for the day that ended on every `day` event.
- The save: `firstlight.persist` writes `run`, `body`, `hut`, `stores` and
`journal` on every day, sleep, death, patch and (throttled) store change,
and on leaving play; it reads them back at awake so a reload resumes the
same morning. The forecast seed is chosen once per world at the first load.
## Methods (call with a colon on `entity.find("GameDirector").component.get("body")`)
| Method | Does | Returns |
|---|---|---|
| `body:eat(kcal)` | Adds calories (a tin is about 800). | calories held (number) |
| `body:warm(degrees)` | Warms the core directly (a hot meal). | core C (number) |
| `body:newRun()` | Starts the next run from the death screen: body, clock and stores reset to the start values plus the cache; journal, seed, deaths, patched gaps and drilled hole stay. Emits `newRun { deaths, cache }`. | — |
| `body:save()` | Writes the save now. | — |
| `body:state()` | `{ coreC, kcal, wet, frostbite, indoors, nearFire, alive, day }` | table |
▲ 0↑ born
# firstlight.stove
The cast-iron box stove in the living hut. Attached to `living_hut` by the
scene build. At awake it spawns the stove (hearth, legs, firebox, door with
mica window and draught vent, top plate and rings, flue through the roof,
poker, the wood stack) as temporary children under `fl_stove`, with a
flickering amber point light and the crackle loop
(`firstlight.body.stove_crackle`).
## What it runs
- Three levels: 0 out, 1 low (`Rules.STOVE_FUEL_PER_HOUR_LOW` kg/h), 2 high
(`Rules.STOVE_FUEL_PER_HOUR_HIGH` kg/h). Fuel burns from the firebox
(`Rules.state.hut.fuelKg`, up to `fireboxKg`), which is loaded from
`Rules.state.stores.fuel`.
- Embers: a fire damped down or burned out keeps embers for
`Rules.STOVE_EMBER_HOURS`; lighting from embers costs no match, otherwise a
match comes off `Rules.state.stores.matches`.
- `Rules.state.hut.stoveHeat` (0..1) follows the burn with the lag of iron;
the light, the window glow, the crackle volume and the hut's warmth
(firstlight.hut) all read it.
- The night: on `sleep` the stove burns the hours slept.
- Emits `stove` `{ level, heat }` on every change of level or on/off.
## Methods (call with a colon on `entity.find("living_hut").component.get("stove")`)
| Method | Does | Returns |
|---|---|---|
| `stove:light()` | Lights the fire at low. Free from embers, otherwise strikes a match. Loads 1.5 kg from the store if the firebox is empty. | HUD line (string) |
| `stove:setLevel(n)` | `0` damps down to embers, `1` low burn, `2` high burn. Lights the stove first if it is out. | HUD line (string) |
| `stove:addFuel(kg?)` | Moves wood (default 1.5 kg) from `stores.fuel` into the firebox. | kg moved (number) |
| `stove:state()` | `{ on, level, heat, embers, fuelKg, matches }` | table |
| `stove:firePosition()` | Hut-local position of the firebox, for a prompt or a bear. | `{ x, y, z }` |
Every method also speaks its line through `Rules.say`.
## Fields
- `fireboxKg` (5) — the most wood the firebox holds.
- `lightIntensity` (9), `lightRadius` (8) — the fire light at a high burn.
▲ 0↑ born
# ui
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this component provides and who
consumes it, then delete both comment lines. -->
TODO: describe this component.
▲ 0↑ born
# firstlight.sky
The sky is the clock. Attached to the scene's `sky` entity beside its
ProceduralSky, this component drives the whole sky from
`Rules.state.clock` every frame:
- **The sun.** South at noon, north at midnight, below the horizon every day
but the last. The `sun` light always points away from it, so the
ProceduralSky draws the disc, its glow and the moon in the right place; its
light arrives only as the disc reaches the horizon on day 30.
- **The moon.** A `distant` light opposite the sun, the blue light on the snow
at full night. It fades as the twilight opens.
- **The ambient light** rises from the night blue to a paler violet-blue with
the twilight.
- **The stars** fade as the twilight opens.
- **The twilight band** over the southern horizon: a dome round the station
wearing `firstlight.sky.twilight`, fed the sun's direction and
`Rules.state.clock.twilight`. Deep blue and a few degrees tall on day 1,
violet then rose at its foot and a third of the sky tall by day 30.
- **The aurora** over the sea ice to the north: five arched curtain sheets
wearing `firstlight.sky.aurora` (the installed Carrington curtain shader
under this sky's palette). Their strength is `Rules.state.weather.aurora`,
each sheet breathing on its own slow clock through its first instance-data
lane, and they drown as the twilight opens.
Everything it hangs under the sky entity is temporary: it is spawned on
`awake` and never saved with the scene.
## Fields
| Field | Default | Meaning |
|---|---|---|
| `auroraOverride` | -1 | Aurora strength to use instead of the blackboard's; -1 follows `Rules.state.weather.aurora`. |
| `twilightGain` | 1.0 | Gain on the twilight band. |
| `moonlight` | 0.32 | The moon's light on the snow at full night. |
| `sunlight` | 1.4 | The sun's light at noon on day 30. |
## Seeing a moment
From `execute`, in play:
```luau
local Rules = require("firstlight.rules")
Rules.restore((day - 1) * Rules.DAY_SECONDS + t * Rules.DAY_SECONDS)
```
then capture looking south (+Z) for the twilight and north (-Z) for the
aurora. `Rules.restore` is the call that moves the clock backward as well as
forward.
▲ 0↑ born
# firstlight.weather
The weather of First Light. The scene attaches it to the `Weather` entity;
from there it reads the clock and the run's forecast seed and, every frame,
writes `Rules.state.weather` and puts the weather into the world:
- **Snowfall** — a particle column around the player's eye whose flakes drift
at the wind's own speed and stretch along their path, so calm air holds
slow dots and a blizzard holds horizontal streaks.
- **Fog** — the scene's height fog, closing from the horizon at calm to a few
paces in a blizzard, and a dome that closes the sky by the same optical
depth, so a whiteout is a whiteout overhead too.
- **Spindrift** — the snow plain's `spindrift_gain`, `spindrift_speed` and
`sparkle_gain` follow the wind: loose snow tears downwind across the crust
as the storm rises, and the ice glint dies in it.
- **Sound** — the wind and howl loops, crossfading with the storm. The wind is
a breath at calm and full in a storm; the howl is silent below the storm
band and full in a blizzard.
- **Events** — `Rules.events.emit("storm", { storm, band, windMs })` whenever
the band changes.
## The blackboard
`Rules.state.weather` carries `storm` (0..1), `band` (calm, wind, storm or
blizzard), `windMs`, `windDir` (radians, the direction the wind blows toward),
`visibilityM`, `airC`, `chillC`, `snowing` (0..1) and `aurora` (0..1). The
body slice reads `chillC`; the sky slice reads `aurora`; the HUD reads
`windMs` and asks `firstlight.forecast` for tomorrow.
## Fields
| field | meaning |
|---|---|
| `forceStorm` | -1 follows the forecast; a value in [0, 1] holds the storm there. For tests and cutscenes; leave it at -1. |
| `snowDensity` | Scale on the snowfall's particle rate. |
`comp:setForce(storm)` sets `forceStorm`; `comp:current()` returns the
blackboard section, which is where the shown weather is read from.
The shown storm eases toward its target rather than jumping, so a forced
value takes a few seconds to arrive and the forecast's own changes roll in
over minutes.
## What it owns in the scene
Four temporary children under `Weather`, spawned at runtime and left out of
the scene's record: `wx_snowfall` (the emitter), `wx_wind` and `wx_howl` (the
loops), `wx_shroud` (the sky dome, drawn with `firstlight.weather.shroud`).
▲ 0↑ born
# firstlight.sites
Everything the survivor can take, and where. Attached to the `Sites` anchor
by the scene build. It places the props, registers each with
`firstlight.interact`, raycasts from the player's camera every frame so
`Interact.current()` names what the reticle is on, answers the interact and
headlamp keys, and drains lamp oil and batteries into `Rules.state.stores`.
## What it places
All of it as temporary children (never saved into the scene), rebuilt on
every load from the counts kept on the blackboard:
| Where | Props | Interaction |
|---|---|---|
| `workshop` | a crate of tins, a stack of scrap timber, a bench with a matchbox, the ice drill | take tins ×3, timber ×4, matches ×6, the drill |
| `generator` | the engine block, two jerry cans, three coils of copper wire | oil residue ×2 (0.5 L each), wire ×3 |
| `radio_hut` | the battery bank, the radio desk, a matchbox | batteries ×3, matches ×4 |
| `storage` | a half-buried crate and salvage planks at the heap's edge | tins ×4, timber ×3 |
| `living_hut` | the hanging lantern and its point light; the snowed-over food cache outside the door | light / snuff the lamp; cache fish and meat outside, bring it back in |
| `fishing_hole` | a cleared ice patch, the hole once drilled, a flag stake | drill the hole (needs the drill), then cast — `castsPerDay` casts a day at `fishChance` |
| `trap_line` | three traps along the hare runs, a flag stake | set the traps; check them from the next day at `trapChance` for meat |
| `river` | the black ice of the frozen river between its banks | landmark |
| `driftwood` | a heap of logs, a flag stake | gather once a day: fuel +4 |
| `coal_seam` | the outcrop and a heap of coal, a flag stake | dig once a day: fuel +6 |
| `wreck` | the listing hull and the ship's stores crate | one search: tins +5, oil +2, batteries +2, matches +10, wire +2 |
| `caribou` | the carcass, from `stores.caribouDay` until butchered | butcher: meat +10 |
A generated model under `/firstlight/sites/<name>.bundle` (`ice_drill`,
`tin_crate`, `jerry_can`, `battery_bank`, `lantern`, `fox_trap`, `driftwood`,
`coal`, `wreck`, `caribou`) is used when it resolves and fitted to size on
its first frame; otherwise the prop is built from primitives and the
materials beside it.
## The stove and the bunk
The body slice spawns `stove` and `bunk` under `living_hut`. Once a second
this component looks for them, fits an `interact_hit` box to each, and
registers them: the stove lights through `firstlight.stove:light()` and
cycles low/high through `:setLevel(n)`; the bunk sleeps through
`firstlight.hut:sleep()`.
## The headlamp
A `SpotLight` child named `headlamp` on the player's camera rig. `F` (the
`headlamp` control of `firstlight.sites.outings`) toggles it. Switching on
with an empty lamp takes a battery from `stores.batteries` and fills
`stores.headlampCharge`; it drains over `headlampBatterySeconds` real seconds
and changes to a fresh battery by itself, or dies when there are none.
## Fields
| Field | Default | Meaning |
|---|---|---|
| `walkMap` | `@builtin::inputMaps.default` | the scheme whose `interact` control is used |
| `outingsMap` | `firstlight.sites.outings` | the headlamp switch |
| `headlampBatterySeconds` | 240 | real seconds one battery lasts |
| `lampOilPerHour` | 0.05 | litres the hut lamp burns per in-game hour |
| `fishChance` | 0.45 | chance a cast lands a fish |
| `trapChance` | 0.55 | chance the traps hold something the next morning |
| `castsPerDay` | 5 | casts before the fish stop biting for the day |
Every use emits `interact { site, action }` and a `say` line; every store
change goes through `firstlight.stores` and emits `stores`.
▲ 0↑ born
# headlamp
<!-- zero:scaffolded-readme -->
<!-- Replace the line below with what this inputBinding provides and who
consumes it, then delete both comment lines. -->
TODO: describe this inputBinding.
▲ 0↑ born
# snowfield
The arctic plain of Carrington Night. Wind-packed snow: sastrugi ridges
displaced in the vertex stage and masked out of the switchyard's graded pad,
their normal reconstructed analytically per fragment, a crust/powder split
driving albedo and roughness, a spindrift sheet streaming downwind at every
distance, and ice-crystal glint near the lens.
▲ 0↓ import
backing path · scenes/main.scene
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
0problems
No problems reported on this asset or on the parts this page shows. Parts it leaves out are not counted here.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up
agent_score is exposed.usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor
+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
—%no reports yet
Sign in to report whether this part worked for you.
Discussion
Scoped to this part · feeds back into the world's score.
0comments
Sign in to post.sign in
No comments yet. Be the first.