Electus Computers Exports
Exports for integrating Electus Computers with your own FiveM scripts: desktop apps, computers, hacking and laptop hardware.
Call exports with exports.electus_computers:<Name>(...). Everything marked Stable API v1 keeps its name, parameters, results and reason codes for the whole 1.x series. New optional fields may be added.
Registrations and handlers live in electus_computers, so register again whenever it (re)starts:
if GetResourceState("electus_computers") == "started" then RegisterMyApp() end
AddEventHandler("onClientResourceStart", function(resourceName)
if resourceName == "electus_computers" then RegisterMyApp() end
end)Desktop apps
Stable API v1. Adds your own app to the computer: an icon on the desktop, or a listing in the in-game software store, that opens a window with your web page in it.
Register the app on both the client and the server, with the same options. The client draws the app. The server lets players install it from the store, move it to Trash and keep its desktop position. A shared script does both:
-- shared_script in your fxmanifest.lua
local function RegisterMyApp()
exports.electus_computers:AddDesktopApp({ id = "my-notes", label = "My Notes", url = "web/index.html" })
end
if GetResourceState("electus_computers") == "started" then RegisterMyApp() end
AddEventHandler(IsDuplicityVersion() and "onResourceStart" or "onClientResourceStart", function(resourceName)
if resourceName == "electus_computers" then RegisterMyApp() end
end)The server reads id and store and ignores the client-only options. Apps registered only on the client still open, but nothing about them is saved. When your resource stops, its apps are removed on both sides: their icons stay put and show a "cannot open" notice until the resource starts again.
AddDesktopApp
Client and server.
local ok, reason = exports.electus_computers:AddDesktopApp({
id = "my-notes",
label = "My Notes",
url = "web/index.html",
icon = "terminal",
width = 800,
height = 500,
onOpen = function(data)
exports.electus_computers:SendDesktopAppMessage(data.id, "load", { notes = GetMyNotes() })
end,
})| Option | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique app id: letters, digits, - and _, up to 64 characters. Registering the same id again replaces the app. |
label | string | required | Name on the desktop, in the window title and in the store. Up to 64 characters. |
url | string | required | Page shown in the window: a file in your resource ("web/index.html"), "nui://<resource>/<path>", or an http(s):// URL. Files must be listed in your fxmanifest.lua files. |
icon | string | browser icon | A built-in icon name, or an image resolved like url. Use a full-bleed square image; it is drawn with rounded corners. |
width | number | 640 | Window width in pixels, 200 to 3840. |
height | number | 420 | Window height in pixels, 150 to 2160. |
storageGb | number | 1 | Disk space the app takes on a computer, 0 to 1000. |
store | boolean | false | false: the app is added to the desktop of every computer. true: it is listed in the software store and players install it. |
summary, version, publisher, category | string | Store listing text. publisher defaults to your resource name. | |
onOpen | function | Client only. Called with { id = string } each time the player opens the app window. It does not run for players watching that screen, or when your page navigates inside the window. |
Built-in icon names: binary, briefcase, browser, calculator, cast, cloud, explorer, flame, folder, key, mail, map, paint, radar, radio, settings, shield, siren, snake, terminal, tray, wallet.
Returns true, or false and a reason: invalid_options, invalid_id, invalid_label, invalid_url, invalid_icon, invalid_width, invalid_height, invalid_storageGb, invalid_store, invalid_summary, invalid_version, invalid_publisher, invalid_category or invalid_onOpen. The server export only returns invalid_options, invalid_id and invalid_store. Every failure also prints an error naming the option. Unknown options print a warning and are ignored.
Paid apps
Prices are server authority. To sell a store app, add its id to Config.Software.apps in config/apps/software.lua. The store then shows that price and the server charges it in Config.Crypto.asset. Store apps without an entry are free once the server export has registered them.
["my-notes"] = { title = "My Notes", price = 500 },RemoveDesktopApp
Client only. Takes the app off this player's computers, icons included, for apps a player can lose, such as a job or gang app. Add it again with AddDesktopApp.
exports.electus_computers:RemoveDesktopApp("my-notes")Returns true, or false and unknown_app.
SendDesktopAppMessage
Client only. Posts a message to your app page on this player's own screen.
exports.electus_computers:SendDesktopAppMessage("my-notes", "load", { notes = notes })Returns true, or false and unknown_app or invalid_action (action is not a non-empty string). data defaults to {}.
Your page receives it as a message event. The page also gets the string "componentsLoaded" whenever it loads and before each message:
window.addEventListener("message", (event) => {
if (typeof event.data !== "object" || event.data.appId !== "my-notes") return
const { action, data } = event.data
if (action === "load") render(data.notes)
})The page's root font size is set to the desktop's (16px at 1080p), so size your page in rem and it scales with the computer, not with the window. Inside a computer window window.name is "electus_computers_app", and your resource's SendNUIMessage does not reach the page: send it data with SendDesktopAppMessage, or return it from your NUI callbacks.
To send data back, call your own resource's RegisterNUICallback handlers from the page:
fetch("https://<your_resource>/<callback>", { method: "POST", body: JSON.stringify(payload) })Desktop app events
Both fire on the client of the player who opened the app, after onOpen, with { id = string }:
AddEventHandler("electus_computers:desktopAppOpened", function(data) end) -- any app
AddEventHandler("electus_computers:desktopAppOpened:my-notes", function(data) end) -- one appOther client exports
| Export | Returns |
|---|---|
GetComputerApps() | { id: string, label: string }[]: built-in, store and registered desktop apps, sorted by label. |
GetComputerModels() | { laptop: string, desktop: string }: prop models of those computer types. |
Server API
Stable API v1. Every export returns ok, result: true and a result table, or false and a reason code string.
CreateComputer
Places a computer in the world.
local ok, result = exports.electus_computers:CreateComputer({
computerType = "desktop",
coords = vector4(-510.9, 287.3, 83.3, 180.0),
computerName = "Front desk",
apps = { "documents", "calculator" },
allowedJobs = { police = 0 },
})Returns true, { serialNumber, computerType, placement }.
| Option | Type | Description |
|---|---|---|
computerType | string | Required. A key of Config.Computer.types: "desktop", "laptop" or "tv". |
coords | vector3, vector4 or { x, y, z, w? } | Required. w is used as heading when heading is not set. |
heading | number | Heading in degrees. |
rotation | vector3 or { x, y, z } | Full rotation. Defaults to { 0, 0, heading }. |
bucket | integer | Routing bucket. Defaults to 0. |
model | string | Defaults to the computer type's model. |
serialNumber | string | Fixed serial. Generated when omitted. |
ownerIdentifier | string | Character identifier of the owner. |
computerName | string | Name shown on the computer. |
password | string | Password needed to unlock it, 1 to 128 characters. |
apps | (string | { appId, data })[] | Apps to install. See InstallComputerApp. |
replaceDefaultApps | boolean | Install only apps, not the default starting apps. |
allowedJobs | table<string, number> | Job name to minimum grade. Empty allows everyone. |
temporary | boolean | Remove the computer when your resource stops or electus_computers restarts. |
Reason codes: invalid_options, invalid_type, coords_missing, invalid_bucket, model_missing, invalid_password, serial_exists, placement_failed, owner_resource_stopped, plus any InstallComputerApp reason.
DestroyComputer
Deletes the computer, its placement and everything stored on it.
local ok, result = exports.electus_computers:DestroyComputer(serialNumber)Returns true, { serialNumber }, or false and serial_missing or computer_not_found.
InstallComputerApp
Installs an app on one computer. For note apps ("note", "notes", "notepad") it adds the notes in data instead.
local ok, result = exports.electus_computers:InstallComputerApp(serialNumber, "notes", {
note = { title = "Vault code", content = "4412" },
})Returns true, { serialNumber, appId, notes }.
data field | Description |
|---|---|
location | "desktop", "folder" or "stored". |
folderId | Folder to place the app in when location is "folder". |
grid | { column, row } position on the desktop. |
note, notes | One note or a list of notes: { id?, title?, content?, updatedAt? }. |
Reason codes: serial_missing, app_missing, computer_not_found, computer_destroyed, busy, invalid_location, folder_missing, invalid_note.
UninstallComputerApp
Removes an app, including from the trash.
local ok, result = exports.electus_computers:UninstallComputerApp(serialNumber, "notes")Returns true, { serialNumber, appId }, or false and app_not_installed or one of the InstallComputerApp reasons.
Server events
Server-local: listen with AddEventHandler, never RegisterNetEvent.
| Event | Arguments |
|---|---|
electus_computers:computerCreated | serialNumber, { computerType, ownerIdentifier?, source?, resource? }. Fired by CreateComputer (resource set) or when a laptop, desktop or TV item gets its serial (source set). |
electus_computers:computerDestroyed | serialNumber |
electus_computers:appInstalled | serialNumber, appId |
electus_computers:appUninstalled | serialNumber, appId |
electus_computers:hackCompleted | success, source, appId, serialNumber, { targetId, minigameId, durationMs, reason? }. reason = "abandoned" for a hack that expired unfinished, was pushed out by newer hacks, or whose player left. |
Hacking API
Stable API v1. Run the minigame on the client, then verify the result on the server before paying out. Never trust a client-side success on its own.
RunHack
Client only.
local ok, result = exports.electus_computers:RunHack({ appId = "port-breacher", targetId = "vault-1" })
if ok then
TriggerServerEvent("my_heist:hacked", result.token)
end| Option | Type | Description |
|---|---|---|
appId | string | Required. A hacking app from Config.HackingApps. The computer must have it installed. |
serialNumber | string | Computer to hack from. Defaults to the open or last used computer. |
computerSource | "placed" | Wait up to 10 seconds for that placed computer to stream in. |
autoOpenComputer | boolean | Open the last used computer when none is open. Default true. |
autoOpen | boolean | Open the hacking app window. Default true. |
minigameId | string | Defaults to the app's minigame. |
targetId, targetLabel | string | What is being hacked. |
difficulty | number | Minigame difficulty. |
timeout | number | Minigame time limit in milliseconds. |
loginTimeout, openTimeout | number | Time in milliseconds to unlock the computer and for it to boot. |
Returns true, result with result.token on success, or false, reason[, result]. Reasons include invalid_app, computer_not_open, computer_not_nearby, computer_closed, computer_open_timeout, read_only, app_not_installed, login_timeout, timeout and failed.
ConsumeHackResult
Server only.
RegisterNetEvent("my_heist:hacked", function(token)
local ok, details = exports.electus_computers:ConsumeHackResult(source, token)
if not ok or details.appId ~= "port-breacher" or details.targetId ~= "vault-1" then return end
-- reward the player
end)Returns true, { appId, serialNumber, targetId, minigameId, durationMs } once per successful hack by that player, otherwise false. Results expire after Config.HackSessions.resultLifetimeMs.
CanRunHackingApp
Server only.
local ok, reason = exports.electus_computers:CanRunHackingApp(source, serialNumber, "port-breacher")Returns true when the player can run that hacking app on that computer, otherwise false, reason.
Laptop hardware
Server only. Laptops have parts that wear, break and get repaired or upgraded at a repair bench. Desktops, TVs and world screens have none. All three exports do nothing while Config.LaptopHardware.enabled is false.
GetLaptopHardware
local hardware = exports.electus_computers:GetLaptopHardware(serialNumber)
if hardware and hardware.bootFailure then return end -- the laptop can't startReturns nil, or { serialNumber, parts, battery, effects, bootFailure?, screenDamage }:
| Field | Description |
|---|---|
parts | { id, label, tier, tierLabel, tierIndex, tierCount, condition, status }[] in bench order. id is battery, cpu, fan, ssd, wifi, screen or security. condition is 0 to 100. status is good, worn or broken. |
battery | { enabled, charge, charging, pluggedIn, runtimeMinutes, low, minutesLeft?, minutesToFull? }. Placed laptops count as plugged in. minutesLeft is set while unplugged, minutesToFull while charging below 100%. |
effects | { hackTimeBonusSeconds, storageGb, routerRangeMultiplier, wifiBroken }. |
bootFailure | Why the laptop won't start: cpu, ssd, screen, battery_broken or battery_empty. |
A laptop that was never damaged or opened reports factory parts at full condition.
DamageLaptopPart
Takes amount condition points off one part, for your own accidents such as an EMP, a taser or a fire.
local ok, reason = exports.electus_computers:DamageLaptopPart(serialNumber, "screen", 40)Returns true, or false and disabled or invalid_part.
RepairLaptopHardware
Restores every part to full condition without changing tiers.
local ok = exports.electus_computers:RepairLaptopHardware(serialNumber)Returns true or false.