Field Time Slots
This page defines how time of day and weather behave during field play. The key words MUST, MUST NOT, SHALL, SHOULD, and MAY are used as in RFC 2119 — they define expected behavior, not current implementation status.
The decision (playtest notes, post-#646): the game does not ship a dynamic day-night cycle. A moving clock in a field implies shops closing and NPCs going home — the wrong genre of simulation for this game. Time of day is authored per field: each field ships exactly one deliberate, tuned slot — its identity time (valley day, snowfield night, ruins torch-dark). The snowfield's pinned hour-22 night is the template; this contract generalizes it from a per-area spelling into the slot table.
The rules
- The runtime MUST NOT run a free-running clock during
field play. There is no 24-real-minute day.
TimeManager's hour changes only when a slot is applied or a debug key previews one. - Each field SHALL ship exactly one authored slot per
area — chosen deliberately in that area's own issue, not generated. The
slot MUST be applied once at field/cell entry through the
pin block in
valley_field_controller._ready(); lighting MUST NOT be re-tracked per frame. - The applied slot hour MUST own
TimeManager.current_hourfor the duration of field play, so hour-derived consumers (the sky palette, the moonlight) read the field's authored time, not a leftover session value. - Light MUST NOT come from the player. The old player-carried lantern omni was a night-visibility crutch from the free-running-clock era (#659 removed it): every field's lighting is authored — the rig and the stage's placed effects carry it, and the player reads as part of the scene, not a source.
- The city (s00) MUST be always day. The city scenes
carry no clock at all — their lighting is authored interiors. City stages
reached through the field controller (the coliseum debug arena) pin
12.0(noon, deliberate).
The slot row
A slot row carries the area's identity: an hour (float —
fractional hours pick a stable lerped palette between phase presets), an
optional weather, and optional rig overrides applied after the
phase preset (ambient/sun/moon energies, the moon's elevation via
moon_pitch and its shadows, the sun's elevation via
sun_pitch and its shadows via
sun_shadows, the tonemap white
point, and the vertex-color bake mix that blends the baked lighting toward
white so the dynamic rig drives the look). A row MAY set
geometry_casts_shadows: map geometry ships shadows-off (the
bake is the look), and a rig that stands on real shadows — moon
(moon_shadows) or sun (sun_shadows) — turns casting
on so models shadow each other by position; either shadow row also skips the
player blob shadow (blob + real shadow reads double). One carve-out on the
sun side: a stage shell that ENCLOSES a room (walls + ceiling + backdrop,
often one mesh) must not cast — its own shadow would delete the sun from
its interior, and with it every dynamic shadow including the player's. At
room build, each casting mesh is ray-tested alone against the applied sun;
one that blocks every sample ray is disarmed from casting (it still
receives), so the player and placed objects cast real shadows on it.
Partial blockers — walls, rims — keep casting. Rows resolve most-specific-first:
exact stage_id → variant prefix (s03a,
s03b, tower floor styles) → area id → default day.
| Area row | Area | Hour | Weather | Note |
|---|---|---|---|---|
s03b | Snowfield B caves (variant row) | 5.5 — pre-dawn | snow (open ceilings) | LOCKED (walk-lab read-out): moon 0.6 @ −55°, ambient 0.05, bake 0.75, geometry casting; kinoko spores + anchors authored |
gurhacia | Valley (s01) | 10.0 — day | sand | the cheat rig (#648): stage keeps its bake; sun 0.90 / ambient 0.40 @ −60° lights actors + lit_surfaces (greenery only — every hard-surface prop read out of place); the collision-shell shadow catcher multiplies the actors' dynamic shadows onto the walkable ground; sand drift |
ozette | Wetlands (s02) | 10.0 — day | — | interim; #649 authors the overcast mood |
rioh | Snowfield (s03) | 22.0 — night | snow | the locked #646 rig (see below); s03a stages only now |
makara | Ruins (s04) | 10.0 — day | — | interior hours; #650 authors torch-dark |
paru | Forgotten City (s05) | 10.0 — day | — | interim; #651 establishes identity |
arca | Moon Facility (s06) | 10.0 — day | — | interim; #652 authors fixture lights |
dark | Dark Shrine (s07) | 10.0 — day | — | interim; #653 authors the dark-interior pin |
tower | Eternal Tower (s08) | 10.0 — day | — | interim; #654 authors fixed-hour floors |
city | City field stages (s00) | 10.0 — day | — | coliseum debug arena excepts to noon |
The snowfield rows split by variant (#657, the first variant row):
s03b caves pin 5.5 — the sunrise ramp's midpoint, a stable
lerped pre-dawn palette — under a blanket moon, LOCKED from the walk-lab
read-out: sun off, ambient 0.05 floor, moon 0.6 at −55° elevation with
real shadows and geometry casting (models and rocks shadow each other by
position, the original's implied moon position), bake mix 0.75 so a
breath of the blue bake survives under the moon. Open-ceiling B stages
carry the row's snow; the five enclosed ones stay weather-skipped by the
indoor gate. The s03a open-field stages keep the #646 night
lock verbatim (hour 22, snow, sun energy 0, ambient 1.50, moon 0.35 with
moon shadows on, bake mix 0.25 — geometry casting off: the bake is the
look there). The B caves' light anchors are authored placed
light effects from the stage config — the art ships no
crystals, so the pools are the blue reflective anchors and the red
mushroom clusters the warm accents, each kinoko cluster dusted by an
authored pink spores drift. The interim rows (10.0 day)
preserve pre-#655 behavior for areas whose identity issues (#648–#654)
have not authored a slot yet; each issue replaces its row's values and
locks them from a playtest read-out.
The valley row (#648) is the cheat rig — the
art-direction call from the 2026-09-21 hardware passes: the stage
keeps its authored bake (pure baked vertex color; no
bake_mix, so the white-strategy pass never runs), and the
dynamic sun lights only what the bake could not account for: the
player and enemies (lit on their own spawn paths) and
the row's lit_surfaces — the leaf greenery
(1_reaf1–5) only, matched by material name after the
per-surface split. The list is greenery-only by accumulated read-out:
every hard-surface class lit on trial — the ground decals
(1_deco1), oasis terrain (1_oas*), and the
bridge/rail/lantern-stone set (1_bri2 the final strike:
its mirror shader stays the lit variant under the keep-list, sunning
the bridge against baked rock) — read bright and out of place against
the baked world. Plants blend; stone and lumber don't. The toro
lanterns keep their warm placed-light pools without being lit
themselves. The stage's light-independence is forced, not
assumed:
some glTF materials import shaded (the diagnostic caught
1_flo1/1_view1/1_rock1/
1_step2 — the low ground lit up and the panorama
self-shaded under the rig), so a force-unlit pass flips every non-listed
Standard surface to UNSHADED — the MeshBasicMaterial guarantee. That
guarantee includes the bake's other half: the flip also forces
vertex_color_use_as_albedo, because imports without the
flag render raw-texture bright (the transparent ground detail planes and
the flat cliff faces of the 2026-09-21 read-out). Mirror-wrapped
surfaces (pass1, deco1) run the custom wrap
shader, and a custom ALBEDO shader is lit by default — under
the cheat they swap to its UNSHADED twin (COLOR_0 tint preserved)
unless they're on the lit list. Lighting
the floors themselves proved wrong twice over: it
erased the bake's intentionally dark unwalkable low ground (the
"you can only walk on the raised area" read) and drew harsh lines at
lit/unlit floor boundaries. Instead the row carries
shadow_catcher: the collision shell — the
walkable surface, exactly — renders as a white, multiply-blended,
per-pixel receiver lifted a hair above the walk height. Lit, it
multiplies the bake by ~1 (invisible); inside a shadow it multiplies
down — so the actors' dynamic shadows (the row's
sun_shadows; the blob shadow is skipped under any shadow
row) read as painted onto the authored look, the low ground keeps its
baked darkness, and the unwalkable areas get no shadows at all. No
geometry_casts_shadows: only the actors cast, so no rim
scenery shadows into the play space; the panorama shadow-eye placement
still runs. Sun 0.90 / ambient 0.40 at sun_pitch −60° is
the actor-lighting character — and, via the catcher's multiply, the
shadow depth (ambient is the shadow floor); the in-field tuner (,/.
ambient, 9/0 sun, 7/8 elevation, P read-out) owns the balance until
locked from a walk. Weather is a blowing sand drift (the
valley's dust), the first non-snow weather type. The stone-lantern
stages (s01a_td1/td2, the only 1_toro art)
carry warm placed-light anchors at day-punch intensity. The boss
arena's 2_kemu smoke stays un-authored — detection puts
every cluster on the distant backdrop ring, scenery rather than
sources.
The full sun-shadow rig that preceded the cheat (per-pixel stage,
geometry casting, the enclosure carve-out, panorama shadow-eye
placement and its rim pull) remains in the codebase and the row
schema — sun_shadows re-arms all of it — documented here
as the lesson: at every balance the dynamic stage shadows either read
invisible (under half a stop) or read wrong (rim scenery casting into
the play space; double lighting over the bake). A future row that
wants real stage shadows re-authors those fields knowingly.
Weather precedence
- A quest-authored
weatherkey (session level) MUST override the slot row's weather — explicit per-quest authoring beats the area default. - Otherwise the slot row's weather SHALL apply (this is the #609 unification: per-area weather config, not scattered prefixes).
- Indoor stages MUST NOT spawn weather particles regardless of source.
Debug preview
The [ / ] keys preview the current field at an
adjacent hour: they set TimeManager.current_hour and the field
controller re-applies the active slot's rig at the previewed hour. The
preview MUST NOT persist across cell transitions — each
cell entry re-applies the authored slot. On fields whose slot ships rig
overrides, the tuning keys (`,`, `.`, ambient; `[`, `]`, moon; `9`, `0`,
sun; `7`, `8`, sun elevation; `-`, `=`, bake mix; `P` for the
read-out) own those keycodes and the hour preview yields.
Explicitly deferred (phase 2 — do not build)
- Additional slot variations per field (valley evening, wetlands dusk-rain, …) — added one at a time only after that field's first slot is locked and plays well.
- Selection/advancement logic — rolled at field selection vs. fixed A→B progression. This only becomes a real question once variations exist.
Supersedes the always-day ask in #605 (day becomes Valley's one slot).