<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
<title>Tiles Grid + PHP Gallery + Objects + Lines + Attributes</title>
<script>
// Cache timestamp for all resources
const timestamp = Date.now();
// Apply cache-busting to CSS
document.write(`<link rel="stylesheet" href="styles.css?v=${timestamp}">`);
</script>
</head>
<body>
<div class="topbar">
<button id="settingsBtn" title="Settings">βοΈ</button>
<button id="imagesBtn" title="Images">πΌοΈ</button>
<button id="tilemapBtn" title="Tile Map">πΊοΈ</button>
<button id="objectViewBtn" title="Object View">ποΈ</button>
<button id="resetBtn" title="Reset view">π</button>
</div>
<!-- Settings panel -->
<div class="panel" id="settingsPanel">
<div class="settings-track">
<div class="stepper" data-key="tileWidth"><label>tileWidth</label>
<div class="stepper-controls"><button>-</button><input type="number" value="16"><button>+</button></div>
</div>
<div class="stepper" data-key="tileHeight"><label>tileHeight</label>
<div class="stepper-controls"><button>-</button><input type="number" value="16"><button>+</button></div>
</div>
<div class="stepper" data-key="xOffset"><label>xOffset</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
<div class="stepper" data-key="yOffset"><label>yOffset</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
<div class="stepper" data-key="Hspacing"><label>Hspacing</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
<div class="stepper" data-key="Vspacing"><label>Vspacing</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
</div>
</div>
<!-- Images panel (PHP-driven) -->
<div class="panel" id="imagesPanel">
<div class="folder-bar">
<strong style="margin-right:.5rem">π</strong>
<div class="crumbs" id="crumbs"></div>
<div style="flex:1"></div>
<button id="goUpBtn" title="Up one level" style="background:none;border:1px solid #2a2a2a;border-radius:.4rem;padding:.35rem .6rem;color:var(--ink)">β¬οΈ Up</button>
<button id="refreshBtn" title="Refresh" style="margin-left:.4rem;background:none;border:1px solid #2a2a2a;border-radius:.4rem;padding:.35rem .6rem;color:var(--ink)">π</button>
</div>
<div class="folders-track" id="foldersTrack"></div>
<div class="empty-hint" id="emptyFolders" hidden>No folders here.</div>
<div class="gallery-track" id="galleryTrack"></div>
<div class="empty-hint" id="emptyImages" hidden>No images in this folder.</div>
</div>
<div class="content">
<!-- Objects bar -->
<div class="objects" id="objectsBar">
<div id="objectPills"></div>
<div class="controls">
<button id="addObjectBtn">β New Object</button>
<button id="renameObjectBtn">βοΈ Rename</button>
<button id="removeObjectBtn">ποΈ Delete</button>
</div>
</div>
<!-- Lines (for active object) -->
<div class="lines" id="linesBar">
<div id="linePills"></div>
<div class="controls">
<button id="addLineBtn">β Add Line</button>
<button id="renameLineBtn">βοΈ Rename</button>
<button id="removeLineBtn">ποΈ Remove</button>
<button id="clearLineBtn">π§Ή Clear Line</button>
</div>
</div>
<!-- Tank (active line) -->
<div class="tank" id="tankBar">
<div class="count" id="tankCount">0 items</div>
<div class="tank-strip" id="tankStrip" title="Captured tiles for the selected line appear here"></div>
</div>
<div class="meta" id="meta">Open an image, then tap grid tiles to add thumbnails to the selected line.</div>
<div class="stage" id="stage">
<div class="viewport" id="viewport">
<div class="img-layer" id="imgLayer"></div>
<div class="grid" id="grid"></div>
</div>
</div>
</div>
<!-- Full-screen Object View -->
<div class="overlay" id="objectOverlay" aria-hidden="true">
<div class="ov-wrap">
<div class="ov-head">
<h2 id="ovTitle">Object</h2>
<button id="closeOverlayBtn">β Close</button>
</div>
<div class="ov-body" id="ovBody"></div>
</div>
</div>
<script>
// Cache timestamp for cache busting (already defined above for CSS)
if (typeof timestamp === 'undefined') {
const timestamp = Date.now();
}
// Global error handler
window.addEventListener('error', (e) => {
alert(`JavaScript Error: ${e.message}\nFile: ${e.filename}\nLine: ${e.lineno}`);
});
// Script loader with caching control and alerts
function loadScript(src, callback) {
alert(`Loading: ${src}`);
const script = document.createElement('script');
script.src = `${src}?v=${timestamp}`;
script.onload = () => {
alert(`β Loaded: ${src}`);
callback();
};
script.onerror = () => {
alert(`β Failed to load: ${src}`);
};
document.head.appendChild(script);
}
// Load scripts in sequence with verification and alerts
function initializeApp() {
alert('Starting app initialization...');
loadScript('core.js', () => {
if (typeof initializeCore !== 'function') {
alert('β Core module not found');
return;
}
alert('β Core module ready');
loadScript('workspace.js', () => {
if (typeof initializeWorkspace !== 'function') {
alert('β Workspace module not found');
return;
}
alert('β Workspace module ready');
loadScript('attributes.js', () => {
if (typeof initializeAttributes !== 'function') {
alert('β Attributes module not found');
return;
}
alert('β Attributes module ready');
loadScript('tilemap.js', () => {
if (typeof initializeTilemap !== 'function') {
alert('β Tilemap module not found');
return;
}
alert('β Tilemap module ready');
loadScript('gallery.js', () => {
if (typeof initializeGallery !== 'function') {
alert('β Gallery module not found');
return;
}
alert('β Gallery module ready');
// All scripts loaded - initialize
alert('All modules loaded. Starting initialization...');
try {
alert('Initializing Core...');
initializeCore();
alert('β Core initialized');
alert('Initializing Workspace...');
initializeWorkspace();
alert('β Workspace initialized');
alert('Initializing Attributes...');
initializeAttributes();
alert('β Attributes initialized');
alert('Initializing Tilemap...');
initializeTilemap();
alert('β Tilemap initialized');
alert('Initializing Gallery...');
initializeGallery();
alert('β Gallery initialized');
alert('π App initialization complete!');
} catch (error) {
alert(`Initialization failed: ${error.message}`);
}
});
});
});
});
});
}
// Start when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
alert('DOM ready, starting app...');
initializeApp();
});
</script>
</body>
</html>