🔨 KICKSTARTER DEMO 99% - Tools (63), Blacksmith (8), Repair UI (6), Ivan NPC (5)

- Generated ALL 63 tool sprites (10 types × 6 tiers + 3 extras)
- Completed Blacksmith Building sprites (8/8)
- Completed Repair Bench UI (6/6)
- Generated Ivan Blacksmith NPC sprites with master reference (5/6)
- Confirmed NPC eye style: friendly NPCs have red eyes WITH pupils
- Total: 112 production-ready sprites in 30min session
- Demo launch ready, only organization remaining
This commit is contained in:
2026-01-05 10:05:19 +01:00
parent 5d60b17399
commit c1c40446ec
7 changed files with 563 additions and 2 deletions

337
tools/asset_browser.html Normal file
View File

@@ -0,0 +1,337 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🎨 NovaFarma Asset Browser</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #1a1a1a;
color: #fff;
padding: 20px;
}
.header {
text-align: center;
padding: 30px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 15px;
margin-bottom: 30px;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.filters {
display: flex;
gap: 15px;
margin-bottom: 30px;
flex-wrap: wrap;
justify-content: center;
}
.filter-btn {
padding: 12px 24px;
background: #2d2d2d;
border: 2px solid #444;
border-radius: 25px;
color: #fff;
cursor: pointer;
transition: all 0.3s;
font-size: 1em;
}
.filter-btn:hover {
background: #667eea;
border-color: #667eea;
transform: translateY(-2px);
}
.filter-btn.active {
background: #667eea;
border-color: #667eea;
}
.search-box {
width: 100%;
max-width: 600px;
margin: 0 auto 30px;
padding: 15px 25px;
background: #2d2d2d;
border: 2px solid #444;
border-radius: 30px;
color: #fff;
font-size: 1.1em;
text-align: center;
}
.search-box:focus {
outline: none;
border-color: #667eea;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 50px;
}
.asset-card {
background: #2d2d2d;
border-radius: 15px;
padding: 15px;
border: 2px solid #444;
transition: all 0.3s;
cursor: pointer;
position: relative;
}
.asset-card:hover {
transform: translateY(-5px);
border-color: #667eea;
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
}
.asset-card img {
width: 100%;
height: 200px;
object-fit: contain;
background: #1a1a1a;
border-radius: 10px;
margin-bottom: 10px;
image-rendering: pixelated;
}
.asset-name {
font-size: 0.9em;
text-align: center;
word-break: break-word;
color: #aaa;
}
.asset-size {
font-size: 0.75em;
text-align: center;
color: #666;
margin-top: 5px;
}
.category-section {
margin-bottom: 50px;
}
.category-title {
font-size: 2em;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 3px solid #667eea;
}
.copy-badge {
position: absolute;
top: 10px;
right: 10px;
background: #4CAF50;
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 0.8em;
opacity: 0;
transition: opacity 0.3s;
}
.asset-card.copied .copy-badge {
opacity: 1;
}
</style>
</head>
<body>
<div class="header">
<h1>🎨 NovaFarma Asset Browser</h1>
<p>Visual asset picker for Tiled - Click any asset to copy its path!</p>
</div>
<input type="text" class="search-box" id="search"
placeholder="🔍 Pretraži assete... (npr. 'tree', 'grass', 'tent')">
<div class="filters" id="filters">
<button class="filter-btn active" onclick="filterCategory('all')">Vsi Asseti</button>
<button class="filter-btn" onclick="filterCategory('teren')">🌍 Teren</button>
<button class="filter-btn" onclick="filterCategory('narava')">🌿 Narava</button>
<button class="filter-btn" onclick="filterCategory('zgradbe')">🏚️ Zgradbe</button>
<button class="filter-btn" onclick="filterCategory('objekti')">📦 Objekti</button>
<button class="filter-btn" onclick="filterCategory('crops')">🌾 Crops</button>
<button class="filter-btn" onclick="filterCategory('biomi')">🗺️ Biomi</button>
</div>
<div id="gallery-container"></div>
<script>
// Asset categories and their file paths
const assetPaths = {
teren: 'assets/slike 🟢/teren',
narava: 'assets/slike 🟢/narava',
zgradbe: 'assets/slike 🟢/zgradbe',
objekti: 'assets/slike 🟢/objekti',
crops: 'assets/crops/faza1',
biomi: 'assets/slike 🟢/biomi'
};
let currentFilter = 'all';
let allAssets = [];
// Load assets dynamically
async function loadAssets() {
const container = document.getElementById('gallery-container');
// For demo, manually list known assets
const knownAssets = [
// Teren
{ path: 'assets/slike 🟢/teren/teren_dirt_path_style32.png', category: 'teren', name: 'Dirt Path' },
{ path: 'assets/slike 🟢/teren/teren_corrupted_ground_style32.png', category: 'teren', name: 'Corrupted Ground' },
{ path: 'assets/slike 🟢/teren/teren_lava_ground_style32.png', category: 'teren', name: 'Lava Ground' },
{ path: 'assets/slike 🟢/teren/teren_roots_ground_style32.png', category: 'teren', name: 'Roots Ground' },
// Narava
{ path: 'assets/slike 🟢/narava/rastline/narava_rastline_grass_tile.png', category: 'narava', name: 'Grass Tile' },
{ path: 'assets/slike 🟢/narava/rastline/narava_rastline_grass_basic_style32.png', category: 'narava', name: 'Basic Grass' },
{ path: 'assets/slike 🟢/narava/rastline/narava_rastline_grass_flowers_style32.png', category: 'narava', name: 'Grass with Flowers' },
// Crops (spritesheets)
{ path: 'assets/maps 🟣/crop_spritesheets/carrots_spritesheet.png', category: 'crops', name: 'Carrots (All Seasons)' },
{ path: 'assets/maps 🟣/crop_spritesheets/corn_spritesheet.png', category: 'crops', name: 'Corn (All Seasons)' },
{ path: 'assets/maps 🟣/crop_spritesheets/lettuces_spritesheet.png', category: 'crops', name: 'Lettuce (All Seasons)' },
{ path: 'assets/maps 🟣/crop_spritesheets/potatos_spritesheet.png', category: 'crops', name: 'Potatoes (All Seasons)' },
{ path: 'assets/maps 🟣/crop_spritesheets/pumpkins_spritesheet.png', category: 'crops', name: 'Pumpkins (All Seasons)' },
{ path: 'assets/maps 🟣/crop_spritesheets/tomatoes_spritesheet.png', category: 'crops', name: 'Tomatoes (All Seasons)' },
];
allAssets = knownAssets;
renderAssets(allAssets);
}
function renderAssets(assets) {
const container = document.getElementById('gallery-container');
// Group by category
const grouped = {};
assets.forEach(asset => {
if (!grouped[asset.category]) grouped[asset.category] = [];
grouped[asset.category].push(asset);
});
container.innerHTML = '';
for (const [category, items] of Object.entries(grouped)) {
const section = document.createElement('div');
section.className = 'category-section';
const title = document.createElement('h2');
title.className = 'category-title';
title.textContent = getCategoryTitle(category);
section.appendChild(title);
const gallery = document.createElement('div');
gallery.className = 'gallery';
items.forEach(asset => {
const card = createAssetCard(asset);
gallery.appendChild(card);
});
section.appendChild(gallery);
container.appendChild(section);
}
}
function createAssetCard(asset) {
const card = document.createElement('div');
card.className = 'asset-card';
card.onclick = () => copyPath(asset.path, card);
const img = document.createElement('img');
img.src = '../../' + asset.path;
img.alt = asset.name;
img.onerror = () => {
img.src = 'data:image/svg+xml,' + encodeURIComponent(
'<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><rect fill="#333" width="200" height="200"/><text x="50%" y="50%" fill="#666" text-anchor="middle">No Preview</text></svg>'
);
};
const name = document.createElement('div');
name.className = 'asset-name';
name.textContent = asset.name;
const badge = document.createElement('div');
badge.className = 'copy-badge';
badge.textContent = '✓ Copied!';
card.appendChild(badge);
card.appendChild(img);
card.appendChild(name);
return card;
}
function getCategoryTitle(category) {
const titles = {
teren: '🌍 Teren (Ground Tiles)',
narava: '🌿 Narava (Nature)',
zgradbe: '🏚️ Zgradbe (Buildings)',
objekti: '📦 Objekti (Objects)',
crops: '🌾 Crops (All Seasons)',
biomi: '🗺️ Biomi (Biomes)'
};
return titles[category] || category;
}
function copyPath(path, card) {
navigator.clipboard.writeText(path);
card.classList.add('copied');
setTimeout(() => card.classList.remove('copied'), 2000);
console.log('Copied path:', path);
}
function filterCategory(category) {
currentFilter = category;
// Update button states
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
event.target.classList.add('active');
if (category === 'all') {
renderAssets(allAssets);
} else {
const filtered = allAssets.filter(a => a.category === category);
renderAssets(filtered);
}
}
// Search functionality
document.getElementById('search').addEventListener('input', (e) => {
const query = e.target.value.toLowerCase();
const filtered = allAssets.filter(a =>
a.name.toLowerCase().includes(query) ||
a.path.toLowerCase().includes(query)
);
renderAssets(filtered);
});
// Load on start
loadAssets();
</script>
</body>
</html>