Skip to content

Weather App

Full documentation for the tablet Weather app — live weather display with animated particles and admin controls integrated with Renewed-Weathersync.

Overview

The Weather app displays current in-game weather with animated canvas particles, temperature, humidity, wind stats, and a digital clock. It integrates with the Renewed-Weathersync resource for live data and falls back to static data if the resource is not found. Players with command.weather ACE permission get an admin control panel to change weather, set time, toggle blackout, and freeze time.

Architecture

┌─────────────┐     NUI      ┌──────────────┐   GlobalState   ┌──────────────────┐
│  React UI   │ ──────────→  │ client/      │ ←────────────── │ Renewed-         │
│  (Weather)  │              │ tablet.lua   │                 │ Weathersync      │
│             │ ←──────────  │              │   TriggerServer │ (server/weather) │
│  data       │   SendNUI    │ 8 callbacks  │ ──────────────→ │                  │
│  isAdmin    │              │              │                 │ GlobalState:     │
│  adminData  │              └──────────────┘                 │  .weather        │
└─────────────┘                       │                      │  .currentTime    │
                                      │                      │  .freezeTime     │
                                      ▼                      │  .blackOut       │
                              ┌──────────────┐               └──────────────────┘
                              │ server/      │
                              │ weather_     │──→ lib.callback.await('Renewed-Weathersync:...')
                              │ control.lua  │──→ GlobalState.blackOut = not GlobalState.blackOut
                              │              │──→ GlobalState.freezeTime = not GlobalState.freezeTime
                              │ (91 lines)   │──→ GlobalState.currentTime = { hour, minute }
                              └──────────────┘

Files

FilePurpose
ui/src/apps/Weather/index.jsxReact weather UI: animated particles, display, admin panel (534 lines)
client/tablet.lua8 NUI callbacks for weather data + admin commands (lines 161–250)
server/weather_control.lua7 admin server events with ACE permission checks (91 lines)
config/config.lua(No weather config — uses Renewed-Weathersync config)

Data Flow

1. Load Weather Data

WeatherApp mounts
  → nuiFetch('weather:getData')
  → client/tablet.lua reads GlobalState.weather + GlobalState.currentTime
  → Returns:
    {
      source: 'Renewed-Weathersync' | 'fallback',
      weather: 'EXTRASUNNY' | 'CLOUDS' | ...,
      hour: 14,
      minute: 30,
      windSpeed: 0.1,
      windDirection: 0,
      hasSnow: false,
      timeLeft: 120,       -- minutes until weather change
    }
  → React sets data + source
  → If source = 'Renewed-Weathersync' → "Live" badge (green)
  → If fallback → "Static · Resource not found" badge (grey)

2. Auto-Refresh

Every 15 seconds:
  → nuiFetch('weather:getData') → updates display
  → nuiFetch('weather:getQueue') → updates admin panel state

3. Admin Check

WeatherApp mounts
  → nuiPost('weather:checkAdmin')
  → client/tablet.lua → TriggerServerEvent('wtf_group:server:weather:checkAdmin')
  → server/weather_control.lua: IsPlayerAceAllowed(source, 'command.weather')
  → TriggerClientEvent('wtf_group:client:weather:adminStatus', src, isAdmin)
  → SendNUIMessage({ action: 'weather:adminStatus', isAdmin })
  → React shows/hides "Admin" button

4. Admin: Set Weather Type

Admin clicks weather type button (e.g., RAIN)
  → nuiPost('weather:setType', { index: 1, weatherType: 'RAIN' })
  → client/tablet.lua → TriggerServerEvent('wtf_group:server:weather:setType', 1, 'RAIN')
  → server/weather_control.lua: lib.callback.await('Renewed-Weathersync:server:setWeatherType', src, 1, 'RAIN')
  → Renewed-Weathersync updates GlobalState.weather
  → All clients receive new weather state
  → TriggerClientEvent('wtf_group:client:weather:controlSuccess', src, 'setType', 'RAIN')
  → SendNUIMessage({ action: 'weather:controlResult', success: true, ... })
  → React refreshes data after 300ms

