Documentation

Exports & Events

Exports and local server events for Image Studio integrations.

General Information

Hosted-library exports return nil while the publisher is still starting. Vehicle model, variant, and selector values are sanitized by Image Studio; use lowercase model names and relative library paths.

Personal vehicle capture integrations must run on the server, use authoritative vehicle data, and reauthorize the player after completion before saving a URL.

Context

The shared export is registered on both client and server. Client exports use local game state. Hosted-library and personal-capture exports are server sided.

#Complete Export Index

ContextExports
SharedgetVehicleImagePath
ClientisPlayerVehicleCaptureEnabled, fetchVehicleShadowMetadata
ServergetHostedVehicleImageUrl, getHostedVehicleImageThumbnailUrl, getHostedVehicleImages, getHostedVehicleLinks, requestPlayerVehicleCapture

#Shared Sided Exports

#Get Vehicle Image Path

Builds a local nui:// URL from the configured output folder, sanitized model name, optional variant, and image format. The format defaults to PNG. Invalid characters become underscores; an empty sanitized model returns an empty string.

This export does not confirm that the local image exists and does not return a hosted Media Studio URL.

Example:

lua
---@param vehicleModel string | number @ Vehicle model or generated image basename
---@param imageFormat? "png" | "webp" @ Defaults to png
---@param variant? string @ Optional folder below Config.Capture.outputFolder
---@return string imagePath
local imagePath = exports["zyke_imagestudio"]:getVehicleImagePath("drafter", "webp", "sideview")

#Client Sided Exports

#Is Player Vehicle Capture Enabled

Returns the current Config.PlayerCapture.enabled value. Use this to hide an integration entry point when personal captures are disabled; the server export still validates the setting when a request is made.

Example:

lua
---@return boolean enabled
local enabled = exports["zyke_imagestudio"]:isPlayerVehicleCaptureEnabled()

#Fetch Vehicle Shadow Metadata

Temporarily spawns the requested model, creates the configured Studio camera, and returns the projected shadow metadata used by external tooling. Run from a yielding client context.

The export returns {success = false, error = "..."} for capture-busy, invalid-model, spawn-failed, shadow-data-unavailable, or a bounded runtime error. It always cleans up its temporary vehicle and camera.

Example:

lua
---@param modelName string
---@param settings? table @ NUI-facing Studio settings
---@return table result
local result = exports["zyke_imagestudio"]:fetchVehicleShadowMetadata("drafter", {
    vehicleHeading = 250.0,
    captureShadowAngle = 35.0,
})

if (result.success) then
    print(json.encode(result.captureShadowProjection))
end

A successful result includes model, captureHeading, captureShadowAngle, captureShadowFootprint, captureShadowProjection, and captureShadowSettings.

#Server Sided Exports

#Get Hosted Vehicle Image URL

Returns the active public source URL for one vehicle model, or nil while the library is unavailable or no matching image exists.

Without a variant, Image Studio resolves the current final image for the model. default and base select the configured base output folder; another safe variant selects that subfolder, such as edited.

Example:

lua
---@param model string
---@param variant? string
---@return string? publicUrl
local publicUrl = exports["zyke_imagestudio"]:getHostedVehicleImageUrl("drafter", "edited")

#Get Hosted Vehicle Image Thumbnail URL

Returns the active thumbnail URL for one vehicle model and optional variant. It falls back to the public source URL until a thumbnail derivative is available. Returns nil when no matching image exists or the library is unavailable.

Example:

lua
---@param model string
---@param variant? string
---@return string? thumbnailUrl
local thumbnailUrl = exports["zyke_imagestudio"]:getHostedVehicleImageThumbnailUrl("drafter", "edited")

#Get Hosted Vehicle Images

Returns a map keyed by sanitized model name. Each value contains publicUrl and optional thumbnailUrl. Without a selector, it returns the current final record discovered for each model.

The optional selector must be a relative path containing exactly one <model> placeholder and ending in .png or .webp. It can select a folder, filename suffix, and format, for example edited/<model>_sideview.png. Absolute paths, doubled slashes, parent traversal, and unsupported formats return an empty table.

Returns nil while the hosted publisher is not ready.

Example:

