document.addEventListener('DOMContentLoaded', () => { // Initialize PIXI application const app = new PIXI.Application({ width: 800, height: 600, backgroundColor: 0x111111, view: document.getElementById('previewContainer') }); // File upload handling const setupFileUpload = () => { const dropZone = document.getElementById('dropZone'); const fileInput = document.getElementById('fileInput'); const uploadBtn = document.getElementById('uploadBtn'); const resetBtn = document.getElementById('zoomResetBtn'); // Set up drag and drop ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } function highlight() { dropZone.classList.add('border-indigo-400'); } function unhighlight() { dropZone.classList.remove('border-indigo-400'); } ['dragenter', 'dragover'].forEach(eventName => { dropZone.addEventListener(eventName, highlight, false); }); ['dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, unhighlight, false); }); dropZone.addEventListener('drop', handleDrop, false); function handleDrop(e) { const files = e.dataTransfer.files; handleFiles(files); } uploadBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', () => handleFiles(fileInput.files)); function handleFiles(files) { if (!files.length) return; const file = files[0]; if (!file.type.startsWith('image/')) { alert('Please upload an image file.'); return; } const reader = new FileReader(); reader.onload = async (e) => { await loadCharacter(e.target.result); }; reader.readAsDataURL(file); } resetBtn.addEventListener('click', () => { app.stage.removeChildren(); document.querySelector('#previewContainer p').style.display = 'block'; }); }; // Character rigging functionality const loadCharacter = async (imageSrc) => { try { // Load character texture const texture = await PIXI.Texture.fromURL(imageSrc); const sprite = new PIXI.Sprite(texture); // Center and scale sprite sprite.anchor.set(0.5); sprite.x = app.screen.width / 2; sprite.y = app.screen.height / 2; sprite.scale.set(0.5); app.stage.addChild(sprite); document.querySelector('#previewContainer p').style.display = 'none'; // Initialize rigging controls initRiggingControls(sprite); } catch (error) { console.error('Error loading character:', error); alert('Failed to load character image'); } }; // Rigging controls const initRiggingControls = (sprite) => { // Zoom controls document.getElementById('zoomInBtn').addEventListener('click', () => { sprite.scale.x *= 1.1; sprite.scale.y *= 1.1; }); document.getElementById('zoomOutBtn').addEventListener('click', () => { sprite.scale.x = Math.max(0.1, sprite.scale.x * 0.9); sprite.scale.y = Math.max(0.1, sprite.scale.y * 0.9); }); // Pivot point controls document.querySelectorAll('.pivot-control input').forEach(input => { input.addEventListener('input', (e) => { const part = e.target.dataset.part; const axis = e.target.dataset.axis; // Update pivot point position // This would be connected to actual rigging logic }); }); // Auto-detect pivots using free API document.getElementById('autoPivotsBtn').addEventListener('click', async () => { try { // This would call a free pose detection API const response = await fetch('https://api.posenet.com/detect', { method: 'POST', body: JSON.stringify({ image: sprite.texture.baseTexture.source.src }) }); const data = await response.json(); // Update pivot points based on detected keypoints console.log('Detected pivots:', data); } catch (error) { console.error('Pivot detection failed:', error); } }); }; // Initialize setupFileUpload(); // Initialize PixiJS for rigging with API integration async function initPixi(imageSrc) { try { console.log('Initializing character rigging'); // Create form data for API request const formData = new FormData(); const blob = await fetch(imageSrc).then(r => r.blob()); formData.append('image', blob, 'character.png'); formData.append('name', document.getElementById('charName').value || 'Unnamed'); formData.append('type', document.getElementById('charType').value); // Send to API endpoint const response = await fetch('/api/upload', { method: 'POST', body: formData }); if (!response.ok) { throw new Error(`API Error: ${response.status}`); } const data = await response.json(); console.log('Character uploaded:', data); // Initialize PixiJS with the returned character data const app = new PIXI.Application({ width: 600, height: 600, transparent: true, view: document.getElementById('previewContainer') }); const sprite = PIXI.Sprite.from(imageSrc); sprite.anchor.set(0.5); sprite.x = app.screen.width / 2; sprite.y = app.screen.height / 2; app.stage.addChild(sprite); // Store character ID for future API calls previewContainer.dataset.characterId = data.id; } catch (error) { console.error('Rigging initialization failed:', error); alert('Failed to initialize rigging. Please try again.'); } } // Setup API event listeners document.querySelectorAll('[data-api-call]').forEach(btn => { btn.addEventListener('click', async () => { const endpoint = btn.dataset.apiCall; try { const charId = previewContainer.dataset.characterId; if (!charId) throw new Error('No character loaded'); const response = await fetch(`/api/${endpoint}`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ character_id: charId }) }); if (!response.ok) throw new Error(await response.text()); const result = await response.json(); console.log(`${endpoint} success:`, result); } catch (error) { console.error(`${endpoint} failed:`, error); alert(`API Error: ${error.message}`); } }); }); console.log('BoneWizardry 3000 Unleashed initialized'); });