treekoo's picture
remove the duplicate cards, fill in functionality using free or open libraries and apis where possible. continue
cf772b4 verified
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');
});