feat/time-of-day #98

Merged
akadmin merged 5 commits from feat/time-of-day into main 2026-07-06 19:38:32 +00:00
Owner
No description provided.
Implements issue #21: a TimeOfDay component on the directional-light
entity drives the sun through a full day/night cycle.

- TimeOfDay { hours 0-24, hours_per_second, sun_path_tilt_deg } with
  sun_direction(): hour angle on a tilted circle - 6:00 rises east,
  noon peaks off-zenith by the tilt, 18:00 sets west, 0:00 nadir.
- Derived at light-gather time (not Transform mutation): when a
  directional light carries TimeOfDay, gather_lights overrides its
  direction from the clock and tints its color by
  atmosphere::sun_transmittance - a CPU mirror of the sky shader's
  secondary march (8 samples, 1.1x Mie extinction) with a smoothstep
  horizon fade. Sky, fog tint, shadows, and scene lighting all follow
  via the existing lights[0] pipeline (ADR-0032); no shader changes.
- gather_lights now takes &AtmosphereParams (both call sites updated).
- behavior_tick advances hours in Play (wraps at 24; speed 0 pauses);
  the default 0.5 h/s gives a 48 s full cycle.
- Debug UI: inspector "Time of Day" section (Hours slider, Speed,
  Path tilt) with live viewport scrubbing via apply_preview and one
  SetTimeOfDayCommand per drag; Add Component menu entry; hint that
  Transform rotation is ignored.
- Serialized via EntityFile (save/load, export, Play snapshot,
  delete/undo); Add/Set commands with tests.
- 21 new tests incl. the acceptance cycle test (48 s fixed-step
  Play sweep hits east/up/west/down and returns the clock to noon).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two reports after the TimeOfDay feature: "the atmosphere barely
provides light" and "the time slider does not work". Root cause is
one issue: under the procedural sky the ambient term was still the
0.03 default-grey IBL, so surfaces outside direct sunlight were
near-black - and scrubbing time changed almost nothing visible.

- LightsData gains a sky_ambient vec4 (UBO 480 -> 496, mirrored in
  fragment/depth/unlit shaders): a diffuse sky-colored ambient fill
  derived from the same sun-elevation palette as the fog (x0.35),
  active only under the atmosphere sky - HDR scenes keep their IBL
  ambient, sky-less scenes stay unchanged. The scene now brightens
  and tints with the time of day.
- Slider data path verified end to end by a new headless test
  (working copy -> apply_preview -> world -> gather_lights moves the
  sun); added a changed()-without-drag fallback so click-jumps and
  keyboard entry commit immediately, and an inspector hint when the
  scene has no Sky entity (time of day is invisible without a sky).
- ADR-0033 records the ambient addition as the analytic stopgap for
  the deferred atmosphere-driven IBL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sky, fog, ambient, and shadow matrix all read the slot-0 light,
and order_lights promoted the lowest-entity-id directional there. A
scene with any directional light older than the TimeOfDay sun kept
that static light in slot 0 - so scrubbing the time slider moved an
invisible slot-1 light while the sky's sun stayed pinned at its old
position ("stays high noon").

- order_lights entries gain an is_sun flag (directional + TimeOfDay,
  ADR-0033): the declared sun sorts before everything else and wins
  slot 0; lowest id breaks ties between multiple TimeOfDay suns.
  Regression tests at both the order_lights and gather_lights level
  (older static directional + newer TimeOfDay sun).
- Inspector warns when TimeOfDay sits on an entity without a
  directional Light - the other way the slider could silently drive
  nothing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was no way to take a component off an entity — Add Component
had no inverse.

- New generic RemoveComponentCommand<T> (one struct instead of ten):
  execute snapshots the component and removes it, undo re-inserts
  the exact values (not defaults); remap-safe. Tests cover restore,
  missing-component no-op, and entity remapping.
- Inspector gains a "Remove Component" menu mirroring Add Component,
  listing whichever of Material/Mesh/MeshSource/Light/Camera/Sky/
  Rotator/Time of Day/Script/Collider/RigidBody are present. Name
  and Transform are deliberately not removable (everything labels
  and positions through them).
- Stale working copies are harmless after removal: apply_preview
  writes via get_mut, which no-ops once the component is gone, and
  the per-frame sync clears the edit state next frame.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chore(scene): update demo scene with TimeOfDay sun
All checks were successful
CI / build (pull_request) Successful in 3m23s
46e74280d5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
akadmin deleted branch feat/time-of-day 2026-07-06 19:38:32 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
akadmin/NemesisEngine!98
No description provided.