PROTOTYPE: procedural weather moods on the day-cycle sky#84
Open
ryanbr wants to merge 7 commits into
Open
Conversation
Explores weather-style backgrounds that work WITH the existing time-of-day gradient (the idea in discussion). Aesthetic only — no real conditions, no location/network, so NOOP stays offline. - LiquidSky: a new weather layer between the warm sheet and the starfield, tinted by the CURRENT sky so a cloud at dusk reads mauve and at noon white. Six moods, all procedural Canvas fills (no assets): clear (default), hazy, overcast (soft drifting radial clouds), rain (clouds + falling streaks), fog (rising veil), snow (drifting specks). Animated on the Today sky. - Appearance settings: an experimental "Weather" menu picker (menu style so it can't overflow like #43), gated on the day-cycle background being on. Default clear = today's look unchanged. PROTOTYPE — iOS/macOS, Today background only; values are a first pass to tune on-device (SwiftUI Canvas can't be previewed off-device). Static-tab skies are left plain for now.
Android's Today background is the same gradient sky as iOS (LiquidSky.kt, a 1:1 port), so this mirrors the iOS prototype exactly rather than touching the image scenes. - LiquidSky.kt: a weather layer in the shared renderLiquidSky (so it covers BOTH the animated Today sky AND the static scaffold sky in one place — the gap the iOS side has), tinted by the current sky. Six moods matching iOS: clear (default), hazy, overcast, rain, fog, snow. LiquidWeather enum + a reactive LiquidWeatherState (mirrors CardAppearance) so the picker live-updates. - NoopPrefs: weather getter/setter, stored under the SAME "liquid.weather" raw string as iOS. Loaded at launch (LiquidWeatherState.init in MainActivity). - Settings → Appearance: a "Weather (experimental)" SegmentedPillControl below the day-cycle toggle, gated on it, live-updating the sky. PROTOTYPE — values are a first pass to tune on-device. Android compiles locally.
…ocedural fallback) The procedural moods read a bit muted; add an IMAGE path so richer art can drive each mood, with the procedural draw as the fallback when no art is present — so the app still works with zero assets and dropping a file in upgrades that mood with no code change. - iOS/macOS (LiquidSky.swift): loadWeatherImage() resolves weather_<mood> from the asset catalog (UIImage/NSImage); drawWeatherLayer draws it blended (.screen, 0.85 — tunable) over the gradient, else falls back to the procedural draw. - Android (LiquidSky.kt): rememberWeatherImage() resolves weather_<mood> from res/drawable via getIdentifier (0 = absent → fallback); rendered with drawImage(blend=Screen, alpha=0.85) in the shared render core. - docs/WEATHER_ASSETS.md: exact asset names, where the files go per platform, art guidance, and a REQUIRED licence table — every weather image must have its source + licence recorded before committing (unlike the inherited scene1-10 backdrops). No art committed yet — supply weather_<mood> files (self-generated / licensed) and they render automatically. Blend + opacity are on-device tuning knobs. Android compiles locally.
First real weather art: weather_rain (1500x1000) into the iOS asset catalogs (Strand + StrandiOS) and Android res/drawable-nodpi. The Rain mood now draws the image instead of the procedural streaks. - Blend default changed .screen -> normal source-over (both platforms): the supplied art is an OPAQUE storm scene, which source-over lets cover/darken the sky (screen would drop the dark background and only lighten). Source-over is also the universal default — a transparent overlay still shows the gradient through its alpha. Opacity 0.9 (tunable). - docs/WEATHER_ASSETS.md: license row for weather_rain flagged TO CONFIRM. NB: weather_rain provenance/license is NOT yet recorded — must be confirmed before this ships or merges (prototype/testing only for now). Android compiles locally.
…retch"/"doubled") Android drew the weather image aspect-fit-to-width, top-aligned — a 3:2 landscape storm image covered only the top ~2/3 of the tall sky band with a hard bottom edge, which read as "not stretched" and (split by a floating card over its middle) as "doubled". Now stretches to fill the whole sky canvas (dstSize = w×h), matching the iOS draw; the settle fade dissolves the lower part into the page. Android compiles.
…ix scroll stutter) A weather image is static, but the animated sky (Today) re-blitted the full-screen bitmap every frame (20fps) — behind a scrolling list that stutters, and it hides the animated breath/stars underneath anyway. Now the sky poses ONCE (no frame loop) when an image is present, so scroll composites a cached texture instead of a per-frame redraw. Procedural moods + the plain sky keep the live animation. - iOS: LiquidSky.body skips TimelineView when loadWeatherImage() resolves. - Android: LiquidSky takes the static (no withFrameNanos) path when weatherImage != null. Android compiles locally.
…r the image) The weather image is a soft, stretched background wash, so full 1500px res buys no visible quality but quadruples the texture the translucent scrolling cards must composite over each frame — the residual card stutter on the (already-static) Settings sky. Decode at half res (inSampleSize=2, ~750px). Android compiles.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prototype / not for merge as-is — exploring weather-style backgrounds that layer with the time-of-day gradient.
Approach
LiquidSkyis already a layered Canvas (gradient → warm sheet → stars → settle). This slots a weather layer between the warm sheet and the stars, tinted by the current sky — so a cloud at dusk reads mauve, at noon white. Aesthetic only: no real conditions, no location/network (keeps NOOP offline).Six moods, all procedural (no assets):
Opt-in via an experimental "Weather" picker in Appearance settings (menu style so it can't overflow like #43), gated on the day-cycle background being on.
How to try it
Sideload the testing build → Settings → Appearance → Weather (experimental) → cycle the modes and watch the Today background at different times of day.
Honest caveats
Files:
Strand/Liquid/LiquidSky.swift,Strand/Screens/SettingsView.swift.