5. Admin: Set Time

Admin enters hour/minute → clicks "Set Time"
  → nuiPost('weather:setTime', { hour: 14, minute: 30 })
  → client → server: TriggerServerEvent('wtf_group:server:weather:setTime', 14, 30)
  → server: GlobalState.currentTime = { hour = 14, minute = 30 }
  → Renewed-Weathersync reads GlobalState.currentTime on all clients
  → Game time updates for everyone

6. Admin: Toggle Blackout

Admin clicks blackout toggle
  → nuiPost('weather:toggleBlackout')
  → client → server: TriggerServerEvent('wtf_group:server:weather:toggleBlackout')
  → server: GlobalState.blackOut = not GlobalState.blackOut
  → All clients: city lights turn on/off

7. Admin: Toggle Freeze Time

Admin clicks freeze time toggle
  → nuiPost('weather:toggleFreezeTime')
  → client → server: TriggerServerEvent('wtf_group:server:weather:toggleFreezeTime')
  → server: GlobalState.freezeTime = not GlobalState.freezeTime
  → Game clock pauses/resumes for everyone

Weather Types

IDIconLabelTemp (°F)HumidityParticle
EXTRASUNNY☀️Extra Sunny8825%sun
CLEAR☀️Clear8235%sun
CLEARINGClearing7250%sun
CLOUDS☁️Cloudy7055%cloud
OVERCAST☁️Overcast6465%cloud
NEUTRAL☁️Neutral6850%cloud
RAIN🌧️Rainy6280%rain
THUNDER⛈️Thunderstorm5890%thunder
SNOW❄️Snow3070%snow
SNOWLIGHT❄️Light Snow3475%snow
BLIZZARD❄️Blizzard2280%blizzard
XMAS🎄Christmas2870%snow
FOGGY🌫️Foggy6585%fog
SMOG🌫️Smog7860%fog

Particle Types

Canvas-based animated particles rendered via WeatherParticles component:

TypeBehaviorMax Particles
sunConcentric glowing rings with slow pulseN/A (no particles)
rainDiagonal falling lines (blue-white)80
thunderRain + random white flash overlay80
snowRotating falling circles (white-blue)50
blizzardSnow + horizontal drift + more particles120
fogRadial gradient blobs drifting right8
cloudLarge radial gradient blobs drifting right8

Admin Panel

Two-column layout available to players with command.weather ACE permission:

Left Column: Time Control

  • Digital clock display — current hour/minute in large font
  • Hour/Minute inputs — numeric inputs (0–23, 0–59)
  • Set Time button — applies the entered time
  • Quick time buttons — Morning (9AM), Noon (12PM), Evening (6PM), Night (10PM)

Left Column: Controls

  • Freeze Time toggle — pause/resume game clock
  • Blackout toggle — disable/enable city lights

Right Column: Weather Control

  • Weather type grid — 14 weather types in a 5-column grid, active type highlighted
  • Current State panel — 6 stat cards:
    • Weather (icon + label)
    • Wind (mph)
    • Time (digital)
    • Time Left (minutes until weather change)
    • Blackout (ON/OFF)
    • Time Frozen (YES/NO)

Accessing the Admin Panel

  1. Player opens Weather app
  2. If ACE command.weather is granted, "Admin" button appears (top-right)
  3. Click "Admin" → admin panel overlays the weather display
  4. Click "Weather View" to return to the normal display

NUI Callbacks

CallbackDataDescription
weather:getDataGet current weather from GlobalState (Renewed-Weathersync or fallback)
weather:checkAdminCheck if player has command.weather ACE permission
weather:setType{ index, weatherType }Set weather type at queue index
weather:setDuration{ index, duration }Set event duration at queue index
weather:removeEvent{ index }Remove weather event at queue index
weather:toggleBlackoutToggle city blackout on/off
weather:toggleFreezeTimeToggle time freeze on/off
weather:setTime{ hour, minute }Set in-game time
weather:getQueueGet current weather queue state (admin panel poll)

Server Events

