diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-28 18:48:05 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-28 18:48:05 +0800 |
| commit | d3a2604e30b1deb91afebf550a79cde71bbca6d6 (patch) | |
| tree | 7cf10505e76f5a6749faadb96ff4d678a3c8fb26 /src/LivingVillage.Desktop/TitleScreen.fs | |
| parent | 323552b7e49550d378d3871fadcb711c16c71fed (diff) | |
| download | living-village-d3a2604e30b1deb91afebf550a79cde71bbca6d6.tar.gz | |
p42: 启动/菜单水面涟漪整改 — 振幅0.32+波峰列, 帧差14.3, 防降振回归 (leader fix: 提交+推送)
Diffstat (limited to 'src/LivingVillage.Desktop/TitleScreen.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/TitleScreen.fs | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop/TitleScreen.fs b/src/LivingVillage.Desktop/TitleScreen.fs index 0dcd693..2e760ef 100644 --- a/src/LivingVillage.Desktop/TitleScreen.fs +++ b/src/LivingVillage.Desktop/TitleScreen.fs @@ -88,6 +88,38 @@ module TitleScreen = if frameCount >= 120L then 0.0f else 1.0f - float32 frameCount / 120.0f + // ---- P42 environment FX: all pure functions of the frame counter, so re-rendering + // the same frame is byte-identical. Shared by the splash and the start menu. ---- + + /// Sine ripple amplitude of the water band. Kept as a named constant so a test can + /// assert it never regresses below the full-frame visibility budget (>= 0.25). + let waterRippleAmplitude = 0.32f + + /// Water ripple phase: moves with the frame and is dense across tile columns + /// (~5 tiles per wave), so adjacent 28px columns differ enough to read at 1x. + let waterRipplePhase (frame: int64) (column: int) (rowIndex: int) : float32 = + float32 (frame % 4096L) / 5.0f + float32 column * 1.25f + float32 rowIndex * 0.6f + + /// Water ripple brightness per tile column: base 1.0 +/- waterRippleAmplitude sine. + let waterRippleBrightness (frame: int64) (column: int) (rowIndex: int) : float32 = + 1.0f + waterRippleAmplitude * sin (waterRipplePhase frame column rowIndex) + + /// Water crest lift in whole pixels (-2..2) for a tile column; drives the moving + /// ripple highlight without ever leaving a hole in the water band. + let waterRippleLift (frame: int64) (column: int) (rowIndex: int) : int = + int (System.Math.Round(float (sin (waterRipplePhase frame column rowIndex) * 2.0f), System.MidpointRounding.AwayFromZero)) + + /// True on columns sitting on a wave crest; the renderer caps these with a bright + /// highlight and the frame analysis counts them. + let waterRippleCrest (frame: int64) (column: int) (rowIndex: int) : bool = + sin (waterRipplePhase frame column rowIndex) > 0.55f + + /// Eave-lantern breathing glow alpha, bounded to [40, 96]; phase moves with the + /// frame and the lantern index so the bank lanterns breathe out of step. + let lanternBreathAlpha (frame: int64) (index: int) : int = + let phase = float32 (frame % 4096L) / 22.0f + float32 index * 1.3f + 68 + int (System.Math.Round(float (sin phase * 28.0f), System.MidpointRounding.AwayFromZero)) + let layout (viewportWidth: int) (viewportHeight: int) : TitleLayout = let width = max 320 viewportWidth let height = max 240 viewportHeight |
