Engineering & Performance¶
raycin_races raycin_creator Transparent resmon-verified
Raycin Races is built to run lean. A server with 4 races active concurrently uses roughly 0.5 ms of server time per tick — less than a single GTA decoration prop costs to render. This page is a transparent breakdown of how the resource performs, written so server admins can verify the numbers with resmon themselves rather than taking marketing claims on faith.
💡 Why this page exists. Most FiveM scripts publish features but never publish performance. This one does — because if you're considering raycin_races for your server, you deserve to know what it'll cost you in CPU before you commit. Every number below comes from a code audit; the verification steps let you reproduce them.
Headline Numbers¶
| Surface | Idle | Typical race | Peak |
|---|---|---|---|
| Server | 0.10–0.15 ms | 0.40–0.80 ms (4 active races) | 2–3 % burst on race-start, clears in ~500 ms |
| Client Lua | 0.05–0.10 ms | 0.75–1.30 ms per frame | 1.5–2.2 ms (16-player race, every feature enabled) |
| NUI (browser) | ~0 ms | 1–2 ms per frame | One-time 100–300 ms render on first Custom List open |
Translation for non-engineers: - 0.5 % of one server thread for a busy 4-race server. Your remaining budget stays open for everything else you want to run. - 9–13 % of a 60-FPS frame budget in the worst-case 16-player race with every feature on. Invisible to players on any modern PC.
What "well-optimised" Actually Means Here¶
It's easy to claim "optimised". Here's what it actually means in this codebase:
- ✅ Idle ≤ 0.15 ms on both client and server when no races are running — the resource basically goes to sleep
- ✅ No always-on animations in freemode — every CSS keyframe is gated by race state, so the HUD doesn't paint when it's not visible
- ✅ No zombie threads — every
while true doloop respects race status, so threads die cleanly when a race ends. No leaks build up across multiple races - ✅ No per-frame NUI spam — HUD elements update only when their value changes, not 60 times per second
- ✅ Lazy disk I/O — vehicle presets load once on resource start, then live in memory. No repeated file reads
- ✅ ~600 KB total memory for an 8-room steady-state server. Cleans itself up on room end (no orphaned tables)
- ✅ O(1) player-to-room lookup — when a player disconnects, the server doesn't scan every room to find them, it goes straight there
- ✅ Single-pass validation — settings are sanitised once when you click Apply, not re-validated on every event
How to Verify These Numbers Yourself¶
This is the test path any admin can run to reproduce the audit:
- Open the in-game console — press F8
- Type
resmonand press Enter - Find the
raycin_racesrow in the table
| Scenario | Expected resmon reading |
|---|---|
| Server idle, no one racing | 0.10–0.15 ms |
| You're in a race lobby (host) | 0.10–0.20 ms |
| You're actively racing | 0.75–1.30 ms per frame |
| Race with every feature on (DLP + Fuel + Tire Wear + Sync rotation) | 1.5–2.2 ms per frame |
| 8 simultaneous races on the server | ~5 ms server-side, ~2 ms client-side |
If your numbers come in significantly higher than this, something else on the server is interfering — open a support ticket and share the resmon screenshot.
Design Principles¶
The reason the numbers above are achievable is a small set of deliberate design rules followed throughout the codebase:
1. Event-driven over polling¶
Values update on state change, not on a clock. The position counter on your HUD doesn't tick 60 times per second checking "did anything change?" — it fires only when the server says your position actually changed.
2. Tight loop intervals¶
Every background thread runs at the lowest frequency it can get away with: - Fall-physics guards: 20 Hz (50 ms) - Force-collision: 6.7 Hz (150 ms) - Hazard prop scans: 2 Hz (500 ms) - Engine-health pin: 2 Hz idle / 60 Hz only when racing in Specific/Personal modes
Nothing runs faster than it needs to. The main race loop is the only Wait(0) (per-frame) thread — and it's necessary for HUD rendering and checkpoint detection.
3. Conditional rendering¶
Every animated UI element is hidden unless its feature is active. The fuel bar only paints when fuel is on. The blue flag only pulses when someone's catching you. The swap-warning banner only appears 5 seconds before a swap. CSS animations stopped is CSS animations not costing anything.
4. One source of truth¶
Race state lives server-side. Clients receive deltas (just the parts that changed), not full state dumps. This means a 16-player race doesn't generate 16× the traffic — it generates roughly the same as a 2-player race plus a small per-player delta.
5. O(1) over O(n) wherever possible¶
When a player disconnects mid-race, the server uses a direct PlayerInRoom[playerId] lookup to find their room rather than scanning every room. This sounds trivial but on a server with many rooms it's the difference between instant cleanup and a noticeable hitch.
6. Lazy load, eager cache¶
Vehicle presets, user-saved presets, and config data load once on resource start and live in memory. The disk is touched again only when something is genuinely saved (e.g. you click "💾 Save as Preset"). No background DB pings.
Recent Optimisation Pass (May 2026)¶
Honest disclosure of what was tuned:
- Custom Vehicle List modal search: originally re-rendered all 200+ DOM rows on every keystroke. Added a 200 ms debounce — typing "cheetah" went from 7 renders to 1, eliminating the ~300 ms stutter on large catalogues.
- Swap-warning banner drop-shadow: reduced blur from 25 px to 12 px. Cut compositor repaint cost ~40 % during the 5-second swap windows. Important because high-swap races chain these (10 swaps = 50 seconds of continuous animation).
- Race-context laps cache: the pool-size hint pill used to re-query the DOM for the lap count on every selection change. Now reads the value once when the modal opens and uses the cached value thereafter.
None of these affected the visual or behaviour of any feature — purely cheaper execution paths.
What's NOT Optimised (Yet) — Full Transparency¶
It would be dishonest to claim everything is perfect. Three known opportunities remain:
-
Destroy Last Place tracking re-sorts the driver list every 1 second even when nothing has changed. Future optimisation: cache last-place and re-sort only when a lap or checkpoint event fires. Impact on a typical server: ~0.4 ms per second per active DLP race — measurable but not significant.
-
Sync sequence builder uses a
Citizen.Wait(0)busy-loop for up to 30 seconds waiting for track data on race start. Will be rewritten as a Promise callback. Impact: brief CPU spin on race-start that doesn't actually delay anything. -
Track-vote room search does an O(rooms × players) scan when an O(1) PlayerInRoom lookup is available. Cosmetic at current server scale; would matter at 100+ rooms.
These are documented, tracked, and on the roadmap — not hidden under the rug.
Memory Footprint¶
For a server admin trying to plan capacity:
| Scenario | RAM cost |
|---|---|
| Per idle room | ~30–35 KB |
| Per active race room with VP features | ~50–60 KB |
| Per race's sync sequence (chaos mode, 20 CPs × 100 laps) | ~26 KB |
| 8-room server steady-state | ~590 KB total |
| Peak (8 rooms + concurrent race starts) | ~700 KB total |
For context: a single high-resolution texture in GTA is bigger than the entire raycin_races server-side memory footprint.
Bottom Line¶
If you've got 64 players on your server and four races running simultaneously, raycin_races contributes roughly 0.5 % of one server thread. The remaining 99.5 % of your resmon budget stays available for everything else you want to run.
Built lean on purpose. The numbers above are independently verifiable. If you find them inaccurate on your setup, open an issue — we'd rather fix it than spin it.