lua
---@class HostedVehicleImage
---@field publicUrl string
---@field thumbnailUrl? string

---@return table<string, HostedVehicleImage>? imagesByModel
local imagesByModel = exports["zyke_imagestudio"]:getHostedVehicleImages("edited/<model>_sideview.png")

if (imagesByModel and imagesByModel.drafter) then
    print(imagesByModel.drafter.publicUrl)
end

Returns every active source associated with one sanitized model, sorted by relative path and public URL. Returns nil while the hosted publisher is not ready, or an empty array for an invalid model / no matching images.

configPath is present when Image Studio can represent the filename with a <model> placeholder. This is the selector copied by /imagelink <model> for integrations such as zyke_garages.

Example:

lua
---@class HostedVehicleLink
---@field path string @ Relative hosted library path
---@field publicUrl string
---@field thumbnailUrl? string
---@field configPath? string @ Path containing the <model> placeholder

---@return HostedVehicleLink[]? links
local links = exports["zyke_imagestudio"]:getHostedVehicleLinks("drafter")

for i = 1, #(links or {}) do
    print(links[i].configPath or links[i].path, links[i].publicUrl)
end

#Request Player Vehicle Capture

This is a trusted server operation. Authorize the player and load the authoritative vehicle record before calling it. Do not expose the request table through an unrestricted network event.

Creates one personal-vehicle capture session for the player and opens the capture interface with a detached snapshot of the supplied properties.

reference is an opaque server-owned correlation value such as a VIN. It must be non-empty and at most 128 characters. model must be non-empty and at most 64 characters. label is optional and limited to 96 characters. The JSON-encoded vehicle-properties snapshot is limited to 65,536 bytes.

A successful result is {success = true, sessionId = "..."}. Failure reasons are disabled, hosting_unavailable, player_unavailable, session_active, or invalid_request.

Example:

lua
---@class PlayerVehicleCaptureRequest
---@field reference string @ Server-owned correlation value
---@field model string
---@field vehicleProperties table @ Authoritative properties loaded by the server
---@field label? string

---@param plyId integer
---@param request PlayerVehicleCaptureRequest
---@return {success: boolean, sessionId?: string, reason?: string} result
local result = exports["zyke_imagestudio"]:requestPlayerVehicleCapture(plyId, {
    reference = vin,
    model = vehicleModel,
    vehicleProperties = vehicleProperties,
    label = displayLabel,
})

if (result.success) then
    pendingCaptures[result.sessionId] = {
        plyId = plyId,
        reference = vin,
    }
end

See Personal Vehicle Captures for token handling, completion, and reauthorization requirements.

#Server Local Events

These events are local server integration notifications. They are not network event entry points and do not authorize database mutation by themselves.

#Player Vehicle Capture Completed

Fires after the final image upload succeeds and Media Studio returns a validated CDN URL. sourceUrl is present only when source uploading was enabled and succeeded.

Match the pending sessionId, confirm originResource, re-fetch the vehicle by your server-owned reference, and reauthorize the player before saving either URL.

Example:

lua
---@param sessionId string
---@param originResource string @ Resource that requested the session
---@param plyId integer
---@param reference string @ Server-owned request correlation value
---@param finalUrl string
---@param sourceUrl? string
AddEventHandler("zyke_imagestudio:PlayerVehicleCaptureCompleted", function(sessionId, originResource, plyId, reference, finalUrl, sourceUrl)
    local pending = pendingCaptures[sessionId]
    pendingCaptures[sessionId] = nil
    if (not pending or pending.plyId ~= plyId or pending.reference ~= reference) then return end

    -- Re-fetch the vehicle and reauthorize plyId before saving finalUrl
end)

#Player Vehicle Capture Ended

Fires whenever a personal capture session is unregistered, including cancellation, expiry, requesting-resource stop, and successful completion cleanup. Use it to clear integration-owned pending state that was not already cleared by the completion handler.

Example:

lua
---@param sessionId string
---@param originResource string
---@param plyId integer
---@param reference string
AddEventHandler("zyke_imagestudio:PlayerVehicleCaptureEnded", function(sessionId, originResource, plyId, reference)
    pendingCaptures[sessionId] = nil
end)