ns-killfeed โ
A two-way verified killfeed for RedM with a draggable NUI overlay, per-player visual themes, weapon-specific icons, and a spoof-resistant kill-confirmation pipeline. Drop-in friendly across VORP, RSG-Core and RedEM:RP through ns-lib.
Each player picks the look they want from the settings panel; the server never trusts a single client's word for a kill.
Table of Contents โ
- Highlights
- Themes
- Weapon icons
- Two-way verification
- Installation
- Configuration
- Player commands & keybinds
- Settings panel & persistence
- Cross-resource API
- File structure
- Building the NUI
- Troubleshooting
- Discord
Highlights โ
- Four themes, swappable on the fly โ Telegraph Wire, Wanted Ledger (default), Wild Headline, Tally Marks. Same data, four visual takes.
- 23 weapon-specific icons โ every cattleman, every shotgun, every thrown bottle gets the right silhouette. Falls back to a category SVG for environment and fist kills.
- Spoof-resistant pairing โ both the victim and the killer must report, inside a configurable window. A lone victim can never fabricate a kill in strict mode;
fallbackmode pings the alleged killer for a one-shot ack when the killer's report is missing. - Per-player UI โ drag to position, scale 0.5รโ1.5ร, opacity, max rows, per-row lifetime, fade-out duration, theme selection. Everything is KVP-persisted on the player's client.
- Server-side validation โ death check on every suicide claim, two rate limits (general + extended suicide cooldown),
sourcecapture on every net event, ack timeouts on fallback pings. - Cross-framework via ns-lib โ no direct VORP/RSG/RedEM calls. The resource works on any of the three with no code changes.
- Cross-resource API โ admin tools, deathmatch resources or duel scripts can push rows directly with
exports['ns-killfeed']:Push(...). - Suicide rendering โ fall, drown, fire, bleed-out are emitted as italicised single-name rows with an environment icon.
Themes โ
All four themes render the same row data; you swap the look from the settings panel without restarting anything.
| Theme | Vibe | Layout |
|---|---|---|
telegraph | Brutalist mono terminal | [HH:MM] KILLER <icon> ยป VICTIM |
ledger (default) | Editorial parchment, two-line | Line 1: <icon> KILLERLine 2: killed VICTIM ยท clean shot |
headline | Old newspaper bold serif | Headline: KILLER FELLS VICTIMSubhead: <icon> ยท clean shot |
tally | Dark leather + brass, compact 32px | KILLER <icon> โธ VICTIM |
Each theme has its own CSS file under ui/src/themes/<theme>.css and a matching <Theme>Row.jsx component. Adding a new theme is a self-contained change: drop a fifth pair of files and append the slug to Config.AvailableThemes.
Weapon icons โ
Every entry in shared/weapons.lua carries three pieces of information:
W[`weapon_revolver_schofield`] = {
label = 'Schofield Revolver',
category = 'revolver', -- colour hint for the row
icon = 'schofield_revolver' -- maps to ui/src/assets/weapons/<icon>.png
}The 23 icon slugs ship with the resource:
single_action_revolver double_action_revolver schofield_revolver
volcanic_pistol semi_auto_pistol_1 semi_auto_pistol_2
mauser_pistol sawed_off_shotgun pump_action_shotgun
lever_action_rifle bolt_action_rifle repeater_carbine
springfield_rifle bow tomahawk
hunting_knife knuckle_knife machete
lasso dynamite throwing_knife
throwing_hatchet fire_bottleMultiple weapons share the same icon when they belong to the same visual family (e.g. Cattleman, Vaquero and Navy all use single_action_revolver; all bolas use lasso). Weapons with category = 'env' or 'fist' and no icon field fall back to a vector SVG drawn in WeaponIcon.jsx, so kills from weapon_fall, weapon_drowning, weapon_unarmed etc. always render something sensible.
To swap an icon, drop a replacement PNG into ui/src/assets/weapons/ keeping the same slug, then run npm run build.
Two-way verification โ
Killfeeds are a classic spoofing target โ a single client can claim "I just killed X" without anyone dying. ns-killfeed pairs two independent reports on the server before broadcasting.
Victim client Server Killer client
โโโโโโโโโโโโโ โโโโโโ โโโโโโโโโโโโโ
I died โ killer S โ
weapon W โ
โโโโโโโโโโโโโโโโโโโโโโโผโโบ pending[victim] = { killer S, W, ts }
โ
"Killer S killed me" โ
โ
โโ I killed victim โโโโโ (killer client sees victim die)
โ with W
โโโโโโโโโโโโโโโโโโโโโโโโโโโโบ pending[victim].killerReported = true
โ โ
โ both flags? โ broadcast
โ
pending expires โ
without killer ack: โ
โโ strict โ drop โ
โโ soft โ emit โ (flagged unconfirmed)
โโ fallback โ ping โโโโโโโบ did you kill victim S?
โ โโโโโโโ yes / no
โ yes โ broadcast, no โ dropMatch modes โ
Config.MatchMode | Behaviour |
|---|---|
strict | Both reports required within MatchWindow. Drops legit kills on packet loss or DC. |
soft | Victim report alone is enough. Not spoof-proof โ trusted/small servers only. |
fallback (default) | Try strict; if only the victim reported, server pings the alleged killer for a one-shot ack within FallbackPingTimeout. Best balance. |
Suicide reports skip pairing: when killerSrc == victimSrc or killerSrc == 0 the server confirms the reporter is actually dead (IsEntityDead(GetPlayerPed(src))), enforces a 30-second per-player cooldown, and broadcasts.
Installation โ
Requirements โ
- A running RedM server with one of:
- VORP core
- RSG-Core
- RedEM:RP
- ns-lib loaded before this resource (cross-framework abstraction layer)
- Node.js + npm โ only required to build the NUI; not needed at runtime
Steps โ
- Drop the resource into your
resources/[Scripts]/ns-killfeedfolder. - Build the NUI (one-time, or when you change UI source):bashThis emits the production bundle to
cd ns-killfeed/ui npm install npm run buildns-killfeed/html/, whichfxmanifest.luaserves to the game client. - In your
server.cfg, make surens-libstarts before this resource:cfgensure ns-lib ensure ns-killfeed - Join the server and press F10 (or run
/killfeed) to open the settings panel.
Configuration โ
All knobs live in config.lua. Player-tunable UI defaults are overridden per-player via KVP once the player saves settings.
Verification โ
| Key | Default | Meaning |
|---|---|---|
Config.MatchMode | 'fallback' | strict | soft | fallback |
Config.MatchWindow | 3000 | ms โ pair must arrive within this |
Config.FallbackPingTimeout | 1500 | ms โ killer must ack the fallback ping by this |
Scope โ
| Key | Default | Meaning |
|---|---|---|
Config.ShowPvP | true | broadcast player-vs-player kills |
Config.ShowSuicide | true | broadcast self / environment deaths |
Config.ShowNpcKill | false | player killed by an NPC |
Config.ShowEnvKill | false | dedicated environmental death lines (future) |
Rate limit โ
| Key | Default | Meaning |
|---|---|---|
Config.MinReportInterval | 800 | ms between victim reports per source |
UI defaults (overridable per-player) โ
| Key | Default | Meaning |
|---|---|---|
Config.DefaultPosition | {x=78, y=4} | % of viewport (top-right corner by default) |
Config.DefaultScale | 1.0 | 0.5 .. 1.5 |
Config.DefaultOpacity | 0.92 | 0.3 .. 1.0 |
Config.MaxRows | 4 | visible rows |
Config.FadeMs | 5000 | per-row visible lifetime |
Config.FadeOutMs | 600 | fade transition duration |
Config.DefaultTheme | 'ledger' | telegraph | ledger | headline | tally |
Config.AvailableThemes | (all four) | list shown in the settings UI picker |
Keybinds & debug โ
| Key | Default | Meaning |
|---|---|---|
Config.SettingsKey | 'F10' | default keybind (rebindable in-game) |
Config.SettingsKeyMapping | 'killfeedsettings' | RegisterKeyMapping ID |
Config.Debug | true | enables /killfeed_test + log output |
Messages (English, no i18n) โ
Config.Messages holds the strings shown to the player (suicide line, settings open/saved toast, unknown-weapon label). Edit in-place if you want custom wording.
Player commands & keybinds โ
| Command | Effect |
|---|---|
/killfeed | Open the settings panel (same as the keybind) |
| F10 (default) | Open the settings panel โ rebindable from the in-game key map |
/killfeed_test | Spawn four demo rows (cattleman / sawed-off / carcano / fall). Only available while Config.Debug = true. |
The keybind is registered via RegisterKeyMapping, so each player can rebind it from the RedM key-mapping menu (Settings โ Key Bindings โ FiveM/RedM).
Settings panel & persistence โ
Open the panel with the keybind or /killfeed. While the panel is open:
- The feed shows four preview rows so you can see what the chosen theme
- scale + opacity actually look like.
- The feed becomes draggable: click-and-hold anywhere on the killfeed anchor to drop it elsewhere on the screen. Live preview, no commit until you press Save.
- Adjust theme, scale, opacity, max rows, fade duration.
- Save commits everything to KVP and closes the panel.
- Cancel / ESC reverts to the previous committed settings.
KVP key (single blob, JSON-encoded):
ns-killfeed:settingsTo wipe a player's settings (debug): clear that KVP key from their client and rejoin.
Cross-resource API โ
Other resources โ admin menus, deathmatch arenas, duel scripts, custom RP events โ can push rows directly. The server-side export skips the pairing step (the caller is trusted).
-- Force a row from another resource.
exports['ns-killfeed']:Push(killerSrc, victimSrc, weaponHash, 'pvp')
exports['ns-killfeed']:Push(killerSrc, victimSrc, weaponHash, 'pvp', true) -- headshot
exports['ns-killfeed']:Push(victimSrc, victimSrc, weaponHash, 'suicide')| Arg | Type | Notes |
|---|---|---|
killerSrc | number | Player server-id, or 0 / victimSrc for suicide |
victimSrc | number | Player server-id of the victim |
weaponHash | number (uint32) | Use a backtick hash literal: `weapon_revolver_cattleman` |
killType | 'pvp' | 'suicide' | Suicide rows never render a headshot badge |
isHeadshot | boolean (opt) | Defaults to false |
Anything you push appears on every client respecting their personal theme and UI settings.
File structure โ
ns-killfeed/
โโโ fxmanifest.lua
โโโ config.lua
โโโ README.md
โโโ shared/
โ โโโ utils.lua
โ โโโ weapons.lua โ hash โ { label, category, icon }
โโโ client/
โ โโโ main.lua โ death watcher, victim reporter
โ โโโ nui.lua โ inbound row pusher, /killfeed_test
โ โโโ settings.lua โ KVP load/save, settings panel bridge
โ โโโ command.lua โ /killfeed + RegisterKeyMapping
โโโ server/
โ โโโ verify.lua โ pairing window, fallback ping, rate limits
โ โโโ main.lua โ net events, Push export
โโโ html/ โ built NUI (git-ignored if you prefer)
โ โโโ index.html
โ โโโ assets/
โ โโโ index-*.js
โ โโโ index-*.css
โ โโโ <weapon>-<hash>.png (23 icons)
โ โโโ *.woff / *.woff2 (Rye, IM Fell English)
โโโ ui/ โ React + Vite source
โโโ package.json
โโโ vite.config.js
โโโ src/
โโโ App.jsx
โโโ main.jsx
โโโ components/ โ KillFeed, KillRow, SettingsPanel, DragAnchor
โโโ themes/ โ *.css + *Row.jsx for the four themes
โโโ icons/ โ WeaponIcon.jsx + SkullBadge.jsx
โโโ hooks/ โ useNuiEvent
โโโ lib/ โ nui.js (NUI fetch bridge)
โโโ styles/ โ global.css
โโโ assets/
โโโ weapons/ โ 23 source PNGsBuilding the NUI โ
cd ui
npm install
npm run build # โ ../html/ (production bundle, Vite hashes the assets)For UI development:
npm run dev # opens localhost:5175 in the browserThe NUI no-ops its fetch('https://ns-killfeed/...') calls when it is not running inside the RedM client (see ui/src/lib/nui.js), so theme/layout work in a normal browser is safe โ drag-positioning, theme picker, and live preview all work without a server.
When you change any file under ui/src/, you must npm run build again and restart the resource (or refresh; ensure ns-killfeed) for the changes to appear in-game.
Troubleshooting โ
| Symptom | Likely cause / fix |
|---|---|
| Resource fails to start | ns-lib not loaded first. Add ensure ns-lib above ensure ns-killfeed. |
| Settings panel won't open | Another resource is grabbing F10. Rebind from the in-game key map or change Config.SettingsKey. |
| Kills never appear | Likely strict mode + lossy network. Switch Config.MatchMode to 'fallback'. |
| Suicide rows spammed | Lower Config.MinReportInterval or check that the client isn't double-reporting. The 30-second per-player suicide cooldown is hard-coded server-side. |
| Wrong icon for a custom weapon | Add the hash to shared/weapons.lua with the matching icon slug. |
unknown weapon label | The hash isn't in weapons.lua. The row still renders, just with a hex placeholder label. |
| Icons look pixelated | objectFit: contain keeps aspect ratio. Bump Config.DefaultScale or row size in the theme CSS. |
/killfeed_test does nothing | Config.Debug = false. Set it to true and restart. |
| Drag handle never appears | The drag anchor only activates while the settings panel is open. Open the panel first. |
Discord โ
Updates, bug reports, and other NativeScriptsDev releases: https://discord.gg/UyyngemnF8