EventParametersACE RequiredDescription
wtf_group:server:weather:checkAdminNoReturns admin status to client
wtf_group:server:weather:setTypeindex, weatherTypecommand.weatherSets weather type via Renewed-Weathersync
wtf_group:server:weather:setDurationindex, durationcommand.weatherSets event duration via Renewed-Weathersync
wtf_group:server:weather:removeEventindexcommand.weatherRemoves weather event
wtf_group:server:weather:toggleBlackoutcommand.weatherToggles GlobalState.blackOut
wtf_group:server:weather:toggleFreezeTimecommand.weatherToggles GlobalState.freezeTime
wtf_group:server:weather:setTimehour, minutecommand.weatherSets GlobalState.currentTime

Client Events (Received)

EventDataDescription
wtf_group:client:weather:adminStatusisAdminAdmin check result
wtf_group:client:weather:controlSuccessaction, resultAdmin action succeeded
wtf_group:client:weather:controlErroraction, messageAdmin action failed

NUI Messages (Received by React)

ActionDataDescription
weather:adminStatus{ isAdmin }Show/hide admin button
weather:controlResult{ success, action, result/message }Admin action feedback toast

Renewed-Weathersync Integration

The weather app reads from Renewed-Weathersync's GlobalState bag replication:

GlobalState KeyTypeDescription
weather{ weather, windSpeed, windDirection, hasSnow, time }Current weather event
currentTime{ hour, minute }Current in-game time
freezeTimebooleanWhether time is frozen
blackOutbooleanWhether city lights are off
timeScalenumberTime progression speed

No server roundtrip needed — the client reads GlobalState directly (bag replication).

Admin Commands (via server)

Uses Renewed-Weathersync's built-in callbacks:

  • lib.callback.await('Renewed-Weathersync:server:setWeatherType', src, index, weatherType)
  • lib.callback.await('Renewed-Weathersync:server:setEventTime', src, index, duration)
  • TriggerServerEvent('Renewed-Weather:server:removeWeatherEvent', index)

Fallback Mode

If Renewed-Weathersync is not running:

  • GlobalState.weather returns nil
  • App falls back to static data: { weather: 'CLOUDS', hour: 12, minute: 0, ... }
  • Source badge shows "Static · Resource not found"
  • Admin panel still works (controls GlobalState directly)

UI Features

  • Animated Canvas Particles — 6 particle types with physics, fading, rotation
  • Dynamic Background — gradient changes per weather type
  • Large Weather Icon — with glow animation pulsing effect
  • Digital Clock — JetBrains Mono font, large display
  • Stat Cards — humidity, wind speed, wind label with glass morphism
  • Source Badge — green "Live" or grey "Static" indicator
  • Admin Button — visible only to ACE-authorized players
  • Admin Feedback Toasts — success (green) / error (red) slide-in notifications
  • Auto-Refresh — updates every 15 seconds

Time of Day Labels

Hour RangeLabel
5–7Dawn
8–11Morning
12–16Afternoon
17–19Dusk
20–21Evening
22–4Night

Wind Labels

Speed (game units)MPHLabel
≤ 0.1≤ 2Calm
≤ 0.5≤ 11Light Breeze
≤ 1.0≤ 22Breezy
≤ 3.0≤ 67Windy
≤ 8.0≤ 179Strong Wind
> 8.0> 179Storm

ACE Permission

To grant weather admin access, add to your server.cfg:

add_ace group.admin command.weather allow

Or for specific principals:

add_ace principal.youradmin command.weather allow

Notes

  • Weather data is read from GlobalState (no server roundtrip) — updates are instant
  • Admin actions modify GlobalState on the server — changes propagate to all clients
  • The weather:getQueue callback polls GlobalState for current state (not the internal Renewed-Weathersync queue)
  • Particle canvas uses requestAnimationFrame — pauses when tab is hidden
  • The app auto-refreshes every 15 seconds when open
  • Temperature values are display-only (not synced from Renewed-Weathersync)
  • Wind direction is tracked but not displayed in the current UI
  • Admin panel overlays the weather view — click "Weather View" to return

AIFAZI — FiveM Resources