Exports
Public exports registered by nx_write.
nx_write exposes a client API for opening, placing, and closing writing
sessions, plus a set of server-side helpers. The client exports let a
custom inventory open, place, and close sessions, and let custom
positioning tooling create placements directly. The server exports
forward an open request to a player, create trusted placements, and read
a saved document's preview image. RegisterPaperKind exists on both
sides and lets another resource add its own writable paper at runtime.
See Configuration for Config.Inventory, which
decides whether nx_write touches ox_inventory itself or leaves item
handling to you.
Client
exports.nx_write:placeFromSlotclientStart the in-world placement preview for the note held in the given inventory slot. The slot's item must carry a saved document (a docId in its metadata); if it does not, the player is notified to save it first.
Parameters
slotnumber— ox_inventory slot number of the notepad or post-it to place.
Returns
nil-- Wired on the notepad item in ox_inventory/data/items.lua,
-- so the inventory's right-click "Place" button enters placement.
buttons = {
{
label = 'Place',
action = function(slot)
exports.nx_write:placeFromSlot(slot)
end,
},
},During the preview the player aims at a surface, then commits with the
Config.Placement.controls.commit key or cancels
with the cancel key. On commit the note is placed for every nearby
player and the item is consumed from the slot.
exports.nx_write:OpenclientOpen or continue a writing session. Returns false if a session or placement preview is already active, or if the kind is unknown. Pass docId to continue a saved document; omit it for a new one. slot and itemName are opaque values echoed back in nx_write:documentSaved on save.
Parameters
optstable— { kind?: string (default "notepad"), docId?: number, title?: string, slot?: any, itemName?: string, page?: number, readOnly?: boolean, background?: { url?: string, dataUrl?: string } }.
Returns
boolean-- Continue a document your custom inventory stored on the item.
exports.nx_write:Open({
kind = 'notepad',
docId = item.metadata.docId,
slot = item.slot,
itemName = item.name,
})exports.nx_write:RegisterPaperKindclientRegister a writable paper kind at runtime, so another resource can add its own paper without editing nx_write. The def needs a kind key plus whatever differs from the template. Everything else is filled in from a small-card default, and the session feel (hold pose, pen, write animation, hand IK) is inherited from the live post-it entry, so a registered kind tracks future post-it retunes instead of a frozen copy. Call the server export with the same def, or saving a session of that kind is rejected. Built-in kinds cannot be overwritten. Returns true, or false plus a reason string.
Parameters
deftable— { kind: string (required, unique), label?: string, prop?: string, panelWidth?: number, panelHeight?: number, multiPage?: boolean, features?: { tear?: boolean, fontButton?: boolean }, background?: { box: { x, y, w, h } }, ...any other paper field you want to override }.
Returns
boolean, string?-- Register on both sides, then open sessions with your own item.
exports.nx_write:RegisterPaperKind({
kind = 'polaroid',
label = 'Polaroid',
prop = 'prop_cs_polaroid',
features = { tear = false, fontButton = false },
background = { box = { x = 0.06, y = 0.05, w = 0.88, h = 0.72 } },
})
exports.nx_write:Open({
kind = 'polaroid',
docId = item.metadata.docId,
slot = item.slot,
itemName = item.name,
background = { url = photoUrl },
})[!note] A registered kind gets no in-world placement entry and no
ox_inventoryitem. In-world placement and item handling stay with the host resource: open sessions with your own item'sslotanditemName, then persist thedocIdfromnx_write:documentSaved.featureshides DUI buttons that do not apply to your paper, andbackground.boxis the page-fraction box the per-document background image renders into.
exports.nx_write:PlaceclientStart the in-world placement preview for a saved document. docId is required, since the placement renders the document's saved preview image. slot and itemName ride along to the server and are echoed on nx_write:placementCreated.
Parameters
optstable— { kind?: string (default "notepad"), docId: number, slot?: any, itemName?: string }.
Returns
booleanexports.nx_write:Place({ kind = 'notepad', docId = item.metadata.docId, slot = item.slot, itemName = item.name })exports.nx_write:CreatePlacementclientCreate a committed placement at explicit coords and rotation, skipping the in-world aim preview. This is the hook for custom positioning tooling (transform gizmos, snapping, free-rotate): your UX owns where the note goes, nx_write owns persistence, render, and multiplayer sync. It runs the same server callback as a preview commit, so it persists, bakes and renders on every client, and fires nx_write:placementCreated. Returns the placement id on success, or false. A client-driven create is still validated against the player's position (Config.Placement.maxPlaceDistance plus 2 m slack); use the server export for an unbounded, trusted placement.
Parameters
optstable— Pose, in priority order. { kind?: string (default "notepad"), docId: number (the saved document to render), entity?: number (read coords and quat off a live entity, the precise path: point it at your gizmo preview prop), coords?: vector3, quat?: { x, y, z, w } (lossless, preferred over rotation), rotation?: vector3 (pitch, roll, yaw in GTA euler degrees), surfaceKind?: "wall" | "table" (inferred from the pose when omitted), slot?: any, itemName?: string }.
Returns
number | false-- From a transform gizmo: the tool owns positioning, nx_write owns the rest.
-- Passing a live entity is the precise path: the placement is
-- byte-identical to the preview prop the player was dragging.
local id = exports.nx_write:CreatePlacement({
kind = 'notepad',
docId = item.metadata.docId,
entity = gizmoPreviewProp,
slot = item.slot,
itemName = item.name,
})
-- Or place at explicit coords with a lossless quat.
exports.nx_write:CreatePlacement({
kind = 'notepad',
docId = item.metadata.docId,
coords = vec3(215.7, -810.2, 30.7),
quat = { x = 0.0, y = 0.0, z = 0.0, w = 1.0 },
})[!note] Prefer
entityorquatfor the pose. Both are exact.rotation(GTA euler) is a convenience that round-trips cleanly for flat or upright poses only. WhensurfaceKindis omitted, nx_write infers it from the prop's world face normal and validates it against the kind's allowed surfaces.
exports.nx_write:RefreshPlacementsclientRe-pull placements from the server and render any not held locally. Live creates already arrive over the spawn broadcast, so this is a manual resync for tooling that writes to nx_write_placements out of band. Idempotent. Returns true if the refresh ran.
Returns
booleanexports.nx_write:RefreshPlacements()exports.nx_write:CloseclientSave (or discard) the active writing session and close it. Pass true to discard without saving. Returns false if no session was active.
Parameters
discardboolean— true discards the session without saving. Defaults to false (save and close).
Returns
booleanexports.nx_write:Close() -- save and close
exports.nx_write:Close(true) -- discard and closeexports.nx_write:IsBusyclientTrue while a writing session or a placement preview is active. Gate your own item-use with it so a second use does not double-open.
Returns
booleanif not exports.nx_write:IsBusy() then
exports.nx_write:Open({ kind = 'notepad', docId = item.metadata.docId })
endServer
exports.nx_write:OpenserverForward an open request to a player's client. Mirrors the client Open export and accepts the same opts. Use this when your inventory routes item-use through a server hook.
Parameters
sourcenumber— Server id of the player to open the session for.optstable— Same shape as the client Open export.
Returns
boolean-- From your inventory's server-side item-use handler.
exports.nx_write:Open(source, {
kind = 'notepad',
docId = item.metadata.docId,
slot = item.slot,
itemName = item.name,
})exports.nx_write:RegisterPaperKindserverServer-side twin of the client RegisterPaperKind export. Pass the same def. Saving validates the payload kind against the registered papers, so a kind registered only on the client would open sessions it can never save. Returns true, or false plus a reason string.
Parameters
deftable— Same shape as the client RegisterPaperKind export.
Returns
boolean, string?exports.nx_write:RegisterPaperKind({ kind = 'polaroid', label = 'Polaroid' })exports.nx_write:GetDocumentPreviewserverRead a saved document's stored preview image, so a host resource can render the ink outside nx_write (on its own prop, in its own UI). Returns nil if the document does not exist. The preview is a transparent PNG data URL. The caller owns its own access policy: serve only the kinds you registered, or private notepad ink becomes readable.
Parameters
docIdnumber— Document id, as received from nx_write:documentSaved.
Returns
table | nil-- { kind = 'polaroid', title = 'Beach', dataUrl = 'data:image/png;base64,...' }
local preview = exports.nx_write:GetDocumentPreview(docId)
if preview and preview.kind == 'polaroid' then
TriggerClientEvent('myresource:drawInk', src, preview.dataUrl)
endexports.nx_write:CreatePlacementserverCreate a placement at explicit coords from the server, bypassing the aim preview. The trusted mirror of the client CreatePlacement export. Because the server supplies the coords, the per-player rate-limit and distance gate are skipped (those guard the untrusted client callback). Everything else is identical to a preview commit: it persists, broadcasts so every client bakes and renders it, and fires nx_write:placementCreated. Pass coords with quat or rotation; there is no entity option, since the server cannot read a client entity. Returns the placement id on success, or false.
Parameters
sourcenumber— Server id of the player credited with the placement.optstable— { kind?: string (default "notepad"), docId: number, coords: vector3, quat?: { x, y, z, w } (lossless, preferred), rotation?: vector3 (pitch, roll, yaw in GTA euler degrees), surfaceKind?: "wall" | "table" (defaults to a surface the kind allows), slot?: any, itemName?: string }.
Returns
number | false-- Seed a placement programmatically from a server hook.
local id = exports.nx_write:CreatePlacement(source, {
kind = 'notepad',
docId = docId,
coords = vec3(215.7, -810.2, 30.7),
quat = { x = 0.0, y = 0.0, z = 0.0, w = 1.0 },
})[!note] These exports work in any inventory mode. They pair with the server events (
nx_write:documentSaved,nx_write:placementCreated,nx_write:placementPickedUp), which is how a custom inventory persists thedocIdand bridges items on place and pickup.