Skip to main content

Time Manager

Use withTimeManager() to add synchronized game time without adding methods to RpgMap. The server owns the canonical time. The client receives a map snapshot and infers the displayed time locally from elapsedMinutes, scale, paused, and serverTimestamp.

Register the Module

You can use the same module object on both sides:
For a client-only declaration, this also works:

Units and limits

There is one clock for the whole server: every map shares the same time, and pause() or set() applies to all of them. To keep a map out of the day night cycle (a cave, an interior), see Per map lighting.

Clock on screen

hud draws the clock on the client: a pill with the day and the hour, and a round medallion whose sky follows the hour (a sun that crosses it, a moon and stars at night, colors that change at dawn and dusk). It is off by default.
The client must register the same module (provideClientModules([TimeManagerModule])) and load the styles (import "@rpgjs/ui-css/index.css"). “Day N” counts the days since the start. The texts are the rpg.time.* keys (English and French are included). The catalogue of the GUI has it in Compositions / Game clock.

Server API

Use TimeManager from server hooks, events, or services:
Read the derived state:

Client API

Use ClientTimeManager for display logic:
The client does not write time. It projects the current display value from the last synchronized map snapshot.

Snapshot

The synchronized map field is internal and namespaced:
Game code should use TimeManager and ClientTimeManager instead of reading __rpgjsTime directly.

Lighting

When lighting.enabled is true, the server can apply map lighting from time phases:
A phase is merged into the lighting of the map: the light spots, the shadows and the other keys that the phase does not set are kept. If lighting is omitted or disabled, the time manager does not modify map lighting.

Day night cycle

Use dayNight to replace the phases by the continuous color grading of the DayNightCycle preset. The scene follows the hour of the time manager and the spots of the map are lit at night (see Lighting):
Two sets of phases exist, do not mix them up: The hooks onLightingPhaseChange and onPhaseChange (the same transition, the second one reads better for gameplay rules) receive those keys. The state exposes them too: state.phase and state.hourFloat (the hour with decimals, 18.5 is 18:30).

Per map lighting

The time manager lights every registered map. Override or disable it per map, like weather.maps:
A map can also opt out on its own side, in its lighting:

Client module

The client must register the same module (provideClientModules([TimeManagerModule])). Without it the client falls back to a local clock and shows the wrong hour: a warning is logged in the console when the server drives the cycle with the time manager. The client projects the time from the clock of the server, so a client whose clock is off still shows the same hour as the other players.

Weather Ambiences

When weather.enabled is true, the server can roll weather ambiences per map. Each ambience has a weight and a game-time duration. When the duration expires, the server rolls the next ambience and applies it with the existing map weather API.
maps[mapId] overrides the default weather table for that map. A weather: null ambience clears the map weather. If weather is omitted, disabled, or no table exists for a map, the time manager does not modify that map’s weather. Weather remains server-owned. Clients receive the regular weatherState map update and should read engine.sceneMap.weather() or engine.sceneMap.getWeather() for rendering.

Environment Hooks

Use hooks on withTimeManager() when the environment should drive gameplay rules from the plugin itself:
onBeforeWeatherChange() can return false to cancel the roll, or another { key, ambience } candidate to replace it. Initial map registration is silent: hooks run only after an actual time, lighting, or weather transition. Transition payloads include the current map so plugin hooks can update synchronized map state or trigger map-local systems. Events can react locally by declaring matching methods:
Global event hooks work too:
This keeps the environment logic centralized in the time plugin while still letting map events behave like Stardew Valley objects: crops grow on day changes, lamps react to lighting phases, and NPCs or interactables react to weather changes.