UZ Scripts
uz_AutoShot

Integration Examples

Code examples showing how to use uz_AutoShot thumbnails in clothing shops, tattoo shops, vehicle shops, and NUI panels.

Integration Examples

uz_AutoShot photos follow a fixed naming scheme, so your script never has to ask which photos exist. Build the URL from what you already know (gender, category, drawable, model), load it in an <img>, and fall back to a placeholder when the file is missing.


Pass the Base URL to Your NUI

For UIs that render many thumbnails, read the base URL and format once in Lua and build the URLs in JavaScript:

-- client.lua (your script)
SendNUIMessage({
    type = 'photoConfig',
    baseUrl = exports['uz_AutoShot']:getShotsBaseURL(), -- 'https://cfx-nui-uz_AutoShot/shots'
    format = exports['uz_AutoShot']:getPhotoFormat(),   -- 'png'
})
// nui/photos.js
let BASE = 'https://cfx-nui-uz_AutoShot/shots'
let EXT = 'png'

window.addEventListener('message', ({ data }) => {
  if (data.type === 'photoConfig') {
    BASE = data.baseUrl
    EXT = data.format
  }
})

export function clothingUrl(gender, type, id, drawable, texture = 0) {
  const folder = type === 'prop' ? `prop_${id}`
    : type === 'overlay' ? `overlay_${id}`
    : `${id}`
  // Texture 0 and overlays have no suffix
  const suffix = type !== 'overlay' && texture > 0 ? `_${texture}` : ''
  return `${BASE}/${gender}/${folder}/${drawable}${suffix}.${EXT}`
}

export function tattooUrl(gender, collection, overlay) {
  // Tattoo files are saved lowercased
  return `${BASE}/${gender}/tattoos/${collection.toLowerCase()}/${overlay.toLowerCase()}.${EXT}`
}

export const vehicleUrl = (model) => `${BASE}/vehicles/${model}.${EXT}`
export const objectUrl = (model) => `${BASE}/objects/${model}.${EXT}`
clothingUrl('male', 'component', 11, 5)
// → 'https://cfx-nui-uz_AutoShot/shots/male/11/5.png'

clothingUrl('male', 'overlay', 1, 3)
// → 'https://cfx-nui-uz_AutoShot/shots/male/overlay_1/3.png'

tattooUrl('female', 'mpbeach_overlays', 'MP_Bea_F_Back_000')
// → 'https://cfx-nui-uz_AutoShot/shots/female/tattoos/mpbeach_overlays/mp_bea_f_back_000.png'

Missing Photos

Not every item has a photo: a category may not be captured yet, or a new addon was added after the last capture. Swap in a placeholder when the image fails to load:

<img src="https://cfx-nui-uz_AutoShot/shots/male/11/5.png"
     onerror="this.onerror = null; this.src = 'img/placeholder.png'">

Photos captured after the resource started return an error until uz_AutoShot is restarted. See How Photos Are Served.


React: Thumbnail Grid

A React component that displays clothing thumbnails with a placeholder fallback:

import { useState } from 'react'
import { clothingUrl } from './photos'

function Thumb({ src, alt }) {
  const [failed, setFailed] = useState(false)
  if (failed) return <div className="thumb-placeholder" />
  return <img src={src} alt={alt} loading="lazy" onError={() => setFailed(true)} />
}

function ClothingGrid({ gender, type, categoryId, numDrawables }) {
  if (!numDrawables) return <div className="empty">No items available</div>

  return (
    <div className="clothing-grid">
      {Array.from({ length: numDrawables }, (_, drawable) => (
        <button
          key={drawable}
          className="clothing-item"
          onClick={() => applyClothing({ itemType: type, id: categoryId, drawable, texture: 0 })}
        >
          <Thumb src={clothingUrl(gender, type, categoryId, drawable)} alt={`Drawable ${drawable}`} />
          <span>{drawable}</span>
        </button>
      ))}
    </div>
  )
}

