Skip to content

feat(sky): a stated sky can stand at a tick and ask for the game look - #41

Merged
stellarfeline merged 3 commits into
mainfrom
feat/stated-sky-look
Oct 21, 2026
Merged

stellarfeline merged 3 commits into
mainfrom
feat/stated-sky-look

Conversation

@stellarfeline

Copy link
Copy Markdown
Owner

A stated sky can stand at a tick and ask for the game's look

A caller that states its sky (Sky::Stated) used to get Chunky's look every time. 0.2.0's StatedSky had no field for a tick or a look. The HQ day weight was fixed at 1, the environment was sampled at the world's DayTime, and the stated quick sky drew no sunrise glow, moon or stars. A frame that states its sky at dusk therefore came out with Chunky's yellow cast where the game shows orange.

API

  • StatedSky::tick: Option<StatedTick>. StatedTick { time, look, render_distance } is built by StatedTick::new(time, look); StatedSky::at(tick) sets it.
  • StatedSky::new(quick, hq) is a stated sky at no tick, and draws what 0.2.0 drew.
  • QuickSkyColours::vanilla(env, biome, time, sun_dir, forward, draw_distance) returns the colours Sky::Vanilla derives, so a caller can state Lumenwright's own reading.
  • StatedSky and StatedTick are #[non_exhaustive].

Semver: this breaks 0.2.x. Adding a field to an exhaustive public struct breaks every struct literal, and that is true whether the new field has a default or comes with a constructor. Neither option keeps semver. The constructors together with #[non_exhaustive] make this the last such break: a later field is additive. Under Cargo's rule for 0.x, the next release containing this is 0.3.0. Callers move from StatedSky { quick, hq } to StatedSky::new(quick, hq).

Behaviour at a stated tick

  • The environment is sampled at tick.time.
  • The HQ weight comes from the stated look through look_weight, the one function Sky::Vanilla also uses. ByTime calls sky::day_weight, Game is 0, Chunky is 1. StatedSky::hq is Chunky's part of the frame.
  • Both modes draw the tick's sunrise glow, moon and stars through tick_celestials, the one function the vanilla arm also draws them with. Under Sky::Vanilla, quick_sky now gets its colours from QuickSkyColours::vanilla, so the stated and vanilla arms differ only in where the colours come from.

Tests

  • a_stated_sky_at_a_tick_is_the_vanilla_sky_at_it (lumenwright-cli/tests/library.rs) states QuickSkyColours::vanilla and sky::hq_sky at the same sun. Each frame must equal Sky::Vanilla { time: Some(T), sun_dir: Some(sun) } byte for byte on the CPU. Cases: quick at 12800 and 18000; HQ Game at 12800 and 18000; HQ ByTime at 12800. The same stated sky with no tick must draw something different, which proves the tick is not vacuous.
  • a_stated_sky_at_no_tick_draws_as_0_2_0_did (lumenwright-compat/tests/stated_sky.rs) renders one request through this tree and through lumenwright =0.2.0 as published on crates.io. The world's DayTime is midnight. Quick and HQ must be byte-identical on the CPU.
  • lumenwright-compat is a new workspace member with publish = false. A published crate cannot depend on lumenwright 0.2.0 under two names (cargo publish --dry-run refused it), so the oracle lives in its own crate. cargo test --workspace runs it, and the package job skips it.

Red before, green after. Each perturbation below was applied to a scratch copy of the tree:

perturbation test that reds
no celestials at a stated tick tick test: quick ByTime at 12800
stated weight fixed at 1 tick test: HQ Game at 12800
environment sampled at the world's DayTime tick test: quick ByTime at 12800
celestials drawn at no tick 0.2.0 test, quick (and a_stated_sky_is_drawn_as_given)
ByTime as the default look at no tick 0.2.0 test, HQ

The treehouse dusk reference through the stated path

Camera: 140,118,14 looking at 56,82,58, fov 60, render distance 12, tick 12800, HQ, 8 bounces. Rendered on Apple M2 Pro Metal at 2048 spp. The stated sky is QuickSkyColours::vanilla plus sky::hq_sky at the environment's sun, StatedTick::new(12800, ByTime).

  • Stated frame against Sky::Vanilla { time: Some(12800), sun_dir: None } at the same budget: byte-identical, 0 of 921 600 pixels differ.
  • Both against the approved docs/renders/treehouse-camp-dusk-hq.png (CUDA, 16 384 spp): mean |d| 1.83/255.

Measured with measure.py:

method approved reference stated path Chunky's look (--sky chunky)
A, sky band near the horizon (188,125,77), hue 25.9° (188,125,77), hue 25.9° (241,214,120), hue 46.6°
A, sky upper left (161,107,86), hue 16.8° (161,107,86), hue 16.8° (157,153,119), hue 53.7°
B, top third mode 20–30°, 74.5% orange, 5.3% yellow mode 20–30°, 74.8% orange, 5.5% yellow mode 40–50°, 1.8% orange, 81.1% yellow
B, whole frame mode 20–30°, 34.6% orange mode 20–30°, 34.8% orange mode 90–100°, 6.6% orange

Not expressed

Weather: the game's look draws a clear sky, both under Sky::Vanilla and at a stated tick, and applies no rain or thunder. This is recorded in CHANGELOG [Unreleased].

Docs

  • CHANGELOG [Unreleased]
  • docs/library.md: the stated tick
  • docs/SCOPE.md: G10
  • docs/testing.md: the release tests

🤖 Generated with Claude Code

https://claude.ai/code/session_016ba8LkuKW2bd5C5HCDo7p2

stellarfeline and others added 3 commits October 21, 2026 07:18
StatedSky gains `tick: Option<StatedTick>` (time, look, render distance).
At a stated tick the environment is sampled at it, HQ mode weights the
stated look through the one `look_weight` (`sky::day_weight` for
`ByTime`) that `Sky::Vanilla` uses, and both modes draw the tick's sunrise
glow, moon and stars through the one `tick_celestials` the vanilla arm
uses. `QuickSkyColours::vanilla` is the vanilla arm's colour derivation,
public so a caller can state Lumenwright's reading. At no stated tick
(`StatedSky::new`) the frame is 0.2.0's. StatedSky and StatedTick are
`#[non_exhaustive]` with constructors.

Tests: a stated sky at tick T equals `Sky::Vanilla { time: Some(T) }`
with the same sun, byte for byte; at no tick it equals 0.2.0 as published
(a dev-dependency on lumenwright =0.2.0), byte for byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ba8LkuKW2bd5C5HCDo7p2
… the tests

CHANGELOG [Unreleased] records the stated tick, QuickSkyColours::vanilla,
the non_exhaustive constructors (a breaking change for 0.2.x), and
weather as not expressed: the game's look draws a clear sky.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ba8LkuKW2bd5C5HCDo7p2
`cargo publish --dry-run --workspace` refused lumenwright-cli: a published
crate may not depend on lumenwright 0.2.0 twice under two names (the
path dependency and the =0.2.0 oracle). The oracle test moves to
`crates/lumenwright-compat` (publish = false), a workspace member that
`cargo test --workspace` runs and the package job skips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ba8LkuKW2bd5C5HCDo7p2
@stellarfeline
stellarfeline merged commit dbe4d6e into main Oct 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant