hex-world
    Preparing search index...

    Class SeasonCycle

    The year clock, and the pass that turns it into snow on the ground.

    Deliberately shaped like DayNightCycle one level up: a 0–1 phase where 0 is the darkest/coldest point and 0.5 the brightest/warmest, advance(dt) to run it, setPhase to scrub it, paused to freeze it.

    Seasons don't recompute climate — they bias it. The generator's temperature field already folds latitude, elevation, and noise into one 0–1 number per cell, so a season is a single subtraction against it:

    effective = base − amplitude(latitude) · winter
    

    with amplitude interpolating from SeasonOptions.polarAmplitude at the poles to SeasonOptions.equatorAmplitude at the equator. Snow lies where effective falls under SeasonOptions.snowThreshold; ice is left to each liquid's own freezePoint, since water and acid do not give up at the same cold. Because elevation cooling is already baked into base, mountains cross those thresholds first and keep their caps year-round, and the snowline walks down the map through autumn without a line of latitude appearing anywhere in the code.

    That is scope: 'continental', and it is right exactly when the map is big enough for one end to have a different climate from the other. On a valley it isn't: a snowline creeping across a few kilometres reads as a bug. So SeasonOptions.scope 'local' inverts which term dominates —

    effective = localSummer − localAmplitude · winter + (base − 0.5) · localVariation
    

    — and the map's own field, which was the climate, becomes a small stagger on top of a season the whole map shares. Every cell crosses each threshold within a few days of every other, so a hard winter strips every tree and spring blooms all of them, while the high ground still leads by a little.

    Nothing downstream knows which model ran. Snow, per-liquid ice, the foliage tint, blossom, precipitation and climate.snowDepth all read the same two bytes; the scope only changes what gets written into them.

    apply(climate) snaps every cell to the phase's target — deterministic, and what a turn-based game wants, where one turn is one day. apply(climate, dt) eases toward it at SeasonOptions.accumulationRate and SeasonOptions.meltRate, so snow builds and thaws over real seconds instead of popping between frames.

    // Real-time: rides the day clock.
    const seasons = new SeasonCycle({ daysPerYear: 8, dayLength: 120 });
    seasons.advance(dt);
    seasons.apply(climate, dt);
    // Turn-based: one hex per day, winter chasing you.
    seasons.setPhase(dayNumber / DAYS_IN_YEAR);
    seasons.apply(climate);
    // One valley, one season: the whole map turns together.
    const seasons = new SeasonCycle({ scope: 'local' });
    Index

    Constructors

    Properties

    daysPerYear: number

    Days in a full year.

    dayLength: number

    Real seconds per day — the day clock's dayLength.

    paused: boolean

    Freeze/unfreeze the phase (setPhase still works while paused).

    Accessors

    • get year(): number

      Whole years elapsed since construction — incremented as the phase wraps.

      Returns number

    Methods

    • Jump the year clock (value wraps into 0–1). Does not touch the year count.

      Parameters

      • phase: number

      Returns void

    • Advance the phase by whole days — the turn-based entry point.

      Parameters

      • days: number

      Returns void

    • Advance by dt real seconds, at dayLength seconds per day and daysPerYear days per year (no-op while paused). Feed it the same dt the DayNightCycle gets and the two clocks stay locked together.

      Parameters

      • dt: number

      Returns void

    • How far the current phase pulls temperature down at a given normalized latitude (0 = pole, 1 = equator). Exposed because gameplay that wants to ask "how cold will it be there in three weeks" should use the same curve the renderer does.

      Under 'local' scope the latitude is ignored, which is the whole point of that scope — one map, one season.

      Parameters

      • latitude: number

      Returns number

    • Rewrites every cell's snow depth and season-adjusted temperature from its base temperature and the current phase, then marks the texture for upload.

      Snow is eased because it accumulates; temperature is always written exact, because it is a reading rather than a quantity that piles up. Ice is not written at all — each liquid derives its own from the temperature against its freezePoint, which is how water can skin over while acid beside it stays liquid.

      Parameters

      Returns void