Canvas-based seasonal weather effects + demo page

Server picks variant from Lisbon-local date (rain/petals/jacaranda/motes/leaves)
and renders behind content via a canvas particle layer. Each variant has a
hand-drawn silhouette so shapes are recognizable. /weather demo route exposes
variant + intensity + phase pickers, locking the time-of-day phase override.
This commit is contained in:
prosolis
2026-05-25 09:20:35 -07:00
parent 5ea64c1d32
commit 24103394ae
7 changed files with 413 additions and 3 deletions

View File

@@ -42,6 +42,8 @@ type pageData struct {
SiteTitle string
Channels []Channel
Active string // slug of active channel, "" for landing
Weather Weather
Phase string // when set, forces day/dawn/dusk/night and disables the clock-driven phase JS
}
type channelPage struct {
@@ -75,6 +77,7 @@ func (s *Server) base() pageData {
return pageData{
SiteTitle: s.cfg.SiteTitle,
Channels: channels,
Weather: currentWeather(time.Now()),
}
}
@@ -172,6 +175,66 @@ func (s *Server) handleChannel(w http.ResponseWriter, r *http.Request, ch Channe
s.render(w, "channel", data)
}
var (
demoVariants = []string{"rain", "petals", "jacaranda", "motes", "leaves"}
demoIntensities = []string{"light", "medium", "heavy"}
demoPhases = []string{"day", "dawn", "dusk", "night"}
)
type weatherDemoPage struct {
pageData
Variants []string
Intensities []string
Phases []string
Variant string
Intensity string
PhaseSel string
}
func pickOr(v string, allowed []string, fallback string) string {
for _, a := range allowed {
if v == a {
return v
}
}
return fallback
}
func seasonForVariant(v string) string {
switch v {
case "rain":
return "winter"
case "petals", "jacaranda":
return "spring"
case "motes":
return "summer"
case "leaves":
return "autumn"
}
return ""
}
func (s *Server) handleWeatherDemo(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
variant := pickOr(q.Get("variant"), demoVariants, "jacaranda")
intensity := pickOr(q.Get("intensity"), demoIntensities, "heavy")
phase := pickOr(q.Get("phase"), demoPhases, "day")
base := s.base()
base.Weather = Weather{Season: seasonForVariant(variant), Variant: variant, Intensity: intensity}
base.Phase = phase
s.render(w, "weather", weatherDemoPage{
pageData: base,
Variants: demoVariants,
Intensities: demoIntensities,
Phases: demoPhases,
Variant: variant,
Intensity: intensity,
PhaseSel: phase,
})
}
func (s *Server) render(w http.ResponseWriter, page string, data any) {
tpl, ok := s.tpls[page]
if !ok {