Merge the canvas and the 3D Preview into one module.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lenticular Image Generator</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js"></script>
    <style>
        .custom-scrollbar::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }
        .custom-scrollbar::-webkit-scrollbar-track {
            background: #f1f1f1;
        }
        .custom-scrollbar::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 3px;
        }
        .custom-scrollbar::-webkit-scrollbar-thumb:hover {
            background: #555;
        }
        .layer-item {
            transition: all 0.2s ease;
        }
        .layer-item:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .preview-container {
            perspective: 1000px;
        }
        .preview-image {
            transform-style: preserve-3d;
            transition: transform 0.5s ease;
        }
        .slider-thumb::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: #4f46e5;
            cursor: pointer;
        }
        .range-slider {
            height: 5px;
            -webkit-appearance: none;
            width: 100%;
            border-radius: 5px;
            background: #ddd;
            outline: none;
        }
        .range-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: #4f46e5;
            cursor: pointer;
        }
    </style>
</head>
<body class="bg-gray-100 font-sans">
    <div class="container mx-auto px-4 py-8">
        <h1 class="text-3xl font-bold text-center text-indigo-800 mb-8">Lenticular Image Generator</h1>
        
        <div class="flex flex-col lg:flex-row gap-6">
            <!-- Left Panel - Canvas and Controls -->
            <div class="w-full lg:w-2/3 bg-white rounded-lg shadow-md p-4">
                <div class="flex justify-between items-center mb-4">
                    <h2 class="text-xl font-semibold text-gray-800">Canvas</h2>
                    <div class="flex gap-2">
                        <button id="resetCanvas" class="px-3 py-1 bg-gray-200 text-gray-700 rounded hover:bg-gray-300 transition">
                            <i class="fas fa-redo mr-1"></i> Reset
                        </button>
                        <button id="exportBtn" class="px-3 py-1 bg-indigo-600 text-white rounded hover:bg-indigo-700 transition">
                            <i class="fas fa-download mr-1"></i> Export
                        </button>
                    </div>
                </div>
                
                <!-- Canvas Settings -->
                <div class="bg-gray-50 p-3 rounded mb-4">
                    <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-3">
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Canvas Width</label>
                            <div class="flex items-center gap-2">
                                <input type="range" id="canvasWidthSlider" min="100" max="2000" value="800" class="range-slider">
                                <input type="number" id="canvasWidthInput" value="800" min="100" max="2000" class="w-20 px-2 py-1 border rounded">
                            </div>
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Canvas Height</label>
                            <div class="flex items-center gap-2">
                                <input type="range" id="canvasHeightSlider" min="100" max="2000" value="600" class="range-slider">
                                <input type="number" id="canvasHeightInput" value="600" min="100" max="2000" class="w-20 px-2 py-1 border rounded">
                            </div>
                        </div>
                    </div>
                    <div class="flex items-center">
                        <input type="checkbox" id="autoResizeCanvas" class="mr-2">
                        <label for="autoResizeCanvas" class="text-sm text-gray-700">Adjust canvas size to image resolution</label>
                    </div>
                </div>
                
                <!-- Canvas Area -->
                <div class="relative border-2 border-gray-300 bg-gray-200 overflow-hidden mb-4" style="width: 800px; height: 600px;" id="canvasContainer">
                    <canvas id="mainCanvas" width="800" height="600" class="absolute top-0 left-0"></canvas>
                    <div id="canvasOverlay" class="absolute top-0 left-0 w-full h-full pointer-events-none"></div>
                </div>
                
                <!-- Transformation Controls -->
                <div class="bg-gray-50 p-3 rounded">
                    <h3 class="text-lg font-medium text-gray-800 mb-3">Layer Transformation</h3>
                    <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Position X</label>
                            <input type="range" id="posXSlider" min="-200" max="200" value="0" class="range-slider w-full">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Position Y</label>
                            <input type="range" id="posYSlider" min="-200" max="200" value="0" class="range-slider w-full">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Rotation</label>
                            <input type="range" id="rotationSlider" min="0" max="360" value="0" class="range-slider w-full">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Scale</label>
                            <input type="range" id="scaleSlider" min="10" max="200" value="100" class="range-slider w-full">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Depth</label>
                            <input type="range" id="depthSlider" min="-100" max="100" value="0" class="range-slider w-full">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Parallax</label>
                            <input type="range" id="parallaxSlider" min="0" max="100" value="50" class="range-slider w-full">
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- Right Panel - Layers and Preview -->
            <div class="w-full lg:w-1/3 flex flex-col gap-6">
                <!-- Layers Panel -->
                <div class="bg-white rounded-lg shadow-md p-4">
                    <div class="flex justify-between items-center mb-3">
                        <h2 class="text-xl font-semibold text-gray-800">Layers</h2>
                        <button id="addLayerBtn" class="px-3 py-1 bg-green-600 text-white rounded hover:bg-green-700 transition">
                            <i class="fas fa-plus mr-1"></i> Add Layer
                        </button>
                    </div>
                    
                    <div class="bg-gray-50 p-3 rounded mb-3">
                        <div class="flex items-center mb-2">
                            <input type="file" id="imageUpload" accept="image/*" class="hidden">
                            <button id="uploadImageBtn" class="px-3 py-1 bg-blue-600 text-white rounded hover:bg-blue-700 transition mr-2">
                                <i class="fas fa-image mr-1"></i> Upload Image
                            </button>
                            <input type="file" id="depthMapUpload" accept="image/*" class="hidden">
                            <button id="uploadDepthMapBtn" class="px-3 py-1 bg-purple-600 text-white rounded hover:bg-purple-700 transition">
                                <i class="fas fa-map mr-1"></i> Depth Map
                            </button>
                        </div>
                    </div>
                    
                    <div id="layersList" class="space-y-2 max-h-64 overflow-y-auto custom-scrollbar">
                        <!-- Layers will be added here dynamically -->
                        <div class="text-center text-gray-500 py-4">No layers added yet</div>
                    </div>
                </div>
                
                <!-- Preview Panel -->
                <div class="bg-white rounded-lg shadow-md p-4">
                    <div class="flex justify-between items-center mb-3">
                        <h2 class="text-xl font-semibold text-gray-800">3D Preview</h2>
                        <div class="flex items-center">
                            <button id="playPauseBtn" class="px-3 py-1 bg-indigo-600 text-white rounded hover:bg-indigo-700 transition">
                                <i class="fas fa-play mr-1"></i> Play
                            </button>
                        </div>
                    </div>
                    
                    <div class="preview-container bg-gray-100 rounded-lg overflow-hidden mb-3">
                        <div id="previewImage" class="preview-image w-full h-48 bg-gray-200 flex items-center justify-center">
                            <span class="text-gray-500">Preview will appear here</span>
                        </div>
                    </div>
                    
                    <div class="space-y-4">
                        <!-- Viewing Angle Input -->
                        <div class="bg-gray-50 p-3 rounded">
                            <label for="viewingAngleInput" class="block text-sm font-medium text-gray-700 mb-1">Viewing Angle Range (°)</label>
                            <input type="number" id="viewingAngleInput" min="10" max="360" value="45" class="w-full border border-gray-300 rounded px-2 py-1">
                        </div>

                        <!-- Slider Input -->
                        <div class="bg-gray-50 p-3 rounded">
                            <label for="viewAngleSlider" class="block text-sm font-medium text-gray-700 mb-1">View Angle</label>
                            <input type="range" id="viewAngleSlider" min="-45" max="45" value="0" class="range-slider w-full">
                        </div>
                    </div>
                </div>
                
                <!-- Export Settings -->
                <div class="bg-white rounded-lg shadow-md p-4">
                    <h2 class="text-xl font-semibold text-gray-800 mb-3">Export Settings</h2>
                    
                    <div class="space-y-3">
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Frames Count</label>
                            <input type="number" id="framesCount" min="2" max="20" value="5" class="w-full px-3 py-2 border rounded">
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">LPI (Lenticules Per Inch)</label>
                            <select id="lpiSelect" class="w-full px-3 py-2 border rounded">
                                <option value="20">20 LPI</option>
                                <option value="30">30 LPI</option>
                                <option value="40">40 LPI</option>
                                <option value="50">50 LPI</option>
                                <option value="60">60 LPI</option>
                                <option value="75">75 LPI</option>
                            </select>
                        </div>
                        <div>
                            <label class="block text-sm font-medium text-gray-700 mb-1">Output Format</label>
                            <select id="formatSelect" class="w-full px-3 py-2 border rounded">
                                <option value="png">PNG</option>
                                <option value="jpg">JPEG</option>
                                <option value="tiff">TIFF</option>
                            </select>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // Canvas setup
            const canvas = document.getElementById('mainCanvas');
            const ctx = canvas.getContext('2d');
            const canvasContainer = document.getElementById('canvasContainer');
            const canvasOverlay = document.getElementById('canvasOverlay');
            
            // Preview elements
            const previewImage = document.getElementById('previewImage');
            
            // Control elements
            const canvasWidthSlider = document.getElementById('canvasWidthSlider');
            const canvasWidthInput = document.getElementById('canvasWidthInput');
            const canvasHeightSlider = document.getElementById('canvasHeightSlider');
            const canvasHeightInput = document.getElementById('canvasHeightInput');
            const autoResizeCanvas = document.getElementById('autoResizeCanvas');
            const resetCanvasBtn = document.getElementById('resetCanvas');
            
            // Transformation controls
            const posXSlider = document.getElementById('posXSlider');
            const posYSlider = document.getElementById('posYSlider');
            const rotationSlider = document.getElementById('rotationSlider');
            const scaleSlider = document.getElementById('scaleSlider');
            const depthSlider = document.getElementById('depthSlider');
            const parallaxSlider = document.getElementById('parallaxSlider');
            
            // Preview controls
            const viewingAngleInput = document.getElementById('viewingAngleInput');
            const viewAngleSlider = document.getElementById('viewAngleSlider');
            const playPauseBtn = document.getElementById('playPauseBtn');
            
            // Layer controls
            const addLayerBtn = document.getElementById('addLayerBtn');
            const uploadImageBtn = document.getElementById('uploadImageBtn');
            const imageUpload = document.getElementById('imageUpload');
            const uploadDepthMapBtn = document.getElementById('uploadDepthMapBtn');
            const depthMapUpload = document.getElementById('depthMapUpload');
            const layersList = document.getElementById('layersList');
            
            // Export controls
            const exportBtn = document.getElementById('exportBtn');
            const framesCount = document.getElementById('framesCount');
            const lpiSelect = document.getElementById('lpiSelect');
            const formatSelect = document.getElementById('formatSelect');
            
            // State variables
            let layers = [];
            let selectedLayerIndex = -1;
            let isPlaying = false;
            let animationId = null;
            let animationDirection = 1; // 1 for forward, -1 for backward
            let lastAnimationTime = 0;
            const animationSpeed = 0.5; // degrees per frame
            
            // Initialize canvas
            function initCanvas() {
                canvas.width = parseInt(canvasWidthInput.value);
                canvas.height = parseInt(canvasHeightInput.value);
                canvasContainer.style.width = canvas.width + 'px';
                canvasContainer.style.height = canvas.height + 'px';
                redrawCanvas();
            }
            
            // Redraw canvas with all layers
            function redrawCanvas() {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                
                // Draw checkerboard background
                const size = 20;
                for (let y = 0; y < canvas.height; y += size) {
                    for (let x = 0; x < canvas.width; x += size) {
                        const isEven = (Math.floor(x / size) + Math.floor(y / size)) % 2 === 0;
                        ctx.fillStyle = isEven ? '#f0f0f0' : '#e0e0e0';
                        ctx.fillRect(x, y, size, size);
                    }
                }
                
                // Draw layers (from bottom to top)
                layers.forEach(layer => {
                    if (layer.visible) {
                        drawLayer(layer);
                    }
                });
                
                updatePreview();
            }
            
            // Draw a single layer
            function drawLayer(layer) {
                if (!layer.image) return;
                
                ctx.save();
                
                // Apply transformations
                ctx.translate(layer.x + layer.image.width / 2, layer.y + layer.image.height / 2);
                ctx.rotate(layer.rotation * Math.PI / 180);
                ctx.scale(layer.scale / 100, layer.scale / 100);
                
                // Draw image
                ctx.drawImage(
                    layer.image, 
                    -layer.image.width / 2, 
                    -layer.image.height / 2,
                    layer.image.width,
                    layer.image.height
                );
                
                // Draw depth map if available
                if (layer.depthMap) {
                    ctx.globalAlpha = 0.5;
                    ctx.drawImage(
                        layer.depthMap, 
                        -layer.image.width / 2, 
                        -layer.image.height / 2,
                        layer.image.width,
                        layer.image.height
                    );
                    ctx.globalAlpha = 1.0;
                }
                
                ctx.restore();
                
                // Draw selection border if this is the selected layer
                if (layers[selectedLayerIndex] === layer) {
                    ctx.strokeStyle = '#4f46e5';
                    ctx.lineWidth = 2;
                    ctx.setLineDash([5, 5]);
                    ctx.strokeRect(layer.x, layer.y, layer.image.width, layer.image.height);
                    ctx.setLineDash([]);
                }
            }
            
            // Update 3D preview
            function updatePreview() {
                if (layers.length === 0) return;
                
                // Create a temporary canvas for the preview
                const tempCanvas = document.createElement('canvas');
                const tempCtx = tempCanvas.getContext('2d');
                tempCanvas.width = canvas.width;
                tempCanvas.height = canvas.height;
                
                // Draw all visible layers with parallax effect
                const angle = parseInt(viewAngleSlider.value);
                layers.forEach(layer => {
                    if (layer.visible) {
                        tempCtx.save();
                        
                        // Calculate parallax offset based on depth and angle
                        const parallaxOffset = (angle / 360) * layer.parallax * 10 * (layer.depth / 100);
                        
                        tempCtx.translate(
                            layer.x + layer.image.width / 2 + parallaxOffset, 
                            layer.y + layer.image.height / 2
                        );
                        tempCtx.rotate(layer.rotation * Math.PI / 180);
                        tempCtx.scale(layer.scale / 100, layer.scale / 100);
                        
                        // Apply perspective transform based on depth
                        const perspective = 1 + (layer.depth / 500);
                        tempCtx.transform(perspective, 0, 0, 1, 0, 0);
                        
                        tempCtx.drawImage(
                            layer.image, 
                            -layer.image.width / 2, 
                            -layer.image.height / 2,
                            layer.image.width,
                            layer.image.height
                        );
                        
                        tempCtx.restore();
                    }
                });
                
                // Apply 3D rotation to the preview
                const rotationY = angle * Math.PI / 180;
                previewImage.style.transform = `rotateY(${rotationY}rad)`;
                
                // Set the preview image
                previewImage.style.backgroundImage = `url(${tempCanvas.toDataURL()})`;
                previewImage.style.backgroundSize = 'contain';
                previewImage.style.backgroundPosition = 'center';
                previewImage.style.backgroundRepeat = 'no-repeat';
            }
            
            // Create a new layer
            function createLayer(image, depthMap = null) {
                const layer = {
                    image: image,
                    depthMap: depthMap,
                    x: 0,
                    y: 0,
                    rotation: 0,
                    scale: 100,
                    depth: 0,
                    parallax: 50,
                    visible: true,
                    name: `Layer ${layers.length + 1}`
                };
                
                // Center the layer if it's the first one
                if (layers.length === 0) {
                    layer.x = (canvas.width - image.width) / 2;
                    layer.y = (canvas.height - image.height) / 2;
                }
                
                layers.push(layer);
                selectedLayerIndex = layers.length - 1;
                updateLayersList();
                updateTransformControls();
                redrawCanvas();
            }
            
            // Update the layers list in the UI
            function updateLayersList() {
                layersList.innerHTML = '';
                
                if (layers.length === 0) {
                    layersList.innerHTML = '<div class="text-center text-gray-500 py-4">No layers added yet</div>';
                    return;
                }
                
                // Add layers in reverse order (top to bottom)
                for (let i = layers.length - 1; i >= 0; i--) {
                    const layer = layers[i];
                    
                    const layerElement = document.createElement('div');
                    layerElement.className = `layer-item bg-white border rounded p-3 flex items-center justify-between ${selectedLayerIndex === i ? 'border-indigo-500 bg-indigo-50' : 'border-gray-200'}`;
                    
                    layerElement.innerHTML = `
                        <div class="flex items-center">
                            <input type="checkbox" ${layer.visible ? 'checked' : ''} class="mr-2 toggle-visibility" data-index="${i}">
                            <span class="text-sm font-medium">${layer.name}</span>
                        </div>
                        <div class="flex items-center">
                            <button class="p-1 text-gray-500 hover:text-gray-700 move-up" data-index="${i}" ${i === 0 ? 'disabled' : ''}>
                                <i class="fas fa-arrow-up"></i>
                            </button>
                            <button class="p-1 text-gray-500 hover:text-gray-700 move-down" data-index="${i}" ${i === layers.length - 1 ? 'disabled' : ''}>
                                <i class="fas fa-arrow-down"></i>
                            </button>
                            <button class="p-1 text-red-500 hover:text-red-700 delete-layer" data-index="${i}">
                                <i class="fas fa-trash"></i>
                            </button>
                        </div>
                    `;
                    
                    layerElement.addEventListener('click', (e) => {
                        if (!e.target.closest('button') && !e.target.closest('input')) {
                            selectedLayerIndex = i;
                            updateLayersList();
                            updateTransformControls();
                            redrawCanvas();
                        }
                    });
                    
                    layersList.appendChild(layerElement);
                }
                
                // Add event listeners for layer controls
                document.querySelectorAll('.toggle-visibility').forEach(checkbox => {
                    checkbox.addEventListener('change', function() {
                        const index = parseInt(this.dataset.index);
                        layers[index].visible = this.checked;
                        redrawCanvas();
                    });
                });
                
                document.querySelectorAll('.move-up').forEach(button => {
                    button.addEventListener('click', function(e) {
                        e.stopPropagation();
                        const index = parseInt(this.dataset.index);
                        if (index > 0) {
                            [layers[index], layers[index - 1]] = [layers[index - 1], layers[index]];
                            if (selectedLayerIndex === index) selectedLayerIndex--;
                            else if (selectedLayerIndex === index - 1) selectedLayerIndex++;
                            updateLayersList();
                            redrawCanvas();
                        }
                    });
                });
                
                document.querySelectorAll('.move-down').forEach(button => {
                    button.addEventListener('click', function(e) {
                        e.stopPropagation();
                        const index = parseInt(this.dataset.index);
                        if (index < layers.length - 1) {
                            [layers[index], layers[index + 1]] = [layers[index + 1], layers[index]];
                            if (selectedLayerIndex === index) selectedLayerIndex++;
                            else if (selectedLayerIndex === index + 1) selectedLayerIndex--;
                            updateLayersList();
                            redrawCanvas();
                        }
                    });
                });
                
                document.querySelectorAll('.delete-layer').forEach(button => {
                    button.addEventListener('click', function(e) {
                        e.stopPropagation();
                        const index = parseInt(this.dataset.index);
                        layers.splice(index, 1);
                        if (selectedLayerIndex >= index) {
                            selectedLayerIndex = Math.max(-1, selectedLayerIndex - 1);
                        }
                        updateLayersList();
                        updateTransformControls();
                        redrawCanvas();
                    });
                });
            }
            
            // Update transformation controls with selected layer values
            function updateTransformControls() {
                if (selectedLayerIndex >= 0 && selectedLayerIndex < layers.length) {
                    const layer = layers[selectedLayerIndex];
                    
                    posXSlider.value = layer.x;
                    posYSlider.value = layer.y;
                    rotationSlider.value = layer.rotation;
                    scaleSlider.value = layer.scale;
                    depthSlider.value = layer.depth;
                    parallaxSlider.value = layer.parallax;
                    
                    // Enable all controls
                    posXSlider.disabled = false;
                    posYSlider.disabled = false;
                    rotationSlider.disabled = false;
                    scaleSlider.disabled = false;
                    depthSlider.disabled = false;
                    parallaxSlider.disabled = false;
                } else {
                    // Disable all controls
                    posXSlider.disabled = true;
                    posYSlider.disabled = true;
                    rotationSlider.disabled = true;
                    scaleSlider.disabled = true;
                    depthSlider.disabled = true;
                    parallaxSlider.disabled = true;
                }
            }
            
            // Update slider range based on viewing angle
            function updateSliderRange() {
                const viewingAngle = parseInt(viewingAngleInput.value);
                const halfAngle = viewingAngle / 2;
                
                viewAngleSlider.min = -halfAngle;
                viewAngleSlider.max = halfAngle;
                
                // If current value is outside new range, adjust it
                if (viewAngleSlider.value < -halfAngle) viewAngleSlider.value = -halfAngle;
                if (viewAngleSlider.value > halfAngle) viewAngleSlider.value = halfAngle;
                
                updatePreview();
            }
            
            // Animation for preview
            function animatePreview(timestamp) {
                if (!isPlaying) return;
                
                if (!lastAnimationTime) {
                    lastAnimationTime = timestamp;
                }
                
                const deltaTime = timestamp - lastAnimationTime;
                lastAnimationTime = timestamp;
                
                // Calculate angle change based on time and direction
                const angleChange = animationSpeed * animationDirection * (deltaTime / 16.67); // Normalize to 60fps
                let newAngle = parseFloat(viewAngleSlider.value) + angleChange;
                
                const halfAngle = parseInt(viewingAngleInput.value) / 2;
                
                // Reverse direction when reaching limits
                if (newAngle >= halfAngle) {
                    newAngle = halfAngle;
                    animationDirection = -1;
                } else if (newAngle <= -halfAngle) {
                    newAngle = -halfAngle;
                    animationDirection = 1;
                }
                
                viewAngleSlider.value = newAngle;
                updatePreview();
                
                animationId = requestAnimationFrame(animatePreview);
            }
            
            // Start or stop animation
            function toggleAnimation() {
                isPlaying = !isPlaying;
                
                if (isPlaying) {
                    playPauseBtn.innerHTML = '<i class="fas fa-pause mr-1"></i> Pause';
                    lastAnimationTime = 0;
                    animationId = requestAnimationFrame(animatePreview);
                } else {
                    playPauseBtn.innerHTML = '<i class="fas fa-play mr-1"></i> Play';
                    if (animationId) {
                        cancelAnimationFrame(animationId);
                        animationId = null;
                    }
                    // Reset to default view
                    viewAngleSlider.value = 0;
                    updatePreview();
                }
            }
            
            // Event listeners for canvas size controls
            canvasWidthSlider.addEventListener('input', function() {
                canvasWidthInput.value = this.value;
                initCanvas();
            });
            
            canvasWidthInput.addEventListener('change', function() {
                canvasWidthSlider.value = this.value;
                initCanvas();
            });
            
            canvasHeightSlider.addEventListener('input', function() {
                canvasHeightInput.value = this.value;
                initCanvas();
            });
            
            canvasHeightInput.addEventListener('change', function() {
                canvasHeightSlider.value = this.value;
                initCanvas();
            });
            
            autoResizeCanvas.addEventListener('change', function() {
                // This would be implemented when an image is uploaded
            });
            
            resetCanvasBtn.addEventListener('click', function() {
                canvasWidthInput.value = 800;
                canvasWidthSlider.value = 800;
                canvasHeightInput.value = 600;
                canvasHeightSlider.value = 600;
                initCanvas();
            });
            
            // Event listeners for transformation controls
            posXSlider.addEventListener('input', function() {
                if (selectedLayerIndex >= 0) {
                    layers[selectedLayerIndex].x = parseInt(this.value);
                    redrawCanvas();
                }
            });
            
            posYSlider.addEventListener('input', function() {
                if (selectedLayerIndex >= 0) {
                    layers[selectedLayerIndex].y = parseInt(this.value);
                    redrawCanvas();
                }
            });
            
            rotationSlider.addEventListener('input', function() {
                if (selectedLayerIndex >= 0) {
                    layers[selectedLayerIndex].rotation = parseInt(this.value);
                    redrawCanvas();
                }
            });
            
            scaleSlider.addEventListener('input', function() {
                if (selectedLayerIndex >= 0) {
                    layers[selectedLayerIndex].scale = parseInt(this.value);
                    redrawCanvas();
                }
            });
            
            depthSlider.addEventListener('input', function() {
                if (selectedLayerIndex >= 0) {
                    layers[selectedLayerIndex].depth = parseInt(this.value);
                    updatePreview();
                }
            });
            
            parallaxSlider.addEventListener('input', function() {
                if (selectedLayerIndex >= 0) {
                    layers[selectedLayerIndex].parallax = parseInt(this.value);
                    updatePreview();
                }
            });
            
            // Event listeners for preview controls
            viewingAngleInput.addEventListener('input', function() {
                updateSliderRange();
            });
            
            viewAngleSlider.addEventListener('input', function() {
                updatePreview();
            });
            
            playPauseBtn.addEventListener('click', toggleAnimation);
            
            // Event listeners for layer controls
            addLayerBtn.addEventListener('click', function() {
                // Create a blank layer
                const blankCanvas = document.createElement('canvas');
                blankCanvas.width = 200;
                blankCanvas.height = 200;
                const blankCtx = blankCanvas.getContext('2d');
                
                // Fill with a color
                blankCtx.fillStyle = `hsl(${Math.random() * 360}, 70%, 80%)`;
                blankCtx.fillRect(0, 0, blankCanvas.width, blankCanvas.height);
                
                // Add some text
                blankCtx.fillStyle = '#333';
                blankCtx.font = '20px Arial';
                blankCtx.textAlign = 'center';
                blankCtx.textBaseline = 'middle';
                blankCtx.fillText('New Layer', blankCanvas.width / 2, blankCanvas.height / 2);
                
                createLayer(blankCanvas);
            });
            
            uploadImageBtn.addEventListener('click', function() {
                imageUpload.click();
            });
            
            imageUpload.addEventListener('change', function(e) {
                if (e.target.files.length > 0) {
                    const file = e.target.files[0];
                    const reader = new FileReader();
                    
                    reader.onload = function(event) {
                        const img = new Image();
                        img.onload = function() {
                            if (autoResizeCanvas.checked) {
                                canvasWidthInput.value = img.width;
                                canvasWidthSlider.value = img.width;
                                canvasHeightInput.value = img.height;
                                canvasHeightSlider.value = img.height;
                                initCanvas();
                            }
                            createLayer(img);
                        };
                        img.src = event.target.result;
                    };
                    
                    reader.readAsDataURL(file);
                }
            });
            
            uploadDepthMapBtn.addEventListener('click', function() {
                if (selectedLayerIndex >= 0) {
                    depthMapUpload.click();
                } else {
                    alert('Please select a layer first');
                }
            });
            
            depthMapUpload.addEventListener('change', function(e) {
                if (e.target.files.length > 0 && selectedLayerIndex >= 0) {
                    const file = e.target.files[0];
                    const reader = new FileReader();
                    
                    reader.onload = function(event) {
                        const img = new Image();
                        img.onload = function() {
                            layers[selectedLayerIndex].depthMap = img;
                            redrawCanvas();
                        };
                        img.src = event.target.result;
                    };
                    
                    reader.readAsDataURL(file);
                }
            });
            
            // Event listener for export button
            exportBtn.addEventListener('click', function() {
                if (layers.length === 0) {
                    alert('Please add at least one layer before exporting');
                    return;
                }
                
                const frameCount = parseInt(framesCount.value);
                const lpi = parseInt(lpiSelect.value);
                const format = formatSelect.value;
                
                alert(`Exporting with ${frameCount} frames at ${lpi} LPI as ${format.toUpperCase()}`);
                
                // In a real implementation, this would:
                // 1. Generate multiple views of the composition from different angles
                // 2. Interlace these views according to the LPI setting
                // 3. Create a downloadable file in the specified format
            });
            
            // Initialize the application
            initCanvas();
            updateSliderRange();
        });
    </script>
</body>
</html>