Integration Examples
Code examples showing how to integrate uz_AutoShot thumbnails into clothing scripts, vehicle shops, and NUI panels.
Integration Examples
These examples show how to use uz_AutoShot's API and exports in real-world scenarios. Photos are served via FiveM's cfx-nui protocol, while metadata is available through the HTTP API.
NUI Callback (Lua to JS)
The simplest way to pass the API URL from Lua to your NUI:
-- client.lua (your clothing script)
RegisterNUICallback('getClothingPhotos', function(data, cb)
local url = exports['uz_AutoShot']:getManifestURL(data.gender, data.type, data.id)
PerformHttpRequest(url, function(status, body)
if status ~= 200 then
cb({ items = {} })
return
end
local decoded = json.decode(body)
cb({ items = decoded and decoded.items or {} })
end, 'GET')
end)// nui/script.js
const response = await fetch(
`https://cfx-nui-YOUR_SCRIPT/getClothingPhotos`,
{
method: 'POST',
body: JSON.stringify({ gender: 'male', type: 'component', id: 11 })
}
)
const { items } = await response.json()This approach routes through Lua. For better performance, fetch directly from JS. See the next example.
Direct Photo URL (cfx-nui)
Photos are accessible directly via cfx-nui protocol, no HTTP server needed for images:
// Build photo URL directly
function getPhotoUrl(gender, type, id, drawable, texture = 0) {
const prefix = type === 'prop' ? `prop_${id}`
: type === 'overlay' ? `overlay_${id}`
: `${id}`
const texSuffix = type === 'overlay' ? '' : (texture > 0 ? `_${texture}` : '')
return `https://cfx-nui-uz_AutoShot/shots/${gender}/${prefix}/${drawable}${texSuffix}.png`
}
// Clothing
getPhotoUrl('male', 'component', 11, 5, 0)
// → 'https://cfx-nui-uz_AutoShot/shots/male/11/5_0.png'
// Overlay
getPhotoUrl('male', 'overlay', 1, 3)
// → 'https://cfx-nui-uz_AutoShot/shots/male/overlay_1/3.png'
// Vehicle and object URLs use a simpler pattern
function getVehicleUrl(model) {
return `https://cfx-nui-uz_AutoShot/shots/vehicles/${model}.png`
}
function getObjectUrl(model) {
return `https://cfx-nui-uz_AutoShot/shots/objects/${model}.png`
}React: Thumbnail Grid
A React component that displays clothing thumbnails:
import { useState, useEffect } from 'react'
const SHOTS_BASE = 'https://cfx-nui-uz_AutoShot/shots'
function ClothingGrid({ gender, type, categoryId, numDrawables }) {
const prefix = type === 'prop' ? `prop_${categoryId}`
: type === 'overlay' ? `overlay_${categoryId}`
: categoryId
const items = Array.from({ length: numDrawables }, (_, i) => ({
drawable: i,
texture: 0,
url: `${SHOTS_BASE}/${gender}/${prefix}/${i}.png`,
}))
if (!items.length) return <div className="empty">No items available</div>
return (
<div className="clothing-grid">
{items.map((item) => (
<button
key={item.drawable}
className="clothing-item"
onClick={() => applyClothing({ type, id: categoryId, ...item })}
>
<img
src={item.url}
alt={`Drawable ${item.drawable}`}
loading="lazy"
/>
<span>{item.drawable}</span>
</button>
))}
</div>
)
}
function applyClothing(item) {
fetch(`https://cfx-nui-YOUR_SCRIPT/applyClothing`, {
method: 'POST',
body: JSON.stringify({
itemType: item.type,
id: item.id,
drawable: item.drawable,
texture: item.texture,
}),
})
}.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 {
width: 100%;
aspect-ratio: 1;
object-fit: contain;
}React: Vehicle Gallery
Display vehicle thumbnails from uz_AutoShot:
const SHOTS_BASE = 'https://cfx-nui-uz_AutoShot/shots'
function VehicleGallery({ vehicles }) {
return (
<div className="clothing-grid">
{vehicles.map((model) => (
<button key={model} className="clothing-item" onClick={() => spawnVehicle(model)}>
<img
src={`${SHOTS_BASE}/vehicles/${model}.png`}
alt={model}
loading="lazy"
/>
<span>{model}</span>
</button>
))}
</div>
)
}
function spawnVehicle(model) {
fetch(`https://cfx-nui-YOUR_SCRIPT/spawnVehicle`, {
method: 'POST',
body: JSON.stringify({ model }),
})
}React: Category Selector with Thumbnails
A full clothing browser with category tabs and thumbnail grid:
import { useState, useEffect, useCallback } from 'react'
const CATEGORIES = [
{ type: 'component', id: 11, label: 'Tops' },
{ type: 'component', id: 4, label: 'Pants' },
{ type: 'component', id: 6, label: 'Shoes' },
{ type: 'component', id: 1, label: 'Masks' },
{ type: 'component', id: 8, label: 'Undershirt' },
{ type: 'prop', id: 0, label: 'Hats' },
{ type: 'prop', id: 1, label: 'Glasses' },
{ type: 'overlay', id: 1, label: 'Facial Hair' },
{ type: 'overlay', id: 2, label: 'Eyebrows' },
{ type: 'overlay', id: 4, label: 'Makeup' },
]
function ClothingBrowser({ gender = 'male' }) {
const [activeCategory, setActiveCategory] = useState(CATEGORIES[0])
const [items, setItems] = useState([])
const [selected, setSelected] = useState(null)
useEffect(() => {
const { type, id } = activeCategory
fetch(`http://127.0.0.1:3959/api/manifest/${gender}/${type}/${id}`)
.then(res => res.json())
.then(data => setItems(data.items || []))
.catch(() => setItems([]))
}, [gender, activeCategory])
const handleApply = useCallback((item) => {
setSelected(item.drawable)
fetch(`https://cfx-nui-YOUR_SCRIPT/applyClothing`, {
method: 'POST',
body: JSON.stringify({
itemType: item.type,
id: item.id,
drawable: item.drawable,
texture: item.texture,
}),
})
}, [])
return (
<div className="clothing-browser">
<div className="categories">
{CATEGORIES.map((cat) => (
<button
key={`${cat.type}_${cat.id}`}
className={activeCategory === cat ? 'active' : ''}
onClick={() => setActiveCategory(cat)}
>
{cat.label}
</button>
))}
</div>
<div className="items-grid">
{items.map((item) => (
<button
key={`${item.drawable}_${item.texture}`}
className={`item ${selected === item.drawable ? 'selected' : ''}`}
onClick={() => handleApply(item)}
>
<img src={item.url} alt={`#${item.drawable}`} loading="lazy" />
</button>
))}
</div>
</div>
)
}React: Custom Hook
A reusable hook for fetching clothing data:
import { useState, useEffect } from 'react'
export function useClothingItems(gender, type, categoryId) {
const [items, setItems] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => {
if (!gender || !type || categoryId === undefined) return
setLoading(true)
setError(null)
fetch(`http://127.0.0.1:3959/api/manifest/${gender}/${type}/${categoryId}`)
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`)
return res.json()
})
.then(data => {
setItems(data.items || [])
setLoading(false)
})
.catch(err => {
setError(err.message)
setItems([])
setLoading(false)
})
}, [gender, type, categoryId])
return { items, loading, error }
}
// Usage:
function TopsGrid() {
const { items, loading, error } = useClothingItems('male', 'component', 11)
if (loading) return <Spinner />
if (error) return <p>Error: {error}</p>
return (
<div className="grid">
{items.map(item => (
<img key={item.drawable} src={item.url} alt={`#${item.drawable}`} />
))}
</div>
)
}Check if Photo Exists
Before displaying a thumbnail, check if it was captured:
async function hasPhoto(gender, type, id, drawable, texture = 0) {
const params = new URLSearchParams({ gender, type, id, drawable, texture })
const res = await fetch(`http://127.0.0.1:3959/api/exists?${params}`)
const data = await res.json()
return data.exists
}
// Clothing
const exists = await hasPhoto('male', 'component', 11, 5)
if (exists) {
img.src = `https://cfx-nui-uz_AutoShot/shots/male/11/5_0.png`
} else {
img.src = '/placeholder.png'
}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) == GetHashKey('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: 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)