hex-world
    Preparing search index...

    Class HexWorld

    Batteries-included entry point: renderer, camera + RTS controls, lighting, terrain/liquid materials, chunk streaming, per-frame picking, and cell overlays — wired the same way the à-la-carte API would be by hand. Every piece stays reachable (scene, camera, renderer, chunks, overlays, picker, …), so you can drop to the lower-level API at any point.

    const world = await HexWorld.create({ container: document.body });
    FbmPlugin.generate(world.map, FbmPlugin.defaultConfig, Date.now());
    world.chunks.markDirtyCells([]); // or edit through world.map.edit(...)
    world.onFrame = () => { if (world.hoveredCell) … };
    Index

    Properties

    scene: Scene
    camera: PerspectiveCamera
    renderer: WebGLRenderer
    layout: HexLayout
    hashGrid: HexHashGrid
    chunks: ChunkManager
    picker: HexPicker
    sunShadows: SunShadowRig | null = null

    Shadow-casting sun rig when the shadows option was set (and default lights are on); null otherwise.

    onFrame: ((dt: number) => void) | null = null

    Called once per frame after chunks/picking update, before rendering.

    events: Emitter<HexWorldEventMap> = ...

    Typed world events — pointer/cell interaction, the frame tick, chunk streaming, and (after trackUnits) unit movement. Subscribing beats wiring raycasts and callbacks by hand, and unlike the single-slot onFrame / onCellEnter hooks any number of systems can listen.

    world.events.on('cellClick', ({ col, row, button }) => {
    if (button === 0) select(col, row);
    });
    const off = world.events.on('cellHover', ({ cell }) => showTooltip(cell));
    off(); // unsubscribe

    dispose drops every listener before tearing anything down, so no events fire against a half-disposed world.

    terrainMaterialOptions: TerrainMaterialOptions

    The material options used for terrain materials this world builds — reuse for loadHexPack so pack materials match the scene lighting.

    Accessors

    • get hoveredCell(): { col: number; row: number } | null

      Cell under the pointer, updated every frame while the loop runs.

      Returns { col: number; row: number } | null

    • get wind(): Wind

      The world's shared wind — the one vector behind cloud drift, rain slant, plant sway, and the ripples marching across open water. Always present, so it can be configured before or after anything that reads it; switch it on with setWind.

      world.wind.base is the same THREE.Vector2 as world.weather.wind.

      Returns Wind

    • get climate(): ClimateData | null

      Per-cell climate once seasons are on — the same bytes the shaders sample, so climate.snowDepth(col, row) is exactly what the player can see.

      Returns ClimateData | null

    Methods

    • True if the terrain index belongs to any liquid type.

      Parameters

      • terrain: number

      Returns boolean

    • Start the render loop (no-op if already running).

      Returns void

    • Re-emit a UnitManager's events through events, so unit movement arrives alongside cell and chunk events instead of on a second emitter the rest of the game has to know about. Returns an unsubscribe function; dispose also drops every forward this world set up.

      HexWorld does not own the manager — construct it as usual and hand it over:

      const units = new UnitManager({ scene: world.scene, map: world.map, layout: world.layout, fogData: world.fog ?? undefined });
      world.trackUnits(units);
      world.events.on('unitArrived', ({ unit }) => endTurn(unit));

      Parameters

      Returns Unsubscribe

    • Stop the render loop (state is kept; call start() to resume).

      Returns void

    • Swap in a different map; chunks rebuild, climate re-derives, camera recenters.

      Parameters

      Returns void

    • Swap the terrain set at runtime (custom terrain, loaded pack): rebuilds the texture atlas + terrain material and re-derives all lookups. The previous terrain material is disposed unless you pass keepOldMaterial.

      Parameters

      Returns Promise<void>

    • Adopt already-resolved terrain state (e.g. from loadHexPack, which builds its own material). Returns the previous material WITHOUT disposing it — the caller decides, since it may be shared.

      Parameters

      Returns ShaderMaterial

    • Toggle or restyle the shader hex grid overlay drawn by the terrain material — crisp anti-aliased cell borders that fade with camera distance. true/false toggles with current styling; an options object restyles (and enables unless enabled: false). Survives terrain material swaps.

      Parameters

      Returns void

      world.setHexGrid(true);
      world.setHexGrid({ color: 0xffffff, opacity: 0.25, fadeEnd: 120 });
      world.setHexGrid(false);
    • Toggle or restyle the sedimentary bedding the terrain shader draws on bare rock — horizontal layers picking out every cliff face, terrace and carved channel side. On by default; false turns it off, an options object restyles (and enables unless enabled: false). Survives terrain material swaps.

      Parameters

      Returns void

      world.setCliffStrata({ scale: 5, seam: 0.3 });  // finer, sharper beds
      world.setCliffStrata(false);
    • Point the sun (day/night hook): updates the shadow rig AND the terrain material's hand-rolled light direction in one call so shading and shadows never disagree. dirTowardSun points from the scene toward the sun. Survives terrain material swaps.

      Parameters

      • dirTowardSun: Vector3

      Returns void

    • Jump the world clock to a time of day (0 = midnight, 0.5 = noon) and relight the scene. Creates a paused DayNightCycle on first use if the dayNight option wasn't set — unpause via world.dayNight.paused = false to let time flow.

      Parameters

      • time: number

      Returns void

    • Every material the sky hazes into its horizon color: terrain, roads, each liquid layer, and the scatter materials (which setSky runs through attachAtmosphere, since stock three materials have no haze of their own). Hand it to a SkyDome you build yourself, or to configureAtmosphere for distance haze without a dome.

      Returns Generator<Material<MaterialEventMap>>

    • Replace the scatter definitions at runtime and rebuild the scatter of every loaded chunk. New materials get the haze, snow, season, and wind bindings the originals were given at construction, so a definition added from an editor's scatter builder looks like one from the start.

      Parameters

      Returns void

    • Enable, restyle, or (with false) remove the gradient sky dome and its matching distance haze. Options accumulate across calls, and the dome immediately picks up the current time of day and weather.

      groundTint defaults to the terrain palette's average color so the horizon haze matches the biome — pass it explicitly to override. Scatter materials are patched with the same shader haze so they recede with the terrain; do the same for your own unit and prop materials with attachAtmosphere.

      Parameters

      Returns SkyDome | null

      world.setSky(true);
      world.setSky({ fog: { near: 40, far: 120 }, stars: false });
      world.setSky(false);
    • Enable, restyle, or (with false) remove the map skirt — the wall of cut earth that gives the map a bottom and four sides instead of ending where its triangles stop.

      The geometry options that have to agree with the terrain (perturbStrength, noiseScale, elevationScale, elevPerturbStrength) are taken from the world's own geometryOptions unless you override them — pass them by hand only if you are also building terrain by hand, since a mismatch tears the seam along the entire edge.

      Parameters

      Returns MapSkirt | null

      world.setSkirt(true);
      world.setSkirt({ depth: 4, bandScale: 2.4 }); // deeper block, finer strata
      world.setSkirt(false);
    • Every material that renders seasonal snow or ice: terrain, each liquid layer, and the scatter materials (which setSeasons runs through attachSnow, since stock three materials have no snow of their own).

      Roads are deliberately absent — a road under snow is a road you can't see, and hiding the network the player routes on is worse than the realism is worth. Hand your own prop materials to attachSnow if you want them white.

      The seasonal foliage tint is not attached here either, and that is the point: whether a plant turns in autumn is what tells a broadleaf from a pine. Call attachSeasonalTint on the scatter materials that should turn — before or after setSeasons, since both effects share one climate binding.

      Returns Generator<Material<MaterialEventMap>>

    • Enable, restyle, or (with false) remove seasons: a year clock, snow that accumulates and melts, and liquids that freeze at their own freezePoint. Options accumulate across calls.

      Supply climate when the map was generated with a climateData sink — that field is the one the biomes were assigned from. Without it the base temperature is rebuilt via ClimateData.fromMap, which matches only if you pass the same temperature options the generator used.

      The cycle advances with the day clock and re-applies every HexWorldSeasonOptions.applyInterval seconds; scrub it directly with setSeason.

      Parameters

      Returns SeasonCycle | null

      // Generated map: hand over the field the biomes came from.
      const climate = new ClimateData(map.width, map.height);
      generateMap(map, { climateData: climate }, seed);
      world.setSeasons({ daysPerYear: 8 }, climate);
      world.setSeasons({ noise: 0.2, snowThreshold: 0.3 }); // restyle
      world.setSeasons(false); // off
      // Grass and any tinted scatter turn through the year; tune the palette.
      world.setSeasons({ foliage: { autumn: 0xd2601a, bareTemp: 0.3 } });
    • Jump the year clock and repaint immediately — the turn-based entry point ("day 214 of the migration"). Creates a paused cycle if the seasons option wasn't set, so a game that drives its own calendar never needs the real-time clock at all.

      Parameters

      • phase: number

      Returns void

    • Set the weather: drifting cloud shadows on the terrain plus a matching rain/snow layer that falls under the denser clouds and follows the camera (world-anchored — panning doesn't drag the rain). Creates the WeatherSystem on first use; returns it for fine-grained control (intensity ramps, wind changes).

      'clear' means no precipitation, not an empty sky: it keeps scattered fair-weather cloud shadows drifting over the ground. Pass { clouds: false } for a cloudless one.

      Parameters

      Returns WeatherSystem

      world.setWeather('rain');
      world.setWeather('snow', { intensity: 0.6 });
      world.setWeather('clear'); // sun and drifting cloud shadows
      world.setWeather('clear', { clouds: false }); // nothing in the sky at all
    • Every material the wind can move: each liquid layer, and the scatter materials. Materials that carry none of the wind uniforms are skipped by setMaterialWind, so this can be handed out whole.

      The terrain is absent because a hillside does not move, and the road with it. What lives here is water — which drifts and roughens — and whichever plants have been given attachWindSway.

      Returns Generator<Material<MaterialEventMap>>

    • Enable, restyle, or (with false) still the world's wind: one vector that drifts the cloud deck, slants the rain, bends the plants, and marches the ripples across open water. Options accumulate across calls; returns the shared Wind for direct control (world.wind.setPolar(…) mid-storm).

      Which plants bend is yours to say. This drives every material that carries attachWindSway and attaches the patch to none of them — the same division as the seasonal foliage tint, and for the same reason: that a hedge answers the wind and a boulder does not is a fact about your scatter, not about the renderer. Water needs no such call; every liquid material already carries the uniforms and sits at zero until this is switched on.

      The wind itself exists and advances from the first frame either way, which is why a shower gusts before anything on the ground is wired up to it.

      Parameters

      Returns Wind

      attachWindSway(broadleafMat, { height: 1.9 });
      attachWindSway(bushMat, { height: 0.5, stiffness: 1.2, amplitude: 0.16 });
      world.setWind({ heading: Math.PI * 0.25, speed: 4 });
      world.setWind({ gustiness: 0.7, gustPeriod: 4 });  // squally
      world.setWind(false); // dead calm
    • Set the faction roster and start drawing per-cell ownership: translucent faction tints with an outline around each faction's holdings. Creates the TerritoryLayer on first use and returns it for the claim/release calls; later calls just re-colour with the new roster.

      Ownership is stored in the map's metadata channel, so it serializes with the map — no companion file, and world.map round-trips through serializeMapJSON with the borders intact.

      Parameters

      Returns TerritoryLayer

      const territory = world.setFactions([
      { id: 'red', name: 'Kelmar', color: 0xdd4433 },
      { id: 'blue', name: 'Ossiran', color: 0x3377dd },
      ]);
      territory.claim(10, 10, 'red');
    • Set the resource types and start drawing per-cell deposits as instanced camera-facing icons — one draw call per type. Creates the ResourceLayer on first use and returns it for placement calls; later calls swap the type set.

      The world's fog (the fogData option) is wired in automatically, so icons hide on unexplored cells and dim on remembered ones along with the ground beneath them. Placement data lives in the map's metadata channel and serializes with the map.

      Parameters

      Returns ResourceLayer

      const resources = world.setResourceTypes(DEFAULT_RESOURCE_DESCRIPTORS);
      generateResources(world.map, DEFAULT_RESOURCE_DESCRIPTORS, seed, { isWater: world.isWater });
    • Attach or detach fog of war at runtime, across every layer that reads it — terrain, liquids, roads, scatter, and resource icons.

      Parameters

      Returns void

    • Hide unexplored cells (the fog's memory tier boundary), across terrain and resource icons alike. Independent of setDimExplored.

      Parameters

      • enabled: boolean

      Returns void

    • Dim explored-but-not-currently-visible cells — the remembered tier's ghost look — across terrain and resource icons alike.

      Parameters

      • enabled: boolean

      Returns void

    • Swap the liquid types at runtime (edited appearance, new custom liquid). Materials are resolved from the descriptors unless provided; previous liquid materials this world held are disposed unless still referenced by the new set.

      Parameters

      Returns void

    • Stop the loop and free everything this world created.

      Returns void