{
  "about": "Weatherglass sky spec, the master copy. Apps copy this file in and keep their own renderer; the TypeScript at weatherglass.gshaw.ca is the reference one. Colours are sRGB hex, mixed per channel in sRGB. Lengths are points (CSS pixels), times are seconds unless named otherwise.",
  "version": 1,
  "source": "Tides, Sky*.swift and Docs/sky-gradients.md, 2026-11-04",
  "referenceSize": {
    "width": 402,
    "height": 874,
    "note": "iPhone 17 in points. Particle counts are tuned for a screen this size."
  },
  "gradient": {
    "stops": [
      0,
      0.35,
      0.7,
      1
    ],
    "note": "Four stops down the screen's height. The top two carry weather and time of day; the bottom two stay dark in every combination so light text reads over them.",
    "palette": {
      "clear": {
        "dawn": [
          "#3c3f7a",
          "#8c5a7e",
          "#1a2a4e",
          "#0a1626"
        ],
        "day": [
          "#2b7ab0",
          "#3f8dbe",
          "#12294a",
          "#0a1626"
        ],
        "dusk": [
          "#3b2f63",
          "#8a4a63",
          "#172441",
          "#0a1626"
        ],
        "night": [
          "#0e1b33",
          "#14264a",
          "#0c1830",
          "#070f1d"
        ]
      },
      "cloudy": {
        "dawn": [
          "#4a4a63",
          "#7d6a72",
          "#1d2740",
          "#0a1626"
        ],
        "day": [
          "#5b7086",
          "#6e8298",
          "#1a2a42",
          "#0a1626"
        ],
        "dusk": [
          "#3f3a55",
          "#6b5568",
          "#182338",
          "#0a1626"
        ],
        "night": [
          "#151c2b",
          "#1f2838",
          "#10192a",
          "#070f1d"
        ]
      },
      "rain": {
        "dawn": [
          "#3d4457",
          "#5c6270",
          "#18202f",
          "#0a1220"
        ],
        "day": [
          "#46586e",
          "#566a80",
          "#16222f",
          "#0a1220"
        ],
        "dusk": [
          "#333a4e",
          "#4d4f63",
          "#141d2c",
          "#0a1220"
        ],
        "night": [
          "#10141f",
          "#182031",
          "#0c1422",
          "#06090f"
        ]
      },
      "snow": {
        "dawn": [
          "#7d7d98",
          "#938193",
          "#3a4a66",
          "#16233a"
        ],
        "day": [
          "#6f8194",
          "#7489a0",
          "#31465f",
          "#131f30"
        ],
        "dusk": [
          "#6d7396",
          "#8a7f9e",
          "#2c3c58",
          "#131f30"
        ],
        "night": [
          "#2a3348",
          "#3a465e",
          "#1a2436",
          "#0b1220"
        ]
      }
    },
    "ground": {
      "note": "The water under the tide curve in Tides: one shade deeper than each sky's bottom stop, blended like the stops, not changed by weather.",
      "dawn": "#101c33",
      "day": "#16324e",
      "dusk": "#121a30",
      "night": "#0a1424"
    }
  },
  "timeOfDay": {
    "note": "Keyframes, not bands. Each coloured sky holds for holdMinutes either side of sunrise or sunset and takes rampMinutes to arrive and to leave: night at sunrise - hold - ramp, dawn from sunrise - hold to sunrise + hold, day at sunrise + hold + ramp, and the same around sunset with dusk. Between two keyframes the stops mix linearly.",
    "holdMinutes": 30,
    "rampMinutes": 60
  },
  "transitions": {
    "note": "How the drawn sky follows a new target. Gradient changes ease in and out (cubic-bezier 0.42, 0, 0.58, 1). Effects taper with smoothstep over max(gradient duration, taper).",
    "revealSeconds": 1.5,
    "weatherChangeSeconds": 1,
    "blendChangeSeconds": 0.4,
    "taperSeconds": 3,
    "longestFallSeconds": 25,
    "softness": 0.25
  },
  "looks": {
    "note": "The nine distinct skies, in Tides' preview order. Wind is a moderate breeze so rain leans and snow drifts.",
    "windSpeedInMetersPerSecond": 8,
    "items": [
      {
        "id": "clear",
        "weather": "clear"
      },
      {
        "id": "cloudy",
        "weather": "cloudy"
      },
      {
        "id": "fog",
        "weather": "cloudy",
        "effect": "fog"
      },
      {
        "id": "light-rain",
        "weather": "rain",
        "effect": "light-rain"
      },
      {
        "id": "rain",
        "weather": "rain",
        "effect": "rain"
      },
      {
        "id": "heavy-rain",
        "weather": "rain",
        "effect": "heavy-rain"
      },
      {
        "id": "thunderstorm",
        "weather": "rain",
        "effect": "heavy-rain",
        "lightning": true
      },
      {
        "id": "freezing-rain",
        "weather": "snow",
        "effect": "rain"
      },
      {
        "id": "snow",
        "weather": "snow",
        "effect": "snow"
      }
    ]
  },
  "weatherKit": {
    "note": "WeatherKit's WeatherCondition raw names to a sky. Anything not listed is cloudy with no effect, the bucket that claims least.",
    "default": {
      "weather": "cloudy"
    },
    "conditions": {
      "clear": {
        "weather": "clear"
      },
      "mostlyClear": {
        "weather": "clear"
      },
      "hot": {
        "weather": "clear"
      },
      "frigid": {
        "weather": "clear"
      },
      "partlyCloudy": {
        "weather": "cloudy"
      },
      "mostlyCloudy": {
        "weather": "cloudy"
      },
      "cloudy": {
        "weather": "cloudy"
      },
      "breezy": {
        "weather": "cloudy"
      },
      "windy": {
        "weather": "cloudy"
      },
      "foggy": {
        "weather": "cloudy",
        "effect": "fog"
      },
      "haze": {
        "weather": "cloudy",
        "effect": "fog"
      },
      "smoky": {
        "weather": "cloudy",
        "effect": "fog"
      },
      "blowingDust": {
        "weather": "cloudy",
        "effect": "fog"
      },
      "drizzle": {
        "weather": "rain",
        "effect": "light-rain"
      },
      "sunShowers": {
        "weather": "rain",
        "effect": "light-rain"
      },
      "rain": {
        "weather": "rain",
        "effect": "rain"
      },
      "isolatedThunderstorms": {
        "weather": "rain",
        "effect": "rain",
        "lightning": true
      },
      "scatteredThunderstorms": {
        "weather": "rain",
        "effect": "rain",
        "lightning": true
      },
      "heavyRain": {
        "weather": "rain",
        "effect": "heavy-rain"
      },
      "tropicalStorm": {
        "weather": "rain",
        "effect": "heavy-rain"
      },
      "hurricane": {
        "weather": "rain",
        "effect": "heavy-rain"
      },
      "thunderstorms": {
        "weather": "rain",
        "effect": "heavy-rain",
        "lightning": true
      },
      "strongStorms": {
        "weather": "rain",
        "effect": "heavy-rain",
        "lightning": true
      },
      "freezingDrizzle": {
        "weather": "snow",
        "effect": "light-rain"
      },
      "freezingRain": {
        "weather": "snow",
        "effect": "rain"
      },
      "flurries": {
        "weather": "snow",
        "effect": "snow"
      },
      "sunFlurries": {
        "weather": "snow",
        "effect": "snow"
      },
      "snow": {
        "weather": "snow",
        "effect": "snow"
      },
      "heavySnow": {
        "weather": "snow",
        "effect": "snow"
      },
      "blowingSnow": {
        "weather": "snow",
        "effect": "snow"
      },
      "blizzard": {
        "weather": "snow",
        "effect": "snow"
      },
      "sleet": {
        "weather": "snow",
        "effect": "snow"
      },
      "wintryMix": {
        "weather": "snow",
        "effect": "snow"
      },
      "hail": {
        "weather": "snow",
        "effect": "snow"
      }
    }
  },
  "effects": {
    "frameRate": 30,
    "noise": "Every particle is placed by unit(index, salt): SplitMix64 of index * 1000003 + salt, the top 53 bits over 2^53, so the same index draws the same particle in every renderer. A pair [a, b] in this section means a + b * unit(index, salt). The salts are fixed per property; see the renderer.",
    "rain": {
      "kinds": {
        "light-rain": {
          "count": 50,
          "length": 12,
          "speed": 650,
          "opacity": 0.22
        },
        "rain": {
          "count": 110,
          "length": 18,
          "speed": 850,
          "opacity": 0.27
        },
        "heavy-rain": {
          "count": 220,
          "length": 26,
          "speed": 1050,
          "opacity": 0.32
        }
      },
      "nearEvery": 3,
      "farDepth": 0.65,
      "farOpacity": 0.6,
      "nearLineWidth": 1.2,
      "farLineWidth": 0.8,
      "lengthJitter": [
        0.75,
        0.5
      ],
      "paceJitter": [
        0.85,
        0.3
      ],
      "galeInMetersPerSecond": 20,
      "maxSlant": 0.36
    },
    "snow": {
      "count": 80,
      "radius": [
        1.2,
        2.3
      ],
      "fall": [
        22,
        18
      ],
      "driftPerMeterPerSecond": 3,
      "maxWindInMetersPerSecond": 15,
      "sway": [
        8,
        16
      ],
      "swayRate": [
        0.15,
        0.35
      ],
      "opacity": [
        0.35,
        0.45
      ],
      "margin": 30
    },
    "fog": {
      "bands": [
        {
          "center": 0.1,
          "height": 0.16,
          "speed": 7,
          "opacity": 0.14
        },
        {
          "center": 0.25,
          "height": 0.2,
          "speed": -5,
          "opacity": 0.12
        },
        {
          "center": 0.41,
          "height": 0.14,
          "speed": 9,
          "opacity": 0.1
        }
      ],
      "widthScale": 1.6,
      "spacing": 0.8
    },
    "lightning": {
      "period": 9,
      "chance": 0.7,
      "peakOpacity": 0.22,
      "reach": 0.6,
      "firstPulse": 0.08,
      "secondPulse": [
        0.16,
        0.5
      ]
    },
    "stars": {
      "count": 90,
      "reach": 0.6,
      "spread": 1.4,
      "radius": [
        0.4,
        0.9
      ],
      "brightness": [
        0.3,
        0.6
      ],
      "twinkleShare": 0.3,
      "twinkleDepth": 0.55,
      "breatheDepth": 0.12,
      "rate": [
        0.15,
        0.35
      ]
    }
  }
}
