§ How to · with Picoo
How to make a weather system in Roblox
By Sametcan Tasgiran, Founder & Developer·Published ·Updated
The obvious way to make rain — a huge emitter covering the map — is also the most expensive way, and it still misses the player half the time.
Weather is server-owned state rendered locally, with the precipitation following the camera instead of covering the world.
Camera-follow precipitation
Rain and snow emitted in a small volume above the camera, so coverage is perfect at a fraction of the cost.
Server-owned state
One authoritative weather state so every player is in the same storm.
Smooth transitions
Atmosphere, lighting and emitter rates tweened between states instead of snapping.
Clouds
The Clouds instance configured where it actually works, with density tied to the weather state.
Indoor detection
A raycast upward stops rain falling through roofs.
Weather audio
Looping ambience that fades with intensity rather than switching on and off.
Files Picoo ships for this prompt
2 files · 190 lines · ~30s · 1 credit
WeatherService
State machine, schedule, replication, transition timing.
100 lines
WeatherClient
Camera-follow emitters, lighting tweens, indoor raycast, audio.
90 lines
Sample output: StarterPlayerScripts.WeatherClient
-- Rain over a whole map is thousands of particles, most of them somewhere the
-- player will never look. Emit a small volume ABOVE THE CAMERA instead and move
-- it every frame -- identical appearance, a fraction of the particles.
local rainPart = Instance.new("Part")
rainPart.Anchored, rainPart.CanCollide, rainPart.Transparency = true, false, 1
rainPart.Size = Vector3.new(60, 1, 60)
rainPart.Parent = workspace.CurrentCamera -- client-only, never replicates
RunService:BindToRenderStep("Weather", Enum.RenderPriority.Camera.Value + 1, function()
local cam = workspace.CurrentCamera
rainPart.CFrame = CFrame.new(cam.CFrame.Position + Vector3.new(0, 35, 0))
end)
-- Indoors: cast up from the player. Rain falling through a roof is the single
-- most noticeable weather bug and it is one raycast.
local function isSheltered(root: BasePart): boolean
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { root.Parent :: Instance, rainPart }
return workspace:Raycast(root.Position, Vector3.new(0, 60, 0), params) ~= nil
end
-- CLOUDS ONLY WORK PARENTED TO TERRAIN. Anywhere else the instance exists,
-- shows its properties, and renders nothing -- with no error to explain it.
local clouds = workspace.Terrain:FindFirstChildOfClass("Clouds")
or Instance.new("Clouds", workspace.Terrain)
clouds.Cover, clouds.Density = state.cloudCover, state.cloudDensityBuilding a weather system in Roblox
Weather is one of those systems where the obvious implementation and the correct one differ by an order of magnitude in cost.
The obvious version is a rain emitter sized to the map. It works, it is easy to reason about, and it spends almost all of its particles on volume nobody is looking at — while still producing gaps when a player sprints past the edge of the emitter. The correct version is smaller and local: a modest emitter volume parented to the camera, repositioned above it every frame. From inside it is indistinguishable, because the player can only ever see the rain immediately around them. It also never replicates, since the whole thing lives on the client.
What does need to be shared is the state. If weather affects visibility, spawns, or anything players compete over, everyone has to be in the same storm — so the server owns a small piece of state saying which weather is active and how far through the transition it is, and each client renders it. That split keeps the network cost at essentially nothing.
The Clouds instance deserves a specific warning. It only renders when parented directly to Terrain. Put it under Workspace or Lighting and it will sit there with every property visible and draw absolutely nothing, with no error and no warning. It is a fast hour to lose.
Two details separate convincing weather from obviously fake weather. First, raycast upward from the player and stop the rain when they are under a roof — precipitation falling through ceilings is the thing everyone notices immediately. Second, tween every transition. Atmosphere density, brightness and emitter rate moving together over several seconds reads as a storm arriving; the same values changing in a single frame reads as a bug.
See more on the Luau generator, the game builder, or browse the full blog.
Frequently asked
Should rain cover the whole map?+
No. A map-sized emitter spends thousands of particles on volume the player cannot see, and it still leaves gaps when they move fast. A small emitter volume parented to the camera and repositioned each frame looks identical from inside and costs a fraction as much.
Why do my Clouds not appear?+
The Clouds instance only renders when it is a direct child of Terrain. Parent it to Workspace or Lighting and it exists, shows all its properties, and draws nothing — with no error, which is why this one costs an hour.
Should weather run on the server or the client?+
The state on the server, the rendering on the client. Everyone needs to be in the same storm — weather that affects gameplay, visibility or spawns has to agree — but the particles themselves are local, so nothing gets replicated except which state is active.
How do I stop rain falling indoors?+
Raycast upward from the character. If it hits something, cut the emitter rate to zero or shrink the volume. It is one cast per frame per player and it removes the most obvious tell that weather is faked.
How should weather change?+
Tween, never snap. Atmosphere density, lighting brightness and emitter rate all interpolating over several seconds reads as weather; changing them in one frame reads as a bug. Keep transition duration in the state table so a storm can roll in slower than it clears.
Related Picoo prompts
How to set up lighting and atmosphere in Roblox
It is also full of settings that silently cancel each other out — an Atmosphere that makes your fog values do nothing, a Technology mode where your torches cast no shadow.
Roblox day night cycle
3 files · 90 lines · 28 seconds · 1 credit. 24-minute realtime full cycle, configurable.
particle effects in Roblox
Three rules cover almost everything: how bursts are fired, what sequences will accept, and the one multiplication that tells you what you are actually spending.