Генерація каталогу ресурсів
Створення візуальних каталогів 3D-ресурсів з автоматично згенерованими мініатюрами та метаданими.
Огляд робочого процесу
Бібліотека ресурсів
3D-моделі
Обробка
Трансляція в SVF2
Генерація мініатюр
Витягнення метаданих
Генерація каталогу
Створення індексу
Побудова сітки
Додавання пошуку
Результат
HTML-галерея
JSON API
Статичний сайт
Підхід CLI
Крок 1: Генерація мініатюр
mkdir -p ./catalog/thumbnails
raps object list media-assets --output json | jq -r '.[].key' | while read key; do
URN=$(raps object urn media-assets "$key" --output plain)
# Check if translated
STATUS=$(raps translate manifest "$URN" 2>/dev/null | jq -r '.status // "none"')
if [ "$STATUS" = "success" ]; then
SAFE_NAME=$(echo "$key" | tr '/' '_' | sed 's/\.[^.]*$//')
raps derivative thumbnail "$URN" --output "./catalog/thumbnails/${SAFE_NAME}.png"
echo "Generated: ${SAFE_NAME}.png"
fi
done
Крок 2: Витягнення метаданих
echo "[]" > ./catalog/assets.json
raps object list media-assets --output json | jq -r '.[].key' | while read key; do
URN=$(raps object urn media-assets "$key" --output plain)
STATUS=$(raps translate manifest "$URN" 2>/dev/null | jq -r '.status // "none"')
if [ "$STATUS" = "success" ]; then
SAFE_NAME=$(echo "$key" | tr '/' '_' | sed 's/\.[^.]*$//')
# Get metadata
META=$(raps derivative metadata "$URN" --output json 2>/dev/null || echo '{}')
# Add to catalog
jq --arg key "$key" \
--arg name "$SAFE_NAME" \
--argjson meta "$META" \
'. += [{
key: $key,
name: $name,
thumbnail: ($name + ".png"),
metadata: $meta
}]' ./catalog/assets.json > ./catalog/assets.tmp.json
mv ./catalog/assets.tmp.json ./catalog/assets.json
fi
done
Крок 3: Генерація HTML-каталогу
cat > ./catalog/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>3D Asset Catalog</title>
<style>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; margin: 0; padding: 20px; background: #1a1a2e; color: #eee; }
h1 { text-align: center; }
.search { width: 100%; padding: 12px; font-size: 16px; margin-bottom: 20px; border-radius: 8px; border: none; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 20px; }
.asset { background: #16213e; border-radius: 12px; overflow: hidden; transition: transform 0.2s; }
.asset:hover { transform: scale(1.02); }
.asset img { width: 100%; height: 180px; object-fit: contain; background: #0f3460; }
.asset-info { padding: 12px; }
.asset-name { font-weight: 600; margin-bottom: 4px; }
.asset-meta { font-size: 12px; color: #888; }
.tags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 8px; }
.tag { background: #0f3460; padding: 2px 8px; border-radius: 4px; font-size: 11px; }
</style>
</head>
<body>
<h1>3D Asset Catalog</h1>
<input type="text" class="search" placeholder="Search assets..." onkeyup="filter(this.value)">
<div class="grid" id="grid"></div>
<script>
let assets = [];
fetch('assets.json')
.then(r => r.json())
.then(data => { assets = data; render(assets); });
function render(data) {
document.getElementById('grid').innerHTML = data.map(a => `
<div class="asset" data-name="${a.name.toLowerCase()}">
<img src="thumbnails/${a.thumbnail}" alt="${a.name}" onerror="this.src='placeholder.png'">
<div class="asset-info">
<div class="asset-name">${a.name}</div>
<div class="asset-meta">${a.key}</div>
<div class="tags">
${(a.metadata.format || []).map(f => `<span class="tag">${f}</span>`).join('')}
</div>
</div>
</div>
`).join('');
}
function filter(query) {
const q = query.toLowerCase();
const filtered = assets.filter(a => a.name.toLowerCase().includes(q) || a.key.toLowerCase().includes(q));
render(filtered);
}
</script>
</body>
</html>
EOF
Конвеєр CI/CD
# .github/workflows/asset-catalog.yml
name: Asset Catalog Generation
on:
schedule:
- cron: '0 3 * * *' # Daily at 3 AM
workflow_dispatch:
env:
BUCKET: media-assets
jobs:
generate-catalog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install RAPS
run: cargo install raps
- name: Generate thumbnails
env:
APS_CLIENT_ID: ${{ secrets.APS_CLIENT_ID }}
APS_CLIENT_SECRET: ${{ secrets.APS_CLIENT_SECRET }}
run: |
mkdir -p ./catalog/thumbnails
raps object list "$BUCKET" --output json | jq -r '.[].key' | while read key; do
URN=$(raps object urn "$BUCKET" "$key" --output plain)
STATUS=$(raps translate manifest "$URN" 2>/dev/null | jq -r '.status // "none"')
if [ "$STATUS" = "success" ]; then
SAFE=$(echo "$key" | tr '/' '_' | sed 's/\.[^.]*$//')
raps derivative thumbnail "$URN" --output "./catalog/thumbnails/${SAFE}.png" 2>/dev/null || true
fi
done
- name: Generate catalog data
env:
APS_CLIENT_ID: ${{ secrets.APS_CLIENT_ID }}
APS_CLIENT_SECRET: ${{ secrets.APS_CLIENT_SECRET }}
run: |
echo "[]" > ./catalog/assets.json
raps object list "$BUCKET" --output json | jq -r '.[].key' | while read key; do
URN=$(raps object urn "$BUCKET" "$key" --output plain)
STATUS=$(raps translate manifest "$URN" 2>/dev/null | jq -r '.status // "none"')
if [ "$STATUS" = "success" ]; then
SAFE=$(echo "$key" | tr '/' '_' | sed 's/\.[^.]*$//')
META=$(raps derivative metadata "$URN" --output json 2>/dev/null | jq -c '.' || echo '{}')
jq --arg k "$key" --arg n "$SAFE" --argjson m "$META" \
'. += [{key:$k, name:$n, thumbnail:($n+".png"), metadata:$m}]' \
./catalog/assets.json > tmp.json && mv tmp.json ./catalog/assets.json
fi
done
- name: Create HTML
run: |
# Generate index.html (see CLI section)
echo "HTML catalog generated"
- name: Deploy to Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./catalog
Потік конвеєра
Щодня о 3:00
Розклад
→
Генерація
Перелік ресурсів
Генерація мініатюр
Витягнення метаданих
Побудова HTML
→
Розгортання
GitHub Pages
Інтеграція MCP
Генерація каталогу
User: "Create a visual catalog of all our 3D assets"
Користувач
AI-асистент
RAPS MCP
APS Cloud
Користувач→AIЗгенерувати каталог ресурсів
AI→MCPaps_object_list(bucket)
MCP→APSПерелік об’єктів
APS←MCPСписок об’єктів
loopAI→MCPaps_derivative_thumbnail(urn)
loopAI→MCPaps_derivative_metadata(urn)
AI→AIГенерація HTML-галереї
AI→КористувачКаталог готовий
Відповідь AI:
Згенеровано каталог ресурсів з 78 елементами:
Категорії:
- Персонажі: 12
- Середовища: 8
- Реквізит: 45
- Транспорт: 13
Формати:
- FBX: 52
- OBJ: 18
- glTF: 8
Пошук у каталозі
User: "Find all vehicle assets"
Відповідь AI:
Знайдено 13 ресурсів транспорту:
Назва Формат Полігони sports_car_01 FBX 45,000 truck_pickup FBX 32,000 motorcycle OBJ 18,000 bicycle glTF 8,500 … … … Бажаєте переглянути мініатюри?
Додаткові можливості
Організація за категоріями
# Organize by file path/type
cat ./catalog/assets.json | jq '
group_by(.key | split("/")[0]) |
map({
category: .[0].key | split("/")[0],
count: length,
assets: .
})'
Пошуковий індекс
# Create search-friendly index
cat ./catalog/assets.json | jq '[.[] | {
name: .name,
key: .key,
searchText: "\(.name) \(.key) \(.metadata | tostring)"
}]' > ./catalog/search-index.json
Ліниве завантаження
// In catalog HTML - load thumbnails on scroll
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));