Hardware & Servicing
The parts inside each laptop, how they wear, and how players service them.
Every laptop holds real parts, laid out like the Framework Laptop 13 under made-up brands: a mainboard with the processor soldered on and its cooler, two memory sockets, an M.2 SSD, an M.2 Wi-Fi card and a battery. Each part is an inventory item with its own model, serial and condition. What a laptop holds changes how it runs, and players swap, clean and re-paste parts in the service view.
#Parts & Items
There is one item per kind of part, and metadata.model names the exact model. The item names are under hardware.items in Config.
| Part | Item | Models |
|---|---|---|
| Mainboard | laptop_mainboard | One per processor, see Boards. Carries its cooler in metadata.cooler |
| Cooler | laptop_cooler | dual ZC-25D (two 5 mm heat pipes), wide ZC-10W (one 10 mm pipe), wide_pcm ZC-10P (one 10 mm pipe and a phase-change pad) |
| Memory | laptop_ram | Halden DDR4-3200 d4_8, d4_16, d4_32 and DDR5-5600 d5_8, d5_16, d5_32, d5_48 |
| SSD | laptop_ssd | Nordwell nv3_512gb, nv3_1tb (PCIe 3), nv4_512gb, nv4_1tb, nv4_2tb (PCIe 4), nv5_1tb, nv5_2tb (PCIe 5) |
| Wi-Fi card | laptop_wifi | Kestrel Wireless kw6e, kw7 and Meridian mr6e, mr7, Wi-Fi 6E and 7 |
| Battery | laptop_battery | Tamsin zb55 (55 Wh) and zb61 (61 Wh) |
| Tool | Item | Use |
|---|---|---|
| Precision screwdriver | laptop_screwdriver | Opens a laptop for service. Never used up |
| Thermal paste | thermal_paste | Re-pastes the processor. 5 uses a tube. A tube with pcm = true in its metadata is a phase-change pad |
| Compressed air | compressed_air | Blows the dust out of the fan. 10 uses a can |
Uses left are kept in metadata.uses; an item without it is new, and it is gone after its last use. Digital Den sells parts and tools, see Shop.
#Boards
| Models | Generation | Processors (cores / threads) | Speed | Memory | Cooler |
|---|---|---|---|---|---|
kc11_k5, kc11_k7, kc11_k7h | Kestrel Talon 11 | K5-N210, K7-N230, K7-N250 (4 / 8) | 1.30, 1.22, 1.18 | DDR4 | dual |
kc12_k5, kc12_k7, kc12_k7h | Kestrel Talon 12 | K5-P220, K7-P240 (12 / 16), K7-P260 (14 / 20) | 1.12, 1.06, 1.02 | DDR4 | dual |
kc13_k5, kc13_k7, kc13_k7h | Kestrel Talon 13 | K5-Q340, K7-Q360 (12 / 16), K7-Q370 (14 / 20) | 1.08, 1.00, 0.96 | DDR4 | dual |
av7_5, av7_7 | Arden Vela 4 | Vela 5 V460 (6 / 12), Vela 7 V480 (8 / 16) | 1.00, 0.92 | DDR5 | dual |
ka1_5, ka1_7, ka1_7h | Kestrel Apex 1 | Apex 5 A510 (14 / 18), Apex 7 A550, Apex 7 A560 (16 / 22) | 0.95, 0.88, 0.86 | DDR5 | wide |
ava_5, ava_7, ava_9 | Arden Vela AI | Vela AI 5 X540 (6 / 12), Vela AI 7 X550 (8 / 16), Vela AI 9 X570 (12 / 24) | 0.90, 0.84, 0.78 | DDR5 | wide_pcm |
Speed multiplies every wait in the OS, so lower is faster. Memory has to be the board's type, and each board takes only its own cooler. Any SSD, Wi-Fi card or battery fits any board.
Conditions run from 0 to 1, where 1 is as new: wear on an SSD, health with cycles and charge on a battery, dust and paste on a cooler. A memory stick can carry a hidden fault that only shows once the stick is tested (tested).
#Where Parts Are Kept
The laptop item's metadata keeps them under hardware, next to serial, os, skin, finish and ports. Each slot holds the exact part item, {name, metadata}, so a part taken out later is the same item with the same metadata.
luahardware = {
v = 1,
board = {name = "laptop_mainboard", metadata = {model = "kc13_k7", serial = "MB-4F17-Q2K9", cooler = {model = "dual", dust = 0, paste = 1, pastedAt = 1791676800}}},
ram0 = {name = "laptop_ram", metadata = {model = "d4_16", serial = "RM-8D2K-77QF"}},
ram1 = {name = "laptop_ram", metadata = {model = "d4_16", serial = "RM-K4N2-XC9P"}},
ssd = {name = "laptop_ssd", metadata = {model = "nv4_1tb", serial = "ZL-7Q2K-9F4M", wear = 0, os = "facade"}},
wifi = {name = "laptop_wifi", metadata = {model = "kw6e"}},
battery = {name = "laptop_battery", metadata = {model = "zb61", serial = "BT-3MZQ-6H2R", health = 1, cycles = 0, charge = 1}},
leads = 2,
}
ram0 is the right socket, the one filled first. An empty slot is left out. leads is the number of Wi-Fi antenna leads plugged in. The SSD a laptop comes with has the laptop's own serial, and its os mirrors the item's. With item = false, the server's KVP keeps the hardware by the laptop's serial.
#What Parts Do
The server works all of this out from the hardware it reads; the client never reports any of it.
- The drive is on the SSD. Drives are keyed by the installed SSD's serial: the OS, account, home folder, history, system log and Crowbar's timer go wherever the SSD goes, so a pulled drive can be read in another laptop. The laptop's own serial stays for traces, the VPN and
GetLaptopSerial. A new SSD gets a blank drive the first time it boots, and an installer stick takes over. Without an SSD the boot menu leaves the internal drive out and installers refuse, but USB sticks still boot. See Operating Systems. - Speed. The processor, the memory, the SSD and the heat make one factor every wait in the OS is multiplied by, from 0.70 to 1.80. Under 16 GB of working memory is slower, 32 GB and 64 GB are a little faster, and one stick alone runs in single channel. NV3 drives are slower; the boards' M.2 slot is PCIe 4, so an NV5 runs at NV4 speed. An SSD past 90% wear is slower.
- Heat comes from the cooler's dust and dried paste. Above 0.40 waits stretch up to 1.25 times, and above 0.75 up to 1.45 times. A board without its cooler shows a fan error and powers off.
- Wi-Fi card. Without one the radio stays off and no hotspot can be joined, but the phone still tethers over USB. A Wi-Fi 7 card reaches hotspots 10% further and makes the Onion network and pages quicker. Antenna leads that are not plugged in cut the range, set by
hardware.leads. See Wi-Fi & Browsing. - Battery. A laptop put down runs on mains and charges. One in the hands runs on its battery, or on a power bank plugged into it. The OS shows the real charge and health. A laptop without a battery only powers on while it is put down or on a power bank with charge, and picking it up turns it off.
needsBattery = falsemakes a laptop in the hands run as if plugged in: its battery never drains, a laptop without a battery still powers on, and a power bank in it is left alone.- What stops it. A laptop without a mainboard does nothing at all, and one without working memory stays black with its power light blinking. A notification tells the player which. Memory of the wrong type or a faulty stick does not count as working.
Memory that went in or came out is trained on the next power-on.
luahardware = {
-- Hotspot range with 0, 1 or 2 of the Wi-Fi card's antenna leads plugged in, times the hotspot's own range
leads = {[0] = 0.25, [1] = 0.6, [2] = 1.0},
needsBattery = true,
},
#Wear
Parts wear by the server's clock. Powered hours count while an OS runs on the laptop; a laptop asleep in an inventory gathers no dust. Desktop computers never wear on their own.
| Part | How it wears | Setting |
|---|---|---|
| Fan dust | Fills up over powered hours until fully clogged | dustHours = 40 |
| Thermal paste | Dries over real days, from new down to a floor. A phase-change pad dries three times slower; a PCM cooler re-pasted with plain paste dries at the paste rate | pasteDays = 30, padDays = 90, pasteFloor = 0.3 |
| SSD | Wears over the powered hours its model is rated for: NV3 300, NV4 500, NV5 600. At full wear it turns read-only | — |
| Battery | Drains while the laptop is powered in the hands, and charges while it is put down. A worn battery runs out sooner. Health drops with each full cycle drained, never under the floor | batteryMinutes = 720, chargeMinutes = 20, healthPerCycle = 0.002, minHealth = 0.5 |
| Memory | Each working stick may turn faulty, rarely. The fault shows once the stick is tested in the firmware's Setup (F2 while the laptop starts) | ramFaultChance = 0.005 per 10 powered hours |
A full battery at full health lasts 12 hours of use in the hands. A read-only SSD still boots, but the OS refuses to save settings, files, accounts and passwords.
When an SSD turns read-only or a memory stick turns faulty, the server event zyke_laptop:PartWornOut(serial, slotId) fires with the laptop's serial and "ssd", "ram0" or "ram1".
luahardware = {
-- Parts CreatePartMetadata makes with used = true: a random condition, and memory that is faulty this often
used = {minCondition = 0.55, maxCondition = 0.9, faultChance = 0.15},
wear = {
dustHours = 40,
pasteDays = 30,
padDays = 90,
pasteFloor = 0.3,
batteryMinutes = 720,
chargeMinutes = 20,
healthPerCycle = 0.002,
minHealth = 0.5,
ramFaultChance = 0.005,
},
},
#Prebuilts
Laptops come as one of the prebuilts in shared/unlocked/hardware.lua, where you can change them or add your own. Every part gets its own serial when the laptop is made, and a board always comes with its cooler.
| Prebuilt | Board | Memory | SSD | Wi-Fi | Battery |
|---|---|---|---|---|---|
legacy | kc13_k7 | 2 x 16 GB DDR4 | NV4 1 TB | kw6e | zb61 |
basic | kc12_k5 | 1 x 8 GB DDR4 | NV3 512 GB | kw6e | zb55 |
standard | kc13_k7 | 2 x 8 GB DDR4 | NV4 512 GB | kw6e | zb61 |
performance | av7_7 | 2 x 16 GB DDR5 | NV4 1 TB | mr6e | zb61 |
flagship | ava_9 | 2 x 32 GB DDR5 | NV4 2 TB | mr7 | zb61 |
diy | kc13_k5 | None | None, and no OS | kw6e | zb55 |
desktop | kc13_k7 | 2 x 16 GB DDR4 | NV4 1 TB | kw6e | None |
luaConfig.Prebuilts = {
basic = {board = "kc12_k5", ram = {"d4_8"}, ssd = "nv3_512gb", wifi = "kw6e", battery = "zb55"},
-- Leave a part out for a laptop without it
diy = {board = "kc13_k5", wifi = "kw6e", battery = "zb55"},
}
- A
laptopitem given without metadata becomeshardware.default,basic, the first time it is taken out, with fresh serials. desktopis the desktop computer's, set bycomputer.prebuilt. It runs on mains and has no battery.- The server prints a warning on start for a prebuilt with a model the catalogue doesn't have, or parts that don't fit together.
#Older Laptops
A laptop item from before hardware gets hardware.migrated, legacy, on its next take-out: the specs it always showed, its drive kept as the SSD, and its serial, OS, skin, finish and ports left as they were. The write is read back, and a failed one leaves the item as it was to try again next time. With item = false, each laptop gets the same the first time it is taken out.
#Service View
A player opens up a laptop they put down with Service in its options. Every OS on it has to be shut down, nobody else may be using or servicing it, and the player needs a laptop_screwdriver. Desktop computers can't be serviced.
- The lid closes and the laptop turns over. Hold E to loosen the seven bottom screws. Backspace cancels.
- The laptop turns upright and the input cover comes off. Point at a part, or press Tab to go through them, to outline it and see its name and condition. An empty slot shows a small marker.
- Use the keys for the part in focus, listed on screen. Each part that goes in or comes out shows a card at the side of the screen.
- Press Backspace to close up, then hold E to tighten the screws. Closing up seats a lifted cooler.
| Action | Key |
|---|---|
| Loosen or tighten the bottom screws | Hold E |
| Pick a part | Mouse |
| Next part | Tab |
| Take the part out | E |
| Fit a part into an empty slot | F, then pick from the parts carried that fit with 1–9 |
| Lift the cooler off the processor | E |
| Seat a lifted cooler | F |
| Blow out the dust (cooler in place) or clean the fan (lifted) | C |
| Re-paste the processor (cooler lifted or out) | R |
| Connect the next Wi-Fi antenna lead | L |
| Back, close up, or cancel before the cover is off | Backspace or Escape |
- The mainboard comes out last, with its cooler, after the memory, SSD, Wi-Fi card and battery. Memory, the SSD, the Wi-Fi card and the cooler need a board to go into; the battery does not.
- A cooler that goes in is set beside the laptop, lifted, and F seats it. Paste put on a bare processor goes under the next cooler that goes in.
- Blowing out with the cooler in place takes
blowOutof the dust; a lifted cooler is cleaned fully. - On a PCM cooler, re-pasting uses a phase-change pad if the player carries one, otherwise plain paste.
- A Wi-Fi card goes in with its antenna leads unplugged, black first, then white. Closing up with a lead out warns once and goes ahead the second time.
The server checks and writes every step against the exact inventory slot as it happens, so a player who walks away, dies or leaves loses nothing, and the laptop is closed up as it is.
luahardware = {
service = {
enabled = true,
-- Lets players service laptops they didn't put down, the CanServiceLaptop hook decides who
others = false,
-- Items the service view uses, false for no tool needed
items = {tool = "laptop_screwdriver", paste = "thermal_paste", air = "compressed_air"},
-- Uses in a new tube of paste and a new can of air
pasteUses = 5,
airUses = 10,
-- Share of the fan's dust a blow-out takes with the cooler in place
blowOut = 0.7,
},
},
#Repair Shops
Only the character who put a laptop down may service it. Set service.others = true to let others, and edit CanServiceLaptop(plyId, ownerId) in server/unlocked/hooks.lua to decide who, for example a repair shop's job. CanInstallPart and CanRemovePart(plyId, ownerId, slotId, itemName, metadata) can keep parts from going in or coming out, in the service view and through the exports. Return false and a locale key to refuse. See Can-Check Hooks.
#For Developers
Server exports give and read laptops and parts:
| Export | Use |
|---|---|
CreateLaptopMetadata | Metadata for a new laptop item built as a prebuilt, every serial new |
CreatePartMetadata | Metadata for a new part item, new, used or at a set condition, with the label and description ox_inventory shows |
GetPartInfo | What a part item is: kind, model, label, spec, condition, fault and the boards it fits |
GetLaptopHardware | A copy of a laptop's hardware |
SetLaptopHardwareSlot | Fits a part into, or takes it out of, a laptop item without the service view |
RepairLaptop | Cleans the fan, re-pastes, or brings the battery back to full health |
GetLaptopSpecs | The parts, heat and speed factor, worked out as for the OS |
WearLaptop | Wears a laptop on top of its own wear, for a load such as mining |
lualocal metadata = exports["zyke_laptop"]:CreateLaptopMetadata("performance", {finish = "midnight"})
exports.ox_inventory:AddItem(plyId, "laptop", 1, metadata)
local stick = exports["zyke_laptop"]:CreatePartMetadata("laptop_ram", "d5_16", {used = true})
The server events zyke_laptop:PartInstalled, zyke_laptop:PartRemoved, zyke_laptop:LaptopServiced and zyke_laptop:PartWornOut fire after a change is written. On the client, IsServicing tells whether the player has the service view open. See Exports & Events.