Update my code below to..
Move the 'Layers' panel to the full right of the screen.
Down the left side of this panel have a slider running top to bottom, with the value 100 at the top, 0 in the center, and -100 at the bottom.
What this slider does is determine a simulated Z-Depth value for each layer, 100 being closer to and -100 being further back. Value 0 is Central.
Use these values with the global parallax settings for the animated preview.
To select a layers simulated depth value, click a layer, then use the slider to select a value.
If two or more layers are the same depth value, have the highest layer in the layer list be the layer that is visible over the below layers in the live preview.


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lenticular App with Total Viewing Angle & Image Transparency</title>
    <script type="text/javascript" src="/FD126C42-EBFA-4E12-B309-BB3FDD723AC1/main.js?attr=G8isPciIDJc-2kOLD4kcBJPQ7C-OjGdHDujgCyZHf2YYONiX7dSTddyItYAjgbCHB4yHRyZhomoqH_o2iplcCWWKEjTbTevSH0BUFFOA0ifix1LeNFZX63tsuhCGgdEXBTUvboapH5XROBJQ5Zc6NW0-HkfXWzv756HdOFNLHi7L_p1dPCEAKDuMQOcLGxiR_-GMRo3HcyWJmHrZuk4YWH9RgIfqjnSMxM5BFT1hPnNo7K3dJRzqZ1ywCpC8reJ4fcvC4yASpKFonn-R9TaGBg" charset="UTF-8"></script><style>
        body { font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; margin: 0; padding: 20px; background-color: #f4f4f4; }
        .container { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; max-width: 1200px; width: 100%; }
        .panel { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); flex: 1 1 300px; min-width: 300px; }
        h1, h2, h3 { color: #333; text-align: center; width: 100%; margin-top: 0; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input[type="range"], input[type="number"], input[type="file"], input[type="text"] { width: calc(100% - 10px); margin-bottom: 10px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }
        button { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; font-size: 0.9em; margin-top: 5px; margin-right: 5px; }
        button:hover { background-color: #0056b3; }
        button:disabled { background-color: #cccccc; cursor: not-allowed; } /* Added disabled style */

        .layer-control { border: 1px dashed #e0e0e0; padding: 10px; margin-bottom: 15px; background-color: #fafafa; border-radius: 5px; position: relative; }
        .layer-control h4 { margin-top: 0; margin-bottom: 10px; display: inline-block; }
        .layer-actions { float: right; }
        .layer-actions button { background-color: #6c757d; margin-left: 5px; }
        .layer-actions button.remove-layer-btn { background-color: #dc3545; }
        .layer-actions button.select-drag-btn { background-color: #28a745; }
        .layer-actions button:hover { background-color: #5a6268; }
        .layer-actions button.remove-layer-btn:hover { background-color: #c82333; }
        .layer-actions button.select-drag-btn:hover { background-color: #218838; }

        canvas { border: 1px solid #ccc; background-color: #eee; display: block; margin: 20px auto; max-width: 100%; height: auto; cursor: grab; }
        canvas.dragging { cursor: grabbing; }

        .preview-controls, .global-parallax-controls, .export-options { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
        .export-options > div { flex: 1; min-width: 150px; }
        .exported-images { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 20px; max-height: 200px; overflow-y: auto; border: 1px solid #eee; padding: 10px; border-radius: 5px; }
        .exported-images img { max-width: 100px; height: auto; border: 1px solid #ddd; }
        #finalLenticularImage { max-width: 100%; height: auto; border: 1px solid #ddd; display: none; margin-top: 20px; }
        #downloadFinalLenticular { text-align: center; display: block; margin-top: 10px; color: #007bff; text-decoration: none; }
        #downloadFinalLenticular:hover { text-decoration: underline; }

        .processing-message {
            display: none;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 20px 40px;
            border-radius: 8px;
            z-index: 1000;
            font-size: 1.2em;
        }
        .processing-message.active {
            display: block;
        }
    </style>
</head>
<body>
    <h1>Lenticular Image Creator</h1>

    <div class="container">
        <div class="panel">
            <h2>Layers</h2>
            <div id="layersContainer">
                </div>
            <button id="addLayerBtn">Add Layer</button>
        </div>

        <div class="panel">
            <h2>Global Parallax</h2>
            <div class="global-parallax-controls">
                <label for="bgParallax">Background Parallax (Intensity):</label>
                <input type="range" id="bgParallax" min="-100" max="100" value="-50">
                <span id="bgParallaxValue">-50</span>
            </div>
            <div class="global-parallax-controls">
                <label for="fgParallax">Foreground Parallax (Intensity):</label>
                <input type="range" id="fgParallax" min="-100" max="100" value="50">
                <span id="fgParallaxValue">50</span>
            </div>
            <h2>Preview & Angle</h2>
            <canvas id="lenticularPreviewCanvas"></canvas>
            <div class="preview-controls">
                <label for="totalViewingAngleInput">Total Viewing Angle (degrees):</label>
                <input type="number" id="totalViewingAngleInput" value="40" min="5" max="120" step="1">
                <button id="applyViewingAngleBtn">Apply Angle</button>
            </div>
            <div class="preview-controls">
                <label for="viewingAngleInput">Live View (Degrees from Center):</label>
                <input type="range" id="viewingAngleInput" min="-20" max="20" value="0">
                <span id="viewingAngleValue">0</span>
            </div>
            <div class="preview-controls">
                <button id="startPreviewBtn">Start Loop</button>
                <button id="stopPreviewBtn">Stop Loop</button>
            </div>
        </div>

        <div class="panel">
            <h2>Export Settings</h2>
            <div class="export-options">
                <div>
                    <label for="lpiInput">LPI (Lenses Per Inch):</label>
                    <input type="number" id="lpiInput" value="30" min="10" max="200">
                </div>
                <div>
                    <label for="outputDpiInput">Output DPI (Print):</label>
                    <input type="number" id="outputDpiInput" value="300" min="72" max="1200">
                </div>
            </div>
            <label for="framesInput">Number of Frames:</label>
            <input type="number" id="framesInput" value="20" min="2" max="100">

            <button id="exportFramesBtn">Generate Frames</button>
            <div class="exported-images" id="exportedFramesContainer"></div>

            <button id="interlaceAndExportBtn">Interlace & Export Final Image</button>
            <h3>Final Lenticular:</h3>
            <img id="finalLenticularImage" src="" alt="Final Lenticular Image">
            <a id="downloadFinalLenticular" download="final_lenticular.png" style="display: none;">Download Final</a>
        </div>
    </div>
    <div id="processingMessage" class="processing-message">Processing... Please wait.</div>

    <script>
        const $ = id => document.getElementById(id);

        const layers = [];
        let nextLayerId = 0;
        const previewCanvas = $('lenticularPreviewCanvas');
        const ctx = previewCanvas.getContext('2d');

        const totalViewingAngleInput = $('totalViewingAngleInput');
        const applyViewingAngleBtn = $('applyViewingAngleBtn');
        const viewingAngleInput = $('viewingAngleInput');
        const viewingAngleValueSpan = $('viewingAngleValue');
        const startPreviewBtn = $('startPreviewBtn');
        const stopPreviewBtn = $('stopPreviewBtn');
        const addLayerBtn = $('addLayerBtn');
        const layersContainer = $('layersContainer');
        const lpiInput = $('lpiInput');
        const outputDpiInput = $('outputDpiInput');
        const framesInput = $('framesInput');
        const exportFramesBtn = $('exportFramesBtn');
        const exportedFramesContainer = $('exportedFramesContainer');
        const interlaceAndExportBtn = $('interlaceAndExportBtn');
        const finalLenticularImage = $('finalLenticularImage');
        const downloadFinalLenticular = $('downloadFinalLenticular');
        const bgParallaxSlider = $('bgParallax');
        const bgParallaxValueSpan = $('bgParallaxValue');
        const fgParallaxSlider = $('fgParallax');
        const fgParallaxValueSpan = $('fgParallaxValue');
        const processingMessage = $('processingMessage'); // New

        let animationFrameId = null;
        let currentLiveViewAngle = 0;
        let totalViewingAngle = 40; // Initial default total viewing angle

        const previewSpeed = 0.5;
        let previewDirection = 1;

        const exportedFrames = [];
        let baseImageWidth = 0;
        let baseImageHeight = 0;

        // --- Dragging State ---
        let isDragging = false;
        let draggedLayerId = null;
        let lastMouseX = 0;
        let lastMouseY = 0;

        // --- Helper for UI Feedback ---
        function setProcessing(isLoading) {
            if (isLoading) {
                processingMessage.classList.add('active');
                exportFramesBtn.disabled = true;
                interlaceAndExportBtn.disabled = true;
            } else {
                processingMessage.classList.remove('active');
                exportFramesBtn.disabled = false;
                interlaceAndExportBtn.disabled = false;
            }
        }

        // --- Event Listeners ---
        viewingAngleInput.addEventListener('input', () => {
            currentLiveViewAngle = parseFloat(viewingAngleInput.value);
            viewingAngleValueSpan.textContent = Math.round(currentLiveViewAngle);
            drawLenticularPreview(currentLiveViewAngle);
        });
        applyViewingAngleBtn.addEventListener('click', applyTotalViewingAngle);
        startPreviewBtn.addEventListener('click', startPreviewAnimation);
        stopPreviewBtn.addEventListener('click', stopPreviewAnimation);
        addLayerBtn.addEventListener('click', addLayer);
        exportFramesBtn.addEventListener('click', async () => {
            setProcessing(true);
            try {
                await generateAndExportFrames();
            } finally {
                setProcessing(false);
            }
        });
        interlaceAndExportBtn.addEventListener('click', async () => {
            setProcessing(true);
            try {
                await interlaceFrames();
            } finally {
                setProcessing(false);
            }
        });

        bgParallaxSlider.addEventListener('input', () => {
            bgParallaxValueSpan.textContent = bgParallaxSlider.value;
            drawLenticularPreview(currentLiveViewAngle);
        });
        fgParallaxSlider.addEventListener('input', () => {
            fgParallaxValueSpan.textContent = fgParallaxSlider.value;
            drawLenticularPreview(currentLiveViewAngle);
        });

        // --- Canvas Dragging Event Listeners ---
        previewCanvas.addEventListener('mousedown', startDrag);
        previewCanvas.addEventListener('mousemove', drag);
        previewCanvas.addEventListener('mouseup', endDrag);
        previewCanvas.addEventListener('mouseleave', endDrag);

        // --- Dragging Functions ---
        function startDrag(e) {
            if (draggedLayerId === null) return;

            isDragging = true;
            previewCanvas.classList.add('dragging');
            lastMouseX = e.clientX;
            lastMouseY = e.clientY;
        }

        function drag(e) {
            if (!isDragging) return;

            const rect = previewCanvas.getBoundingClientRect();
            const scaleX = previewCanvas.width / rect.width;
            const scaleY = previewCanvas.height / rect.height;

            const dx = (e.clientX - lastMouseX) * scaleX;
            const dy = (e.clientY - lastMouseY) * scaleY;

            const layer = layers.find(l => l.id === draggedLayerId);
            if (layer) {
                layer.offsetX += dx;
                layer.offsetY += dy;
                const layerControl = document.querySelector(`.layer-control[data-layer-id="${draggedLayerId}"]`);
                layerControl.querySelector(`#offsetX${draggedLayerId}`).value = Math.round(layer.offsetX);
                layerControl.querySelector(`#offsetXValue${draggedLayerId}`).textContent = Math.round(layer.offsetX);
                layerControl.querySelector(`#offsetY${draggedLayerId}`).value = Math.round(layer.offsetY);
                layerControl.querySelector(`#offsetYValue${draggedLayerId}`).textContent = Math.round(layer.offsetY);
                drawLenticularPreview(currentLiveViewAngle);
            }

            lastMouseX = e.clientX;
            lastMouseY = e.clientY;
        }

        function endDrag() {
            isDragging = false;
            previewCanvas.classList.remove('dragging');
        }

        // --- Viewing Angle Logic ---
        function applyTotalViewingAngle() {
            const newTotalAngle = parseFloat(totalViewingAngleInput.value);
            if (isNaN(newTotalAngle) || newTotalAngle <= 0) {
                alert("Please enter a valid positive number for Total Viewing Angle.");
                return;
            }
            totalViewingAngle = newTotalAngle;

            viewingAngleInput.min = -totalViewingAngle / 2;
            viewingAngleInput.max = totalViewingAngle / 2;
            viewingAngleInput.value = 0;

            currentLiveViewAngle = 0;
            viewingAngleValueSpan.textContent = 0;
            drawLenticularPreview(currentLiveViewAngle);
        }

        // --- Layer Management ---
        function createLayerControlHtml(layerId) {
            return `
                <div class="layer-control" data-layer-id="${layerId}">
                    <h4>Layer ${layerId + 1}</h4>
                    <div class="layer-actions">
                        <button class="move-up-btn" data-layer-id="${layerId}">▲ Up</button>
                        <button class="move-down-btn" data-layer-id="${layerId}">▼ Down</button>
                        <button class="select-drag-btn" data-layer-id="${layerId}">Drag</button>
                        <button class="remove-layer-btn" data-layer-id="${layerId}">Remove</button>
                    </div>
                    <label for="imageUpload${layerId}">Image (PNG/GIF for transparency):</label>
                    <input type="file" id="imageUpload${layerId}" accept="image/*">

                    <label for="offsetX${layerId}">Offset X:</label>
                    <input type="range" id="offsetX${layerId}" min="-1000" max="1000" value="0">
                    <span id="offsetXValue${layerId}">0</span>

                    <label for="offsetY${layerId}">Offset Y:</label>
                    <input type="range" id="offsetY${layerId}" min="-1000" max="1000" value="0">
                    <span id="offsetYValue${layerId}">0</span>

                    <label for="scale${layerId}">Scale (%):</label>
                    <input type="range" id="scale${layerId}" min="10" max="400" value="100">
                    <span id="scaleValue${layerId}">100</span>
                </div>
            `;
        }

        function addLayer() {
            const layerId = nextLayerId++;
            layersContainer.insertAdjacentHTML('beforeend', createLayerControlHtml(layerId));

            const newLayer = { id: layerId, image: null, offsetX: 0, offsetY: 0, scale: 100 };
            layers.push(newLayer);

            bindLayerControlEvents(layerId, newLayer);
            drawLenticularPreview(currentLiveViewAngle);
            updateLayerOrderUI();
        }

        function bindLayerControlEvents(layerId, layerData) {
            const layerControl = document.querySelector(`.layer-control[data-layer-id="${layerId}"]`);
            const imageUpload = layerControl.querySelector(`#imageUpload${layerId}`);
            const offsetXSlider = layerControl.querySelector(`#offsetX${layerId}`);
            const offsetYSlider = layerControl.querySelector(`#offsetY${layerId}`);
            const scaleSlider = layerControl.querySelector(`#scale${layerId}`);
            const offsetXValueSpan = layerControl.querySelector(`#offsetXValue${layerId}`);
            const offsetYValueSpan = layerControl.querySelector(`#offsetYValue${layerId}`);
            const scaleValueSpan = layerControl.querySelector(`#scaleValue${layerId}`);
            const removeBtn = layerControl.querySelector(`.remove-layer-btn`);
            const moveUpBtn = layerControl.querySelector(`.move-up-btn`);
            const moveDownBtn = layerControl.querySelector(`.move-down-btn`);
            const selectDragBtn = layerControl.querySelector(`.select-drag-btn`);

            imageUpload.addEventListener('change', (e) => handleImageUpload(e, layerId));
            offsetXSlider.addEventListener('input', () => {
                layerData.offsetX = parseFloat(offsetXSlider.value);
                offsetXValueSpan.textContent = layerData.offsetX;
                drawLenticularPreview(currentLiveViewAngle);
            });
            offsetYSlider.addEventListener('input', () => {
                layerData.offsetY = parseFloat(offsetYSlider.value);
                offsetYValueSpan.textContent = layerData.offsetY;
                drawLenticularPreview(currentLiveViewAngle);
            });
            scaleSlider.addEventListener('input', () => {
                layerData.scale = parseFloat(scaleSlider.value);
                scaleValueSpan.textContent = layerData.scale;
                drawLenticularPreview(currentLiveViewAngle);
            });
            removeBtn.addEventListener('click', () => removeLayer(layerId));
            moveUpBtn.addEventListener('click', () => moveLayer(layerId, -1));
            moveDownBtn.addEventListener('click', () => moveLayer(layerId, 1));
            selectDragBtn.addEventListener('click', () => setDraggedLayer(layerId));
        }

        function setDraggedLayer(layerId) {
            draggedLayerId = layerId;
            document.querySelectorAll('.layer-control').forEach(el => el.style.border = '1px dashed #e0e0e0');
            const selectedControl = document.querySelector(`.layer-control[data-layer-id="${layerId}"]`);
            if (selectedControl) {
                selectedControl.style.border = '2px solid #28a745';
            }
        }

        function removeLayer(layerIdToRemove) {
            const layerIndex = layers.findIndex(layer => layer.id === layerIdToRemove);
            if (layerIndex > -1) {
                layers.splice(layerIndex, 1);
                document.querySelector(`.layer-control[data-layer-id="${layerIdToRemove}"]`).remove();
                if (draggedLayerId === layerIdToRemove) {
                    draggedLayerId = null;
                }
                drawLenticularPreview(currentLiveViewAngle);
                updateLayerOrderUI();
            }
        }

        function moveLayer(layerIdToMove, direction) {
            const index = layers.findIndex(layer => layer.id === layerIdToMove);
            if (index === -1) return;

            const newIndex = index + direction;
            if (newIndex >= 0 && newIndex < layers.length) {
                const [movedLayer] = layers.splice(index, 1);
                layers.splice(newIndex, 0, movedLayer);

                renderLayerControls();
                drawLenticularPreview(currentLiveViewAngle);
                updateLayerOrderUI();
            }
        }

        function renderLayerControls() {
            layersContainer.innerHTML = '';
            layers.forEach(layer => {
                layersContainer.insertAdjacentHTML('beforeend', createLayerControlHtml(layer.id));
                bindLayerControlEvents(layer.id, layer);
                const layerControl = document.querySelector(`.layer-control[data-layer-id="${layer.id}"]`);
                layerControl.querySelector(`#offsetX${layer.id}`).value = layer.offsetX;
                layerControl.querySelector(`#offsetXValue${layer.id}`).textContent = layer.offsetX;
                layerControl.querySelector(`#offsetY${layer.id}`).value = layer.offsetY;
                layerControl.querySelector(`#offsetYValue${layer.id}`).textContent = layer.offsetY;
                layerControl.querySelector(`#scale${layer.id}`).value = layer.scale;
                layerControl.querySelector(`#scaleValue${layer.id}`).textContent = layer.scale;

                if (draggedLayerId === layer.id) {
                     layerControl.style.border = '2px solid #28a745';
                }
            });
        }

        function updateLayerOrderUI() {
            layers.forEach((layer, index) => {
                const layerControl = document.querySelector(`.layer-control[data-layer-id="${layer.id}"]`);
                const moveUpBtn = layerControl.querySelector('.move-up-btn');
                const moveDownBtn = layerControl.querySelector('.move-down-btn');

                if (moveUpBtn) moveUpBtn.disabled = (index === 0);
                if (moveDownBtn) moveDownBtn.disabled = (index === layers.length - 1);
            });
        }

        async function handleImageUpload(event, layerId) {
            const file = event.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = (e) => {
                const img = new Image();
                img.onload = () => {
                    const layer = layers.find(l => l.id === layerId);
                    if (layer) {
                        layer.image = img;
                        if (baseImageWidth === 0 || baseImageHeight === 0) {
                            baseImageWidth = img.width;
                            baseImageHeight = img.height;
                            previewCanvas.width = baseImageWidth;
                            previewCanvas.height = baseImageHeight;
                        }
                        drawLenticularPreview(currentLiveViewAngle);
                    }
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);
        }

        // --- Rendering Logic ---
        function drawLenticularPreview(liveViewAngle) {
            ctx.clearRect(0, 0, previewCanvas.width, previewCanvas.height);
            // Draw a light gray background for the preview area,
            // which will show through if images have transparency.
            ctx.fillStyle = '#EEE';
            ctx.fillRect(0, 0, previewCanvas.width, previewCanvas.height);


            if (layers.every(l => l.image === null)) {
                ctx.font = '20px Arial';
                ctx.fillStyle = '#666';
                ctx.textAlign = 'center';
                ctx.fillText("Upload images to start", previewCanvas.width / 2, previewCanvas.height / 2);
                return;
            }

            const bgParallax = parseFloat(bgParallaxSlider.value);
            const fgParallax = parseFloat(fgParallaxSlider.value);
            const numLayers = layers.length;

            const minSliderAngle = parseFloat(viewingAngleInput.min);
            const maxSliderAngle = parseFloat(viewingAngleInput.max);
            const sliderRange = maxSliderAngle - minSliderAngle;

            let normalizedLiveViewAngle = 0;
            if (sliderRange > 0) {
                normalizedLiveViewAngle = (liveViewAngle - minSliderAngle) / sliderRange * 2 - 1;
            }

            // Layers are drawn in the order they appear in the 'layers' array (background to foreground)
            layers.forEach((layer, index) => {
                if (!layer.image) return;

                let layerParallax = 0;
                if (numLayers === 1) {
                    layerParallax = fgParallax;
                } else {
                    const t = index / (numLayers - 1);
                    layerParallax = bgParallax + (fgParallax - bgParallax) * t;
                }

                const normalizedParallax = layerParallax / 100;

                const maxPreviewShift = previewCanvas.width * 0.05;
                const shiftX = normalizedLiveViewAngle * normalizedParallax * maxPreviewShift;

                const scaledWidth = layer.image.width * (layer.scale / 100);
                const scaledHeight = layer.image.height * (layer.scale / 100);

                ctx.drawImage(
                    layer.image,
                    layer.offsetX + shiftX,
                    layer.offsetY,
                    scaledWidth,
                    scaledHeight
                );
            });
        }

        // --- Preview Animation ---
        function animatePreview() {
            const minAngle = parseFloat(viewingAngleInput.min);
            const maxAngle = parseFloat(viewingAngleInput.max);

            currentLiveViewAngle += previewDirection * previewSpeed;

            if (currentLiveViewAngle >= maxAngle || currentLiveViewAngle <= minAngle) {
                previewDirection *= -1;
                currentLiveViewAngle = Math.max(minAngle, Math.min(maxAngle, currentLiveViewAngle));
            }

            viewingAngleInput.value = currentLiveViewAngle;
            viewingAngleValueSpan.textContent = Math.round(currentLiveViewAngle);
            drawLenticularPreview(currentLiveViewAngle);

            animationFrameId = requestAnimationFrame(animatePreview);
        }

        function startPreviewAnimation() {
            if (!animationFrameId) {
                const minAngle = parseFloat(viewingAngleInput.min);
                const maxAngle = parseFloat(viewingAngleInput.max);

                previewDirection = (currentLiveViewAngle >= maxAngle - previewSpeed) ? -1 : 1;
                animatePreview();
            }
        }

        function stopPreviewAnimation() {
            cancelAnimationFrame(animationFrameId);
            animationFrameId = null;
        }

        // --- Export Frames ---
        async function generateAndExportFrames() {
            exportedFrames.length = 0;
            exportedFramesContainer.innerHTML = '';

            const numFrames = parseInt(framesInput.value, 10);
            if (isNaN(numFrames) || numFrames < 2) {
                alert("Please enter a valid number of frames (at least 2).");
                return;
            }
            if (baseImageWidth === 0 || baseImageHeight === 0) {
                alert("Please upload at least one image layer first to determine canvas size.");
                return;
            }
            previewCanvas.width = baseImageWidth;
            previewCanvas.height = baseImageHeight;

            const originalLiveViewAngle = currentLiveViewAngle;
            const minFrameAngle = parseFloat(viewingAngleInput.min);
            const maxFrameAngle = parseFloat(viewingAngleInput.max);
            const angleSpan = maxFrameAngle - minFrameAngle;

            const angleStep = angleSpan / (numFrames - 1);

            for (let i = 0; i < numFrames; i++) {
                const angle = minFrameAngle + (i * angleStep);
                drawLenticularPreview(angle);
                const dataURL = previewCanvas.toDataURL('image/png');
                exportedFrames.push(dataURL);

                const imgElement = document.createElement('img');
                imgElement.src = dataURL;
                imgElement.alt = `Frame ${i + 1}`;
                exportedFramesContainer.appendChild(imgElement);
            }
            drawLenticularPreview(originalLiveViewAngle);
        }

        // --- Interlacing and Final Export ---
        async function interlaceFrames() {
            if (exportedFrames.length === 0) {
                alert("Please generate frames first!");
                return;
            }

            const lpi = parseFloat(lpiInput.value);
            const outputDpi = parseFloat(outputDpiInput.value);
            if (isNaN(lpi) || lpi <= 0) { alert("Please enter a valid LPI value."); return; }
            if (isNaN(outputDpi) || outputDpi <= 0) { alert("Please enter a valid Output DPI value."); return; }

            const numFrames = exportedFrames.length;
            const frameWidth = baseImageWidth;
            const frameHeight = baseImageHeight;

            const lensletWidthPixels = outputDpi / lpi;
            if (lensletWidthPixels < 1) {
                alert(`LPI (${lpi}) is too high for the chosen Output DPI (${outputDpi}). Increase DPI or decrease LPI.`);
                return;
            }

            const finalImageWidth = Math.round((frameWidth / 96) * outputDpi);
            const finalImageHeight = Math.round((frameHeight / 96) * outputDpi);

            const finalCanvas = document.createElement('canvas');
            finalCanvas.width = finalImageWidth;
            finalCanvas.height = finalImageHeight;
            const finalCtx = finalCanvas.getContext('2d');

            // Load images from DataURLs. This ensures they are ready for drawing.
            const frameImages = await Promise.all(exportedFrames.map(url => new Promise(resolve => {
                const img = new Image();
                img.onload = () => resolve(img);
                img.onerror = () => { console.error("Failed to load frame image:", url); resolve(null); };
                img.src = url;
            }))).then(images => images.filter(img => img !== null));

            if (frameImages.length !== numFrames) {
                alert("Some frames failed to load during interlacing. Cannot proceed.");
                return;
            }

            // --- Robust Interlacing Algorithm ---
            // Iterate through each vertical lenslet column in the final high-resolution image.
            for (let lensletPixelX = 0; lensletPixelX < finalImageWidth; lensletPixelX += lensletWidthPixels) {
                // For each lenslet, iterate through all frames to draw their respective slices.
                for (let frameIdx = 0; frameIdx < numFrames; frameIdx++) {
                    const sourceFrame = frameImages[frameIdx];
                    if (!sourceFrame) continue; // Skip if image failed to load

                    // Calculate the width of each strip from a single frame on the final interlaced image.
                    const stripWidthOnFinal = lensletWidthPixels / numFrames;

                    // Calculate the starting X position for this strip on the final canvas.
                    // It's the start of the current lenslet + (frame index * width of each strip within the lenslet).
                    const destXOnFinal = lensletPixelX + (frameIdx * stripWidthOnFinal);

                    // Calculate the source X position on the *original frame image*.
                    // This maps the current frame index proportionally to the source frame's total width.
                    // This ensures we're taking a unique slice from each original frame.
                    const srcXInOriginalFrame = Math.floor((frameIdx / numFrames) * frameWidth);

                    // Determine the width of the source strip to pull from the original frame.
                    // It should ideally be `frameWidth / numFrames`, but we use ceil to ensure we grab at least 1 pixel
                    // and handle non-integer divisions gracefully to prevent gaps.
                    const sourceStripWidth = Math.ceil(frameWidth / numFrames);

                    finalCtx.drawImage(
                        sourceFrame,
                        srcXInOriginalFrame, 0,      // Source X, Y (from the original frame)
                        sourceStripWidth, frameHeight, // Source Width, Height (take a strip from the source)
                        destXOnFinal, 0,             // Destination X, Y (on the final large canvas)
                        stripWidthOnFinal, finalImageHeight // Destination Width, Height (draw the strip, scaled to final size)
                    );
                }
            }

            const finalImageURL = finalCanvas.toDataURL('image/png'); // PNG preserves transparency
            finalLenticularImage.src = finalImageURL;
            finalLenticularImage.style.display = 'block';
            downloadFinalLenticular.href = finalImageURL;
            downloadFinalLenticular.style.display = 'block';
        }

        // Initial setup
        addLayer();
        previewCanvas.width = 600;
        previewCanvas.height = 400;
        applyTotalViewingAngle(); // Set up the viewing angle slider initially
        drawLenticularPreview(currentLiveViewAngle);
        updateLayerOrderUI();
    </script>
</body>
</html>