roblox-performance
Use when optimizing a Roblox game for better frame rates, reducing lag, improving server or client performance, diagnosing FPS drops, handling large worlds, or when asked about streaming, draw calls, object pooling, LOD, MicroProfiler, or expensive loop operations.
By sentinelcore · 680 installs
npx skills add sentinelcore/roblox-skills --skill roblox-performance
Source repository · Upstream listing
Roblox Performance Optimization
Quick Reference
Technique Impact When to Use
StreamingEnabled High Large open worlds
Object pooling High Frequent spawn/destroy
Cache references outside loops High Heartbeat/RenderStepped
task.wait() over wait() Medium All scripts
MeshParts over Unions Medium Many unique shapes
LOD (hide at distance) Medium Complex models
Anchor static parts Medium Reduce physics budget
Limit PointLights High Any scene with many lights
StreamingEnabled
Enable for large worlds — engine sends only nearby parts to the client.
Parts outside the radius are nil on the client — always guard with if part then .
Set Model.LevelOfDetail = Disabled on models that must always be present.
Pre stream an area before a cutscene or teleport:
Hot Path Loop Optimization
RunService.Heartbeat and RenderStepped fire every frame (~60×/sec). Keep them lean.
Bad — searching the hierarchy every frame
Good — cache references once, do work only when needed
Rules:
Cache game:GetService() and part references outside the loop.
Never call FindFirstChild , GetChildren , or GetDescendants inside Heartbeat.
Throttle work that doesn't need every frame:
task Library vs Legacy Scheduler
Always use task — wait() and spawn() throttle under load and are deprecated.
Legacy Modern
wait(n) task.wait(n)
spawn(fn) task.spawn(fn)
delay(n, fn) task.delay(n, fn)
coroutine.wrap(fn)() task.spawn(fn)
Object Pooling
Reuse instances instead of creating and destroying them every frame.
Level of Detail (LOD)
Built in: Set Model.LevelOfDetail = Automatic — engine merges distant parts into an imposter mesh automatically.
Manual distance based LOD:
Reducing Draw Calls
Merge parts that share a material into one MeshPart (export from Blender as .fbx ).
MeshParts batch better than CSG Unions (Unions re triangulate at runtime).
Reuse materials — 10 parts sharing SmoothPlastic costs far less than 10 unique textures.
Use TextureId on a single MeshPart instead of stacking Decals on many parts.
Profiling with MicroProfiler
1. Press Ctrl+F6 in game to open MicroProfiler.
2. Press Ctrl+P to pause and inspect a single frame.
3. Look for wide bars in heartbeatSignal (Lua), physicsStepped (physics), or render (GPU).
4. Label your own code:
Common FPS Killers
Cause Fix
Thousands of individual parts Merge into MeshParts
Unanchored static geometry Anchored = true on anything that never moves
Many PointLight / SpotLight instances Limit to ~10–20 dynamic lights per area
High rate ParticleEmitters Lower Rate and Lifetime ; disable when off screen
wait() under heavy load Replace with task.wait()
FindFirstChild chains inside Heartbeat Cache on load
StreamingEnabled off on large maps Enable it
Model.LevelOfDetail = Disabled everywhere Use Automatic where safe
Common Mistakes
Mistake Fix
workspace:FindFirstChild every frame Cache reference on character/model load
Destroying and re creating bullets/effects Use an object pool
wait() in tight loops task.wait()
All parts with unique materials Standardize to a small set of shared materials
ParticleEmitters enabled off screen Disable Enabled when particle source is not visible
Physics on decorative parts Anchored = true