hex-world
    Preparing search index...

    Class ClimateData

    Per-cell climate state for a hex map, in one GPU-sampled texture.

    Two tiers, mirroring how FogData splits live and remembered state. Base is the map's static climate — the temperature and moisture fields the generator computed, which never change for a given map. Seasonal is the derived state a SeasonCycle rewrites as the year turns: how deep the snow lies and how cold it has become.

    The split is what makes seasons cheap. The base fields are written once; the seasonal pass reads them, applies the year's phase, and writes two bytes per cell. Nothing regenerates and no geometry rebuilds.

    State is stored as a DataTexture (RGBA) that shader materials sample by the cellIndex attribute every hex-world geometry already carries: R = base temperature (0–1), G = base moisture (0–1), B = snow depth (0–1), A = season-adjusted temperature (0–1).

    Note what is not here: whether the water has frozen. Every liquid freezes at its own freezePoint, so a single "is frozen" byte could only ever be right about one of them. The season writes the temperature instead and each liquid — and isFrozen — reads its own answer out of it.

    The CPU side of every channel is readable through temperature, moisture, snowDepth and effectiveTemperature — deliberately the same bytes the shaders sample, so a game's "is this hex snowed in" answer and the white pixels on screen can never drift apart.

    // Generation fills the base fields…
    const climate = new ClimateData(map.width, map.height);
    generateMap(map, { climateData: climate }, seed);

    // …a season cycle derives the rest.
    seasons.setPhase(0.0); // midwinter
    seasons.apply(climate);

    // Gameplay reads exactly what the player sees.
    if (climate.snowDepth(col, row) > 0.5) moveCost += 2;
    Index

    Constructors

    Properties

    texture: DataTexture

    The GPU texture sampled by climate-aware shader materials.

    width: number
    height: number
    temperatureOptions: TemperatureModelOptions | null = null

    The options that reproduce the base temperature field, recorded by generateMap when it fills this instance (including the jitterChannel it picked at random). Save this object — it is tens of bytes — and ClimateData.fromMap rebuilds the base tier exactly on load, which is why serialize does not write the dense field.

    Null when the base fields were supplied some other way.

    Accessors

    • get rawData(): Uint8Array

      Raw RGBA bytes; index as [(row * width + col) * 4].

      Returns Uint8Array

    Methods

    • Writes the base temperature field (0–1, indexed row * width + col).

      Parameters

      • field: Float32Array

      Returns void

    • Writes the base moisture field (0–1, indexed row * width + col).

      Parameters

      • field: Float32Array

      Returns void

    • Base temperature at a cell, 0 (polar) – 1 (equatorial). Out-of-bounds reads 0.

      Parameters

      • col: number
      • row: number

      Returns number

    • Base moisture at a cell, 0–1. Out-of-bounds reads 0.

      Parameters

      • col: number
      • row: number

      Returns number

    • Snow lying on a cell, 0 (bare) – 1 (deep). Out-of-bounds reads 0.

      Parameters

      • col: number
      • row: number

      Returns number

    • The cell's temperature this season — base temperature after the year's swing, on the same 0–1 scale. This is what a liquid's freezePoint is compared against, and what the shaders read out of the A channel. Out-of-bounds reads 0.

      Parameters

      • col: number
      • row: number

      Returns number

    • Whether a liquid with the given freeze point has frozen at this cell — the gameplay question ("can the caravan cross here?"). Pass the descriptor's freezePoint; undefined never freezes, matching how the shaders read a negative uFreezePoint.

      Parameters

      • col: number
      • row: number
      • OptionalfreezePoint: number

      Returns boolean

      const water = descriptors.find(d => d.id === 'water');
      if (climate.isFrozen(col, row, water.freezePoint)) allowCrossing();
    • Overwrite one cell's snow depth (0–1). Use for scripted or gameplay-driven snow.

      Parameters

      • col: number
      • row: number
      • depth: number

      Returns void

    • Overwrite one cell's season-adjusted temperature (0–1).

      Parameters

      • col: number
      • row: number
      • value: number

      Returns void

    • Call once per frame before rendering — uploads the texture if anything changed.

      Returns void

    • Serializes the seasonal tier — snow depth and season-adjusted temperature — as a run-length blob.

      The base fields are deliberately not written: they are a deterministic function of the map and its TemperatureModelOptions, so saving the options (tens of bytes) and calling ClimateData.fromMap on load reproduces them exactly, where the dense field would cost a byte per cell. Snow is genuine runtime state that a campaign accumulates, and both channels run-length well — a summer map collapses to a handful of bytes.

      Returns Uint8Array

    • Restores a seasonal tier written by serialize, leaving the base temperature and moisture fields untouched.

      Throws if the blob is not climate data, is a newer format version, or was saved for a differently-sized map.

      Parameters

      • data: Uint8Array

      Returns void

    • Clears the seasonal tier back to bare ground and open water; base fields are kept.

      Returns void