function applyClothing(item) {
  fetch(`https://YOUR_SCRIPT/applyClothing`, {
    method: 'POST',
    body: JSON.stringify(item),
  })
}

numDrawables comes from your Lua side, for example GetNumberOfPedDrawableVariations(ped, 11).

.clothing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 8px;
  padding: 12px;
}

.clothing-item {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 4px;
  cursor: pointer;
  transition: border-color 0.15s;
}

.clothing-item:hover {
  border-color: rgba(255, 255, 255, 0.3);
}

.clothing-item img,
.thumb-placeholder {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
}

Display vehicle thumbnails from uz_AutoShot:

import { vehicleUrl } from './photos'
// Thumb: the component from the thumbnail grid example above

function VehicleGallery({ vehicles }) {
  return (
    <div className="clothing-grid">
      {vehicles.map((model) => (
        <button key={model} className="clothing-item" onClick={() => spawnVehicle(model)}>
          <Thumb src={vehicleUrl(model)} alt={model} />
          <span>{model}</span>
        </button>
      ))}
    </div>
  )
}

function spawnVehicle(model) {
  fetch(`https://YOUR_SCRIPT/spawnVehicle`, {
    method: 'POST',
    body: JSON.stringify({ model }),
  })
}

Lua: Clothing Shop Integration

Example for a clothing shop script that uses uz_AutoShot photos:

-- Open shop with thumbnails from uz_AutoShot
RegisterCommand('clothingshop', function()
    local ped = PlayerPedId()
    local gender = (GetEntityModel(ped) == `mp_m_freemode_01`) and 'male' or 'female'

    -- Build photo URLs for all tops
    local items = {}
    local numDrawables = GetNumberOfPedDrawableVariations(ped, 11)

    for i = 0, numDrawables - 1 do
        items[#items + 1] = {
            drawable = i,
            price = math.random(100, 5000),
            photo = exports['uz_AutoShot']:getPhotoURL(gender, 'component', 11, i, 0)
        }
    end

    -- Send to NUI
    SendNUIMessage({
        type = 'openShop',
        category = 'Tops',
        items = items,
    })
    SetNuiFocus(true, true)
end)

Lua: Tattoo Shop Integration

Tattoo photos are keyed by collection and overlay name, the same fields every tattoo list has. With a list in the illenium-appearance format:

-- tattoos = { ZONE_TORSO = { { label = '...', collection = 'mpbeach_overlays', hashMale = '...', hashFemale = '...' }, ... }, ... }
local function buildTattooItems(tattoos)
    local ped = PlayerPedId()
    local gender = (GetEntityModel(ped) == `mp_m_freemode_01`) and 'male' or 'female'
    local items = {}

    for zone, list in pairs(tattoos) do
        for _, tattoo in ipairs(list) do
            local overlay = gender == 'male' and tattoo.hashMale or tattoo.hashFemale
            if overlay and overlay ~= '' then
                items[#items + 1] = {
                    zone = zone,
                    label = tattoo.label,
                    photo = exports['uz_AutoShot']:getTattooURL(gender, tattoo.collection, overlay),
                }
            end
        end
    end

    return items
end

Male and female tattoos are captured separately. Switch the studio ped to Female (or turn on Capture both genders) in /shotmaker so both sets exist.


Lua: Vehicle Dealership Integration

Use vehicle photos in a dealership script:

RegisterCommand('dealership', function()
    local vehicles = {}
    local models = GetAllVehicleModels()

    for _, modelName in ipairs(models) do
        local hash = GetHashKey(modelName)
        local classId = GetVehicleClassFromName(hash)

        vehicles[#vehicles + 1] = {
            model = modelName,
            class = classId,
            price = math.random(10000, 500000),
            photo = exports['uz_AutoShot']:getVehiclePhotoURL(modelName)
        }
    end

    SendNUIMessage({
        type = 'openDealership',
        vehicles = vehicles,
    })
    SetNuiFocus(true, true)
end)

On this page