{"id":137468,"date":"2025-06-13T18:15:02","date_gmt":"2025-06-13T16:15:02","guid":{"rendered":"https:\/\/www.cuttalo.com\/stencil-realta-aumentata\/"},"modified":"2025-10-04T03:51:43","modified_gmt":"2025-10-04T01:51:43","slug":"stencil-augmented-reality","status":"publish","type":"page","link":"https:\/\/www.cuttalo.com\/en\/stencil-augmented-reality\/","title":{"rendered":"Stencil augmented reality"},"content":{"rendered":"<!--themify_builder_content-->\n<div id=\"themify_builder_content-137468\" data-postid=\"137468\" class=\"themify_builder_content themify_builder_content-137468 themify_builder tf_clear\">\n                    <div  data-css_id=\"q3gf50\" data-lazy=\"1\" class=\"module_row themify_builder_row fullwidth_row_container tb_q3gf50 tb_first tf_w\">\n                        <div class=\"row_inner col_align_top tb_col_count_1 tf_box tf_rel\">\n                        <div  data-lazy=\"1\" class=\"module_column tb-column col-full tb_bt2t50 first\">\n                    <!-- module plain text -->\n<div  class=\"module module-plain-text tb_qrsw50 \" data-lazy=\"1\">\n        <div class=\"tb_text_wrap\">\n            \r\n        <div id=\"stencil-ar-app\" class=\"stencil-ar-app\">\r\n            <!-- Hero Section -->\r\n            <div class=\"ar-hero-section\">\r\n                <h1 class=\"ar-hero-title\">\r\n                <span class=\"ar-text-gradient\">Your Stencil<\/span>\r\n                <span class=\"ar-text-highlight\">in reality!<\/span>\r\n                <\/h1>\r\n                <p class=\"ar-hero-subtitle\">Upload a Stencil file and view it in augmented reality with your Android smartphone. For best results, use PNG or SVG images with transparent backgrounds.<\/p>\r\n                <\/div>\r\n\r\n            <!-- Upload Section -->\r\n            <div id=\"ar-upload-container\" class=\"ar-upload-container\">\r\n                <div class=\"ar-upload-card\">\r\n                    <!-- Main Upload Section (Desktop Left Side) -->\r\n                    <div class=\"ar-upload-main-section\">\r\n                        <div class=\"ar-upload-area\" id=\"ar-upload-area\">\r\n                        <input type=\"file\" id=\"ar-file-input\" accept=\".png,.svg,.jpg,.jpeg\" style=\"display: none;\">\r\n                        \r\n                        <div class=\"ar-upload-content\" id=\"ar-upload-content\">\r\n                            <div class=\"ar-upload-icon-wrapper\">\r\n                                <div class=\"ar-upload-icon\">\r\n                                    <span style=\"font-size: 40px;\">\ud83d\udce4<\/span>\r\n                                <\/div>\r\n                                <div class=\"ar-pulse-ring\"><\/div>\r\n                            <\/div>\r\n                            <h3 class=\"ar-upload-title\">Drag your image here<\/h3>\r\n                            <p class=\"ar-upload-text\">or <span class=\"ar-upload-link\">browse<\/span> from your device<\/p>\r\n                            <div class=\"ar-upload-formats\">\r\n                                <span class=\"ar-format-badge\">PNG<\/span>\r\n                                <span class=\"ar-format-badge\">SVG<\/span>\r\n                                <span class=\"ar-format-badge\">JPG<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n\r\n                        <!-- Preview Section -->\r\n                        <div class=\"ar-preview-section\" id=\"ar-preview-section\" style=\"display: none;\">\r\n                            <div class=\"ar-preview-container\">\r\n                                <img id=\"ar-preview-image\" class=\"ar-preview-image\" alt=\"Preview\">\r\n                                <div class=\"ar-preview-overlay\">\r\n                                    <button class=\"ar-preview-remove\" id=\"ar-preview-remove\">\r\n                                        <span style=\"font-size: 24px;\">\u2715<\/span>\r\n                                    <\/button>\r\n                                <\/div>\r\n                            <\/div>\r\n                            <div class=\"ar-file-details\">\r\n                                <div class=\"ar-file-name\" id=\"ar-file-name\"><\/div>\r\n                                <div class=\"ar-file-size\" id=\"ar-file-size\"><\/div>\r\n                            <\/div>\r\n\r\n                            <!-- AR Start Button in Preview -->\r\n                            <div class=\"ar-preview-actions\" style=\"margin-top: 1rem; text-align: center;\">\r\n                                <button id=\"ar-start-button\" class=\"ar-button ar-button-primary\" disabled>\r\n                                    <span class=\"ar-button-content\">\r\n                                        <span class=\"ar-button-icon\">\u26a1<\/span>\r\n                                        <span>Start AR Experience<\/span>\r\n                                    <\/span>\r\n                                    <div class=\"ar-button-glow\"><\/div>\r\n                                <\/button>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <!-- Progress Bar -->\r\n                    <div class=\"ar-progress-bar\" id=\"ar-progress-bar\" style=\"display: none;\">\r\n                        <div class=\"ar-progress-fill\" id=\"ar-progress-fill\"><\/div>\r\n                    <\/div>\r\n                    \r\n                    <!-- Background Removal Option - Outside upload container for better mobile visibility -->\r\n                    <div class=\"ar-bg-removal-option\" id=\"ar-bg-removal-section\" style=\"display: none; margin-top: 20px; padding: 15px; background: #f0f0f0; border-radius: 8px; border: 1px solid #ddd;\">\r\n                        <div style=\"display: flex; flex-direction: column; gap: 10px;\">\r\n                            <label style=\"display: flex; align-items: center; gap: 10px; cursor: pointer; font-size: 16px;\">\r\n                                <input type=\"checkbox\" id=\"ar-remove-bg\" name=\"remove_bg\" style=\"width: 20px; height: 20px; cursor: pointer;\">\r\n                                <span style=\"color: #333; font-weight: 500;\">Remove white background<\/span>\r\n                            <\/label>\r\n                            <div id=\"ar-processing-status\" style=\"display: none; margin-top: 10px; color: #666; font-size: 14px;\">\r\n                                Processing...                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <\/div>\r\n\r\n                    <!-- Compatibility Sidebar (Desktop Right Side) -->\r\n                    <div class=\"ar-compatibility-sidebar\" id=\"ar-compatibility-sidebar\">\r\n                        <div class=\"ar-compatibility\" id=\"ar-compatibility\">\r\n                            <div class=\"ar-compat-checking\">\r\n                                <div class=\"ar-spinner\"><\/div>\r\n                                <span>Checking AR compatibility...<\/span>\r\n                            <\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Features Grid -->\r\n                <div class=\"ar-features-grid\">\r\n                    <div class=\"ar-feature-card\">\r\n                        <div class=\"ar-feature-icon\">\ud83d\udca1<\/div>\r\n                        <h4>Perfectly Integrated Stencil<\/h4>\r\n                        <p>See your Stencil as it will be in reality<\/p>\r\n                    <\/div>\r\n                    <div class=\"ar-feature-card\">\r\n                        <div class=\"ar-feature-icon\">\ud83d\udd04<\/div>\r\n                        <h4>Intuitive Controls<\/h4>\r\n                        <p>Resize and rotate with natural gestures<\/p>\r\n                    <\/div>\r\n                    <div class=\"ar-feature-card\">\r\n                        <div class=\"ar-feature-icon\">\ud83c\udfaf<\/div>\r\n                        <h4>Precise Positioning<\/h4>\r\n                        <p>Place your image on any flat surface<\/p>\r\n                    <\/div>\r\n                    <div class=\"ar-feature-card\">\r\n                        <div class=\"ar-feature-icon\">\ud83d\udcf1<\/div>\r\n                        <h4>Android AR<\/h4>\r\n                        <p>Optimized for Android devices with Chrome<\/p>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- AR Viewer (Hidden by default) -->\r\n            <div id=\"ar-viewer-container\" class=\"ar-viewer-container\" style=\"display: none;\">\r\n                <div id=\"ar-canvas-container\"><\/div>\r\n                \r\n                <!-- AR Controls Overlay -->\r\n                <div class=\"ar-controls-overlay\">\r\n                    <div class=\"ar-top-bar\">\r\n                        <button id=\"ar-exit-button\" class=\"ar-control-button ar-exit-button\">\r\n                            <span style=\"font-size: 24px;\">\u2715<\/span>\r\n                        <\/button>\r\n                        <div class=\"ar-status-indicator\" id=\"ar-status-indicator\">\r\n                            <div class=\"ar-status-dot\"><\/div>\r\n                            <span id=\"ar-status-text\">Initializing AR...<\/span>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"ar-bottom-controls\" id=\"ar-bottom-controls\" style=\"display: none;\">\r\n                        <button class=\"ar-control-btn ar-control-primary\" id=\"ar-place-button\" data-tooltip=\"Place\" style=\"display: none;\">\r\n                            <span style=\"font-size: 28px;\">\u2713<\/span>\r\n                        <\/button>\r\n\r\n                        <div class=\"ar-control-group\">\r\n                            <button class=\"ar-control-btn ar-control-reset\" id=\"ar-reset-button\" data-tooltip=\"Reset position\">\r\n                                <span style=\"font-size: 24px;\">\u21ba<\/span>\r\n                                <span style=\"font-size: 16px; margin-left: 8px;\">Reset<\/span>\r\n                            <\/button>\r\n                            \r\n                            <button class=\"ar-control-btn ar-outdoor-mode\" id=\"ar-outdoor-toggle\" data-tooltip=\"Outdoor mode\">\r\n                                <span style=\"font-size: 24px;\">\ud83c\udfe2<\/span>\r\n                                <span style=\"font-size: 16px; margin-left: 8px;\">Outdoor<\/span>\r\n                            <\/button>\r\n                        <\/div>\r\n                        \r\n                        <div class=\"ar-gesture-hint\">\r\n                            <span style=\"font-size: 14px; color: rgba(255, 255, 255, 0.9);\">\u270c\ufe0f Pinch to resize and rotate<\/span>\r\n                        <\/div>\r\n                    <\/div>\r\n                    \r\n                    <!-- Surface type indicator -->\r\n                    <div class=\"ar-surface-indicator\" id=\"ar-surface-indicator\" style=\"display: none;\">\r\n                        <span id=\"ar-surface-type\">Surface detected<\/span>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Tutorial Overlay -->\r\n                <div class=\"ar-tutorial-overlay\" id=\"ar-tutorial-overlay\" style=\"display: none;\">\r\n                    <div class=\"ar-tutorial-content\">\r\n                        <div class=\"ar-tutorial-step\" id=\"ar-tutorial-step-1\">\r\n                            <div class=\"ar-tutorial-icon\">\ud83d\udcf1<\/div>\r\n                            <h3>Move your device<\/h3>\r\n                            <p>Slowly move your phone from left to right pointing at the floor or a wall<\/p>\r\n                        <\/div>\r\n                        <div class=\"ar-tutorial-step\" id=\"ar-tutorial-step-2\" style=\"display: none;\">\r\n                            <div class=\"ar-tutorial-icon\">\ud83d\udfe2<\/div>\r\n                            <h3>Look for the colored circle<\/h3>\r\n                            <p>Green = floor, Cyan = wall. The circle shows where you can place the image<\/p>\r\n                        <\/div>\r\n                        <div class=\"ar-tutorial-step\" id=\"ar-tutorial-step-3\" style=\"display: none;\">\r\n                            <div class=\"ar-tutorial-icon\">\ud83d\udc46<\/div>\r\n                            <h3>Tap to place<\/h3>\r\n                            <p>Tap the screen or use the button to place the image<\/p>\r\n                        <\/div>\r\n                        <div class=\"ar-tutorial-step\" id=\"ar-tutorial-step-4\" style=\"display: none;\">\r\n                            <div class=\"ar-tutorial-icon\">\ud83d\udcf8<\/div>\r\n                            <h3>Capture the screen<\/h3>\r\n                            <p>Use your device screenshot function to save the image (Volume down + Power on Android)<\/p>\r\n                        <\/div>\r\n                    <\/div>\r\n                    <button type=\"button\" class=\"ar-tutorial-skip\" id=\"ar-tutorial-skip\">Skip tutorial \u2192<\/button>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <script type=\"module\">\r\n            \/\/ Translations for JavaScript\r\n            const arTranslations = {\r\n                selectFile: 'Select a PNG, SVG or JPG file',\r\n                fileTooLarge: 'File is too large. Maximum 10MB.',\r\n                imageUploaded: 'Image uploaded successfully!',\r\n                uploadError: 'Upload error:',\r\n                loadingFromUrl: 'Loading image from URL...',\r\n                loadingSaved: 'Loading saved image...',\r\n                errorLoadingUrl: 'Error loading image from URL',\r\n                errorLoadingSaved: 'Error loading saved image',\r\n                arActive: 'AR active - Look for a surface',\r\n                moveDevice: 'Move your device slowly to detect surfaces',\r\n                surfaceDetected: 'detected - Tap to place',\r\n                floor: 'Floor',\r\n                wall: 'Wall',\r\n                stable: '(stable)',\r\n                imagePlaced: 'Image placed',\r\n                onWall: 'on wall',\r\n                onFloor: 'on floor',\r\n                outdoorMode: '(Outdoor mode)',\r\n                indoorMode: '(Indoor mode)',\r\n                continueMoving: 'Continue moving device for better detection',\r\n                pointToWall: 'Point at a wall and move device slowly',\r\n                lookForSurface: 'Move device to find surfaces',\r\n                pinchInstruction: '\u270c\ufe0f Pinch to resize - \ud83d\udd04 Rotate with 2 fingers - \ud83d\udcf8 Screenshot to save',\r\n                pinchInstructionFloor: '\u270c\ufe0f Pinch with 2 fingers to modify - \ud83d\udcf8 Use device screenshot',\r\n                outdoorActivated: 'Outdoor mode activated - Scale increased for longer distances',\r\n                indoorActivated: 'Indoor mode activated - Normal scale for close distances',\r\n                indoor: 'Indoor',\r\n                outdoor: 'Outdoor',\r\n                shareText: 'Check out this AR experience on Android! \ud83c\udfaf\u2728',\r\n                linkCopied: 'Link copied to clipboard!',\r\n                copyError: 'Unable to copy link',\r\n                repositionImage: 'Reposition image',\r\n                touchToStart: 'Tap to start AR',\r\n                goodLighting: 'Make sure you are in a well-lit environment',\r\n                desktopWarning: 'Use your Android smartphone!',\r\n                desktopMessage: 'AR experience is only available on Android devices with Chrome.',\r\n                shareOnPhone: 'Share this page on your Android smartphone:',\r\n                shareWhatsApp: 'Share on WhatsApp',\r\n                copyLink: 'Copy link',\r\n                close: 'Close',\r\n                closingAr: 'Closing AR...',\r\n                loadingImage: 'Loading image...',\r\n                imageReady: 'Image loaded - Ready for AR',\r\n                loadingPercent: 'Loading: %s%%',\r\n                hitTestError: 'Hit test not available',\r\n                arSessionActive: 'AR session already active',\r\n                arNotSupported: 'AR not supported on this device',\r\n                arPermissionDenied: 'Camera permission denied.',\r\n                arSecurityError: 'Requires secure connection (HTTPS).',\r\n                arGenericError: 'Unable to start AR session.',\r\n                trackingLost: 'Tracking lost - Move device',\r\n                trackingRestored: 'Tracking restored!',\r\n                outdoorModeHint: 'For buildings\/outdoor use the \ud83c\udfe2 Outdoor button',\r\n                desktopDetected: '\u26a0\ufe0f Desktop device detected',\r\n                desktopInstructions: 'AR experience is only available on Android mobile devices with WebXR support.',\r\n                iosDetected: '\u26a0\ufe0f iOS device detected',\r\n                iosMessage: 'Unfortunately iOS\/Safari does not yet support WebXR AR.',\r\n                useAndroid: 'Use an Android device with Chrome for the full AR experience.',\r\n                arCompatible: '\u2713 AR compatible Android device',\r\n                checkingCompatibility: 'Checking AR compatibility...',\r\n                updateChrome: 'Try updating Chrome and verify ARCore is installed.',\r\n                webxrNotAvailable: 'WebXR not available. Use Chrome on an ARCore compatible Android device.',\r\n                errorLoadingLibraries: 'Error loading AR libraries. Check internet connection and reload.',\r\n                imageFromUrl: 'Image from URL',\r\n                savedImage: 'Saved image',\r\n                copied: '\u2713 Copied!',\r\n                startAR: 'Start AR Experience'\r\n            };\r\n            \r\n            \/\/ Importa Three.js con fallback\r\n            let THREE, ARButton, XRRay;\r\n            \r\n            try {\r\n                const threeModule = await import('https:\/\/cdn.jsdelivr.net\/npm\/three@0.152.0\/build\/three.module.js');\r\n                const ARButtonModule = await import('https:\/\/cdn.jsdelivr.net\/npm\/three@0.152.0\/examples\/jsm\/webxr\/ARButton.js');\r\n                THREE = threeModule;\r\n                ARButton = ARButtonModule.ARButton;\r\n                XRRay = window.XRRay;\r\n            } catch (error) {\r\n                console.error('Error loading Three.js from main CDN, trying alternative CDN...');\r\n                try {\r\n                    const threeModule = await import('https:\/\/unpkg.com\/three@0.152.0\/build\/three.module.js');\r\n                    const ARButtonModule = await import('https:\/\/unpkg.com\/three@0.152.0\/examples\/jsm\/webxr\/ARButton.js');\r\n                    THREE = threeModule;\r\n                    ARButton = ARButtonModule.ARButton;\r\n                    XRRay = window.XRRay;\r\n                } catch (fallbackError) {\r\n                    console.error('Unable to load Three.js:', fallbackError);\r\n                    document.getElementById('ar-compatibility').innerHTML = `\r\n                        <div class=\"ar-compat-error\">\r\n                            <p>${arTranslations.errorLoadingLibraries}<\/p>\r\n                        <\/div>\r\n                    `;\r\n                }\r\n            }\r\n            \r\n            class StencilARApp {\r\n                constructor() {\r\n                    \/\/ Verifica che Three.js sia caricato\r\n                    if (typeof THREE === 'undefined') {\r\n                        console.error('Three.js not loaded');\r\n                        this.showThreeJSError();\r\n                        return;\r\n                    }\r\n                    \r\n                    this.uploadedFile = null;\r\n                    this.uploadedImageUrl = null;\r\n                    this.isARActive = false;\r\n                    this.isStartingAR = false;\r\n                    this.isExiting = false;\r\n                    this.currentScale = 1;\r\n                    this.nonce = '9f292a79cf';\r\n                    this.ajaxUrl = 'https:\/\/www.cuttalo.com\/wp-admin\/admin-ajax.php';\r\n                    this.logoUrl = 'https:\/\/www.cuttalo.com\/wp-content\/plugins\/00arstencil\/logo.svg';\r\n                    this.uploadedImageId = null;\r\n                    \r\n                    \/\/ Modalit\u00e0 esterni\r\n                    this.outdoorMode = false;\r\n                    this.defaultScale = 1;\r\n                    \r\n                    \/\/ Inizializza propriet\u00e0 Three.js\r\n                    this.renderer = null;\r\n                    this.scene = null;\r\n                    this.camera = null;\r\n                    this.imagePlane = null;\r\n                    this.imageGroup = null;\r\n                    this.imagePlaneContainer = null;\r\n                    this.reticle = null;\r\n                    this.reticleVisuals = null;\r\n                    this.xrSession = null;\r\n                    this.hitTestSource = null;\r\n                    this.localReferenceSpace = null;\r\n                    this.viewerSpace = null;\r\n                    this.hitTestSourceRequested = false;\r\n                    this.isPlaced = false;\r\n                    \r\n                    \/\/ Variabili per il tracking della superficie\r\n                    this.lastHitPose = null;\r\n                    this.surfaceOrientation = 'unknown';\r\n                    this.surfaceNormal = new THREE.Vector3(0, 1, 0);\r\n                    this.placedRotation = 0;\r\n                    \r\n                    \/\/ Variabili avanzate per il rilevamento superfici\r\n                    this.hitTestHistory = [];\r\n                    this.hitTestHistorySize = 10;\r\n                    this.verticalSurfaceThreshold = 0.3; \/\/ Pi\u00f9 basso = pi\u00f9 sensibile a superfici verticali\r\n                    this.surfaceConfidence = 0;\r\n                    this.minConfidenceThreshold = 0.7;\r\n                    this.lastValidHit = null;\r\n                    this.surfaceAngle = 0;\r\n                    \r\n                    \/\/ Event handlers\r\n                    this.sessionStartHandler = null;\r\n                    this.sessionEndHandler = null;\r\n                    this.sessionInterruptHandler = null;\r\n                    this.sessionResumeHandler = null;\r\n                    \r\n                    this.init();\r\n                }\r\n                \r\n                showThreeJSError() {\r\n                    const compatDiv = document.getElementById('ar-compatibility');\r\n                    if (compatDiv) {\r\n                        compatDiv.innerHTML = `\r\n                            <div class=\"ar-compat-error\">\r\n                                <p><strong>\u26a0\ufe0f Errore di caricamento<\/strong><\/p>\r\n                                <p>Impossibile caricare le librerie AR necessarie.<\/p>\r\n                                <p>Ricarica la pagina o verifica la connessione.<\/p>\r\n                            <\/div>\r\n                        `;\r\n                    }\r\n                }\r\n                \r\n                init() {\r\n                    this.setupUploadHandlers();\r\n                    this.checkARCompatibility();\r\n                    this.setupKeyboardShortcuts();\r\n                    this.checkUrlParameters();\r\n                }\r\n                \r\n                async checkUrlParameters() {\r\n                    const urlParams = new URLSearchParams(window.location.search);\r\n                    const uploadFromUrl = urlParams.get('uploadFromUrl');\r\n                    const imageId = urlParams.get('imageId');\r\n                    \r\n                    if (uploadFromUrl) {\r\n                        \/\/ Carica immagine da URL\r\n                        this.showNotification('Caricamento immagine da URL...', 'info');\r\n                        try {\r\n                            await this.uploadFromUrl(uploadFromUrl);\r\n                        } catch (error) {\r\n                            console.error('Errore caricamento da URL:', error);\r\n                            this.showNotification('Errore nel caricamento dell\\'immagine da URL', 'error');\r\n                        }\r\n                    } else if (imageId) {\r\n                        \/\/ Carica immagine gi\u00e0 salvata\r\n                        this.showNotification('Caricamento immagine salvata...', 'info');\r\n                        try {\r\n                            await this.loadSavedImage(imageId);\r\n                        } catch (error) {\r\n                            console.error('Errore caricamento immagine salvata:', error);\r\n                            this.showNotification('Errore nel caricamento dell\\'immagine salvata', 'error');\r\n                        }\r\n                    }\r\n                }\r\n                \r\n                async uploadFromUrl(imageUrl) {\r\n                    const progressBar = document.getElementById('ar-progress-bar');\r\n                    const progressFill = document.getElementById('ar-progress-fill');\r\n                    const startButton = document.getElementById('ar-start-button');\r\n                    \r\n                    progressBar.style.display = 'block';\r\n                    startButton.disabled = true;\r\n                    \r\n                    const formData = new FormData();\r\n                    formData.append('url', imageUrl);\r\n                    formData.append('action', 'stencil_ar_upload_from_url');\r\n                    formData.append('nonce', this.nonce);\r\n                    \r\n                    try {\r\n                        \/\/ Simulate progress\r\n                        let progress = 0;\r\n                        const progressInterval = setInterval(() => {\r\n                            progress += Math.random() * 30;\r\n                            if (progress > 90) progress = 90;\r\n                            progressFill.style.width = progress + '%';\r\n                        }, 200);\r\n                        \r\n                        const response = await fetch(this.ajaxUrl, {\r\n                            method: 'POST',\r\n                            body: formData\r\n                        });\r\n                        \r\n                        clearInterval(progressInterval);\r\n                        progressFill.style.width = '100%';\r\n                        \r\n                        const data = await response.json();\r\n                        \r\n                        if (data.success) {\r\n                            this.uploadedImageUrl = data.data.url;\r\n                            this.uploadedImageId = data.data.id;\r\n                            \r\n                            \/\/ Mostra anteprima\r\n                            const previewImage = document.getElementById('ar-preview-image');\r\n                            const fileName = document.getElementById('ar-file-name');\r\n                            const fileSize = document.getElementById('ar-file-size');\r\n                            \r\n                            \/\/ Debug info\r\n                            console.log('URL upload result:', data.data);\r\n                            console.log('Image URL:', data.data.url);\r\n                            console.log('Image type:', data.data.type);\r\n\r\n                            \/\/ Gestione speciale per SVG\r\n                            previewImage.onload = () => {\r\n                                console.log('Image loaded successfully');\r\n                                \/\/ Force reflow per SVG\r\n                                previewImage.style.display = 'none';\r\n                                previewImage.offsetHeight; \/\/ trigger reflow\r\n                                previewImage.style.display = 'block';\r\n                            };\r\n                            previewImage.onerror = () => {\r\n                                console.error('Failed to load image:', data.data.url);\r\n                            };\r\n\r\n                            previewImage.src = data.data.url;\r\n                            fileName.textContent = data.data.filename || 'Immagine da URL';\r\n                            fileSize.textContent = this.formatFileSize(data.data.size || 0);\r\n\r\n                            document.getElementById('ar-upload-content').style.display = 'none';\r\n                            document.getElementById('ar-preview-section').style.display = 'block';\r\n\r\n                            console.log('Preview section shown, image element:', previewImage);\r\n                            console.log('Image src set to:', previewImage.src);\r\n                            \r\n                            startButton.disabled = false;\r\n                            this.showNotification('Immagine caricata con successo!', 'success');\r\n                            \r\n                            \/\/ Aggiorna URL con imageId\r\n                            const newUrl = new URL(window.location);\r\n                            newUrl.searchParams.delete('uploadFromUrl');\r\n                            newUrl.searchParams.set('imageId', data.data.id);\r\n                            window.history.replaceState({}, '', newUrl);\r\n                            \r\n                            setTimeout(() => {\r\n                                progressBar.style.display = 'none';\r\n                                progressFill.style.width = '0%';\r\n                            }, 500);\r\n                        } else {\r\n                            throw new Error(data.data || arTranslations.uploadError);\r\n                        }\r\n                    } catch (error) {\r\n                        console.error('Upload error:', error);\r\n                        this.showNotification('Errore durante il caricamento: ' + error.message, 'error');\r\n                        progressBar.style.display = 'none';\r\n                        this.resetUpload();\r\n                    }\r\n                }\r\n                \r\n                async loadSavedImage(imageId) {\r\n                    const formData = new FormData();\r\n                    formData.append('image_id', imageId);\r\n                    formData.append('action', 'stencil_ar_load_image');\r\n                    formData.append('nonce', this.nonce);\r\n                    \r\n                    try {\r\n                        const response = await fetch(this.ajaxUrl, {\r\n                            method: 'POST',\r\n                            body: formData\r\n                        });\r\n                        \r\n                        const data = await response.json();\r\n                        \r\n                        if (data.success) {\r\n                            this.uploadedImageUrl = data.data.url;\r\n                            this.uploadedImageId = imageId;\r\n                            \r\n                            \/\/ Mostra anteprima\r\n                            const previewImage = document.getElementById('ar-preview-image');\r\n                            const fileName = document.getElementById('ar-file-name');\r\n                            const fileSize = document.getElementById('ar-file-size');\r\n                            \r\n                            \/\/ Gestione speciale per SVG\r\n                            previewImage.onload = () => {\r\n                                \/\/ Force reflow per SVG\r\n                                previewImage.style.display = 'none';\r\n                                previewImage.offsetHeight; \/\/ trigger reflow\r\n                                previewImage.style.display = 'block';\r\n                            };\r\n                            previewImage.src = data.data.url;\r\n                            fileName.textContent = data.data.filename || 'Immagine salvata';\r\n                            fileSize.textContent = this.formatFileSize(data.data.size || 0);\r\n\r\n                            document.getElementById('ar-upload-content').style.display = 'none';\r\n                            document.getElementById('ar-preview-section').style.display = 'block';\r\n                            document.getElementById('ar-bg-removal-section').style.display = 'block';\r\n                            \r\n                            \/\/ Store original image for background removal\r\n                            this.originalImage = data.data.url;\r\n                            this.processedImage = null;\r\n                            this.uploadedFile = null; \/\/ No file object for saved images\r\n                            \r\n                            \/\/ Setup background removal for shared images\r\n                            this.setupBackgroundRemovalForShared();\r\n                            \r\n                            document.getElementById('ar-start-button').disabled = false;\r\n                            this.showNotification('Immagine caricata con successo!', 'success');\r\n                        } else {\r\n                            throw new Error(data.data || 'Immagine non trovata');\r\n                        }\r\n                    } catch (error) {\r\n                        console.error('Load error:', error);\r\n                        this.showNotification('Errore durante il caricamento: ' + error.message, 'error');\r\n                    }\r\n                }\r\n                \r\n                setupUploadHandlers() {\r\n                    const fileInput = document.getElementById('ar-file-input');\r\n                    const uploadArea = document.getElementById('ar-upload-area');\r\n                    const uploadContent = document.getElementById('ar-upload-content');\r\n                    const previewSection = document.getElementById('ar-preview-section');\r\n                    const startButton = document.getElementById('ar-start-button');\r\n                    const removeButton = document.getElementById('ar-preview-remove');\r\n                    \r\n                    \/\/ Click to upload\r\n                    uploadArea.addEventListener('click', (e) => {\r\n                        if (e.target === uploadArea || uploadContent.contains(e.target)) {\r\n                            fileInput.click();\r\n                        }\r\n                    });\r\n                    \r\n                    \/\/ Drag and drop\r\n                    uploadArea.addEventListener('dragover', (e) => {\r\n                        e.preventDefault();\r\n                        uploadArea.classList.add('dragover');\r\n                    });\r\n                    \r\n                    uploadArea.addEventListener('dragleave', (e) => {\r\n                        e.preventDefault();\r\n                        uploadArea.classList.remove('dragover');\r\n                    });\r\n                    \r\n                    uploadArea.addEventListener('drop', (e) => {\r\n                        e.preventDefault();\r\n                        uploadArea.classList.remove('dragover');\r\n                        \r\n                        const files = e.dataTransfer.files;\r\n                        if (files.length > 0) {\r\n                            this.handleFileSelect(files[0]);\r\n                        }\r\n                    });\r\n                    \r\n                    \/\/ File input change\r\n                    fileInput.addEventListener('change', (e) => {\r\n                        if (e.target.files.length > 0) {\r\n                            this.handleFileSelect(e.target.files[0]);\r\n                        }\r\n                    });\r\n                    \r\n                    \/\/ Remove file\r\n                    removeButton.addEventListener('click', () => {\r\n                        this.resetUpload();\r\n                    });\r\n                    \r\n                    \/\/ Start AR\r\n                    let isStartingFromButton = false;\r\n                    startButton.addEventListener('click', async () => {\r\n                        if (isStartingFromButton || this.isStartingAR || this.isARActive) {\r\n                            console.log('AR gi\u00e0 in corso o in fase di avvio...');\r\n                            return;\r\n                        }\r\n                        \r\n                        if (this.uploadedImageUrl) {\r\n                            isStartingFromButton = true;\r\n                            startButton.disabled = true;\r\n                            \r\n                            try {\r\n                                await this.startAR();\r\n                            } finally {\r\n                                setTimeout(() => {\r\n                                    if (!this.isARActive) {\r\n                                        startButton.disabled = false;\r\n                                    }\r\n                                    isStartingFromButton = false;\r\n                                }, 1000);\r\n                            }\r\n                        }\r\n                    });\r\n                }\r\n                \r\n                async handleFileSelect(file) {\r\n                    \/\/ Validate file type\r\n                    const validTypes = ['image\/png', 'image\/svg+xml', 'image\/jpeg', 'image\/jpg'];\r\n                    if (!validTypes.includes(file.type)) {\r\n                        this.showNotification('Seleziona un file PNG, SVG o JPG', 'error');\r\n                        return;\r\n                    }\r\n                    \r\n                    \/\/ Validate file size (max 10MB)\r\n                    const maxSize = 10 * 1024 * 1024;\r\n                    if (file.size > maxSize) {\r\n                        this.showNotification('Il file \u00e8 troppo grande. Massimo 10MB.', 'error');\r\n                        return;\r\n                    }\r\n                    \r\n                    this.uploadedFile = file;\r\n                    this.bgRemovalApplied = false;\r\n                    \r\n                    \/\/ Show preview\r\n                    this.showPreview(file);\r\n                    \r\n                    \/\/ Upload file automatically\r\n                    await this.uploadFile(file);\r\n                }\r\n                \r\n                showPreview(file) {\r\n                    const reader = new FileReader();\r\n                    reader.onload = (e) => {\r\n                        const previewImage = document.getElementById('ar-preview-image');\r\n                        const fileName = document.getElementById('ar-file-name');\r\n                        const fileSize = document.getElementById('ar-file-size');\r\n                        \r\n                        \/\/ Store original image\r\n                        this.originalImage = e.target.result;\r\n                        this.processedImage = null;\r\n                        \r\n                        previewImage.src = e.target.result;\r\n                        fileName.textContent = file.name;\r\n                        fileSize.textContent = this.formatFileSize(file.size);\r\n                        \r\n                        document.getElementById('ar-upload-content').style.display = 'none';\r\n                        document.getElementById('ar-preview-section').style.display = 'block';\r\n                        document.getElementById('ar-bg-removal-section').style.display = 'block';\r\n                        \r\n                        \/\/ Add success animation\r\n                        const previewContainer = document.querySelector('.ar-preview-container');\r\n                        previewContainer.classList.add('ar-success-animation');\r\n                        setTimeout(() => {\r\n                            previewContainer.classList.remove('ar-success-animation');\r\n                        }, 500);\r\n                        \r\n                        \/\/ Add event listener for checkbox\r\n                        const checkbox = document.getElementById('ar-remove-bg');\r\n                        const processingStatus = document.getElementById('ar-processing-status');\r\n                        \r\n                        if (!checkbox) {\r\n                            console.error('Checkbox not found');\r\n                            return;\r\n                        }\r\n                        \r\n                        \/\/ Store reference to this for use in callbacks\r\n                        const self = this;\r\n                        \r\n                        \/\/ Checkbox change handler\r\n                        checkbox.onchange = async () => {\r\n                            console.log('Checkbox changed:', checkbox.checked);\r\n                            \r\n                            if (checkbox.checked) {\r\n                                \/\/ Show processing status\r\n                                if (processingStatus) {\r\n                                    processingStatus.style.display = 'block';\r\n                                }\r\n                                checkbox.disabled = true;\r\n                                \r\n                                \/\/ Apply background removal\r\n                                self.removeWhiteBackground(self.originalImage, async (processedImage) => {\r\n                                    self.processedImage = processedImage;\r\n                                    self.bgRemovalApplied = true;\r\n                                    previewImage.src = processedImage;\r\n                                    \r\n                                    \/\/ Hide processing status\r\n                                    if (processingStatus) {\r\n                                        processingStatus.style.display = 'none';\r\n                                    }\r\n                                    checkbox.disabled = false;\r\n                                    \r\n                                    \/\/ Re-upload with processed image\r\n                                    await self.uploadFile(self.uploadedFile);\r\n                                });\r\n                            } else {\r\n                                \/\/ Restore original\r\n                                previewImage.src = self.originalImage;\r\n                                self.processedImage = null;\r\n                                self.bgRemovalApplied = false;\r\n                                \r\n                                \/\/ Re-upload with original image\r\n                                await self.uploadFile(self.uploadedFile);\r\n                            }\r\n                        };\r\n                    };\r\n                    reader.readAsDataURL(file);\r\n                }\r\n                \r\n                formatFileSize(bytes) {\r\n                    if (bytes === 0) return '0 Bytes';\r\n                    const k = 1024;\r\n                    const sizes = ['Bytes', 'KB', 'MB', 'GB'];\r\n                    const i = Math.floor(Math.log(bytes) \/ Math.log(k));\r\n                    return parseFloat((bytes \/ Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\r\n                }\r\n                \r\n                removeWhiteBackground(imageDataUrl, callback) {\r\n                    const img = new Image();\r\n                    img.crossOrigin = 'anonymous'; \/\/ Enable CORS for shared images\r\n                    img.onload = function() {\r\n                        const canvas = document.createElement('canvas');\r\n                        const ctx = canvas.getContext('2d');\r\n                        \r\n                        canvas.width = img.width;\r\n                        canvas.height = img.height;\r\n                        \r\n                        \/\/ Draw image\r\n                        ctx.drawImage(img, 0, 0);\r\n                        \r\n                        \/\/ Get image data\r\n                        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n                        const data = imageData.data;\r\n                        \r\n                        \/\/ Define white color threshold\r\n                        const threshold = 240; \/\/ Adjust this value for sensitivity\r\n                        \r\n                        \/\/ Process each pixel\r\n                        for (let i = 0; i < data.length; i += 4) {\r\n                            const r = data[i];\r\n                            const g = data[i + 1];\r\n                            const b = data[i + 2];\r\n                            \r\n                            \/\/ Check if pixel is white\r\n                            if (r > threshold && g > threshold && b > threshold) {\r\n                                \/\/ Make pixel transparent\r\n                                data[i + 3] = 0; \/\/ Alpha channel\r\n                            }\r\n                        }\r\n                        \r\n                        \/\/ Put modified image data back\r\n                        ctx.putImageData(imageData, 0, 0);\r\n                        \r\n                        \/\/ Convert to data URL and callback\r\n                        callback(canvas.toDataURL('image\/png'));\r\n                    };\r\n                    img.onerror = function() {\r\n                        console.error('Failed to load image for background removal');\r\n                        callback(imageDataUrl); \/\/ Return original if error\r\n                    };\r\n                    img.src = imageDataUrl;\r\n                }\r\n                \r\n                setupBackgroundRemovalForShared() {\r\n                    const checkbox = document.getElementById('ar-remove-bg');\r\n                    const previewImage = document.getElementById('ar-preview-image');\r\n                    const processingStatus = document.getElementById('ar-processing-status');\r\n                    \r\n                    if (!checkbox) {\r\n                        console.error('Checkbox not found');\r\n                        return;\r\n                    }\r\n                    \r\n                    const self = this;\r\n                    \r\n                    checkbox.onchange = () => {\r\n                        console.log('Checkbox changed for shared image:', checkbox.checked);\r\n                        \r\n                        if (checkbox.checked) {\r\n                            \/\/ Show processing status\r\n                            if (processingStatus) {\r\n                                processingStatus.style.display = 'block';\r\n                            }\r\n                            checkbox.disabled = true;\r\n                            \r\n                            self.removeWhiteBackground(self.originalImage, (processedImage) => {\r\n                                self.processedImage = processedImage;\r\n                                self.bgRemovalApplied = true;\r\n                                previewImage.src = processedImage;\r\n                                \r\n                                \/\/ For shared images, we need to upload the processed version\r\n                                self.uploadProcessedSharedImage(processedImage);\r\n                                \r\n                                \/\/ Hide processing status\r\n                                if (processingStatus) {\r\n                                    processingStatus.style.display = 'none';\r\n                                }\r\n                                checkbox.disabled = false;\r\n                            });\r\n                        } else {\r\n                            \/\/ Restore original\r\n                            previewImage.src = self.originalImage;\r\n                            self.uploadedImageUrl = self.originalImage;\r\n                            self.processedImage = null;\r\n                            self.bgRemovalApplied = false;\r\n                        }\r\n                    };\r\n                }\r\n                \r\n                async uploadProcessedSharedImage(processedDataUrl) {\r\n                    try {\r\n                        \/\/ Convert data URL to blob\r\n                        const response = await fetch(processedDataUrl);\r\n                        const blob = await response.blob();\r\n                        \r\n                        \/\/ Create form data\r\n                        const formData = new FormData();\r\n                        const fileName = 'shared_processed_' + Date.now() + '.png';\r\n                        const file = new File([blob], fileName, { type: 'image\/png' });\r\n                        \r\n                        formData.append('file', file);\r\n                        formData.append('action', 'stencil_ar_upload_file');\r\n                        formData.append('nonce', this.nonce);\r\n                        formData.append('remove_bg', '1');\r\n                        formData.append('is_shared_processed', '1');\r\n                        \r\n                        const uploadResponse = await fetch(this.ajaxUrl, {\r\n                            method: 'POST',\r\n                            body: formData\r\n                        });\r\n                        \r\n                        const data = await uploadResponse.json();\r\n                        \r\n                        if (data.success) {\r\n                            this.uploadedImageUrl = data.data.url;\r\n                            console.log('Processed shared image uploaded successfully');\r\n                        }\r\n                    } catch (error) {\r\n                        console.error('Error uploading processed shared image:', error);\r\n                    }\r\n                }\r\n                \r\n                async uploadFile(file) {\r\n                    const progressBar = document.getElementById('ar-progress-bar');\r\n                    const progressFill = document.getElementById('ar-progress-fill');\r\n                    const startButton = document.getElementById('ar-start-button');\r\n                    \r\n                    progressBar.style.display = 'block';\r\n                    startButton.disabled = true;\r\n                    \r\n                    const formData = new FormData();\r\n                    \r\n                    \/\/ Check if background removal was applied\r\n                    console.log('Background removal applied:', this.bgRemovalApplied);\r\n                    console.log('Processed image exists:', !!this.processedImage);\r\n                    \r\n                    if (this.bgRemovalApplied && this.processedImage) {\r\n                        console.log('Uploading processed image without background');\r\n                        try {\r\n                            \/\/ Convert data URL to blob\r\n                            const response = await fetch(this.processedImage);\r\n                            const blob = await response.blob();\r\n                            \r\n                            \/\/ Create new file with PNG extension\r\n                            const fileName = file.name.replace(\/\\.[^\/.]+$\/, '.png');\r\n                            const processedFile = new File([blob], fileName, { type: 'image\/png' });\r\n                            \r\n                            formData.append('file', processedFile);\r\n                            formData.append('remove_bg', '1'); \/\/ Flag to indicate background was removed\r\n                            console.log('Uploading processed PNG file');\r\n                        } catch (error) {\r\n                            console.error('Error processing image:', error);\r\n                            \/\/ Fallback to original file\r\n                            formData.append('file', file);\r\n                        }\r\n                    } else {\r\n                        console.log('Uploading original image');\r\n                        formData.append('file', file);\r\n                    }\r\n                    \r\n                    formData.append('action', 'stencil_ar_upload_file');\r\n                    formData.append('nonce', '9f292a79cf');\r\n                    \r\n                    try {\r\n                        \/\/ Simulate progress\r\n                        let progress = 0;\r\n                        const progressInterval = setInterval(() => {\r\n                            progress += Math.random() * 30;\r\n                            if (progress > 90) progress = 90;\r\n                            progressFill.style.width = progress + '%';\r\n                        }, 200);\r\n                        \r\n                        const response = await fetch('https:\/\/www.cuttalo.com\/wp-admin\/admin-ajax.php', {\r\n                            method: 'POST',\r\n                            body: formData\r\n                        });\r\n                        \r\n                        clearInterval(progressInterval);\r\n                        progressFill.style.width = '100%';\r\n                        \r\n                        const data = await response.json();\r\n                        \r\n                        if (data.success) {\r\n                            this.uploadedImageUrl = data.data.url;\r\n                            this.uploadedImageId = data.data.id;\r\n                            startButton.disabled = false;\r\n                            this.showNotification('Immagine caricata con successo!', 'success');\r\n                            \r\n                            \/\/ Aggiorna URL con imageId\r\n                            const newUrl = new URL(window.location);\r\n                            newUrl.searchParams.set('imageId', data.data.id);\r\n                            window.history.replaceState({}, '', newUrl);\r\n                            \r\n                            setTimeout(() => {\r\n                                progressBar.style.display = 'none';\r\n                                progressFill.style.width = '0%';\r\n                            }, 500);\r\n                        } else {\r\n                            throw new Error(data.data || arTranslations.uploadError);\r\n                        }\r\n                    } catch (error) {\r\n                        console.error('Upload error:', error);\r\n                        this.showNotification('Errore durante il caricamento: ' + error.message, 'error');\r\n                        progressBar.style.display = 'none';\r\n                        this.resetUpload();\r\n                    }\r\n                }\r\n                \r\n                resetUpload() {\r\n                    this.uploadedFile = null;\r\n                    this.uploadedImageUrl = null;\r\n                    this.uploadedImageId = null;\r\n                    \r\n                    document.getElementById('ar-upload-content').style.display = 'block';\r\n                    document.getElementById('ar-preview-section').style.display = 'none';\r\n                    document.getElementById('ar-bg-removal-section').style.display = 'none';\r\n                    document.getElementById('ar-start-button').disabled = true;\r\n                    document.getElementById('ar-file-input').value = '';\r\n                    \r\n                    \/\/ Reset checkbox\r\n                    const checkbox = document.getElementById('ar-remove-bg');\r\n                    if (checkbox) checkbox.checked = false;\r\n                    \r\n                    \/\/ Rimuovi imageId dall'URL\r\n                    const newUrl = new URL(window.location);\r\n                    newUrl.searchParams.delete('imageId');\r\n                    newUrl.searchParams.delete('uploadFromUrl');\r\n                    window.history.replaceState({}, '', newUrl);\r\n                }\r\n                \r\n                async checkARCompatibility() {\r\n                    const compatDiv = document.getElementById('ar-compatibility');\r\n                    \r\n                    \/\/ Check if on mobile\r\n                    const isMobile = \/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini\/i.test(navigator.userAgent);\r\n                    const isIOS = \/iPad|iPhone|iPod\/.test(navigator.userAgent) && !window.MSStream;\r\n                    const isAndroid = \/Android\/i.test(navigator.userAgent);\r\n                    \r\n                    if (!isMobile) {\r\n                        compatDiv.innerHTML = `\r\n                            <div class=\"ar-compat-error\">\r\n                                <p><strong>${arTranslations.desktopDetected || '\u26a0\ufe0f Desktop rilevato'}<\/strong><\/p>\r\n                                <p>${arTranslations.desktopInstructions || 'L\\'esperienza AR \u00e8 disponibile solo su dispositivi mobili Android con supporto WebXR.'}<\/p>\r\n                                <div class=\"ar-share-container\">\r\n                                    <p>${arTranslations.shareOnPhone || 'Condividi questa pagina sul tuo smartphone Android:'}<\/p>\r\n                                    <button class=\"ar-share-button ar-whatsapp-button\" onclick=\"window.stencilARApp.shareOnWhatsApp()\">\r\n                                        <span style=\"margin-right: 5px;\">\ud83d\udcf1<\/span>\r\n                                        ${arTranslations.shareWhatsApp || 'Condividi su WhatsApp'}\r\n                                    <\/button>\r\n                                    <button class=\"ar-share-button ar-copy-button\" onclick=\"window.stencilARApp.copyLink()\">\r\n                                        <span style=\"margin-right: 5px;\">\ud83d\udccb<\/span>\r\n                                        ${arTranslations.copyLink || 'Copia link'}\r\n                                    <\/button>\r\n                                <\/div>\r\n                            <\/div>\r\n                        `;\r\n                        window.stencilARApp = this;\r\n                        return;\r\n                    }\r\n                    \r\n                    \/\/ iOS non supporta WebXR AR\r\n                    if (isIOS) {\r\n                        compatDiv.innerHTML = `\r\n                            <div class=\"ar-compat-error\">\r\n                                <p><strong>${arTranslations.iosDetected || '\u26a0\ufe0f iOS rilevato'}<\/strong><\/p>\r\n                                <p>${arTranslations.iosMessage || 'Purtroppo iOS\/Safari non supporta ancora WebXR AR.'}<\/p>\r\n                                <p>${arTranslations.useAndroid || 'Usa un dispositivo Android con Chrome per l\\'esperienza AR completa.'}<\/p>\r\n                            <\/div>\r\n                        `;\r\n                        return;\r\n                    }\r\n                    \r\n                    \/\/ Check WebXR support on Android\r\n                    if (isAndroid && 'xr' in navigator) {\r\n                        try {\r\n                            const supported = await navigator.xr.isSessionSupported('immersive-ar');\r\n                            if (supported) {\r\n                                compatDiv.innerHTML = `\r\n                                    <div class=\"ar-compat-success\">\r\n                                        <span>\u2713<\/span>\r\n                                        <span>${(arTranslations.arCompatible || '\u2713 Dispositivo Android compatibile AR').replace('\u2713 ', '')}<\/span>\r\n                                    <\/div>\r\n                                `;\r\n                            } else {\r\n                                compatDiv.innerHTML = `\r\n                                    <div class=\"ar-compat-error\">\r\n                                        <p>WebXR AR non \u00e8 supportato su questo dispositivo.<\/p>\r\n                                        <p>Assicurati di usare Chrome su Android con ARCore installato.<\/p>\r\n                                    <\/div>\r\n                                `;\r\n                            }\r\n                        } catch (error) {\r\n                            console.error('Error checking AR support:', error);\r\n                            compatDiv.innerHTML = `\r\n                                <div class=\"ar-compat-error\">\r\n                                    <p>Errore durante la verifica del supporto AR.<\/p>\r\n                                    <p>Prova ad aggiornare Chrome e verifica che ARCore sia installato.<\/p>\r\n                                <\/div>\r\n                            `;\r\n                        }\r\n                    } else {\r\n                        compatDiv.innerHTML = `\r\n                            <div class=\"ar-compat-error\">\r\n                                <p>WebXR non disponibile.<\/p>\r\n                                <p>Usa Chrome su un dispositivo Android compatibile con ARCore.<\/p>\r\n                            <\/div>\r\n                        `;\r\n                    }\r\n                }\r\n                \r\n                shareOnWhatsApp() {\r\n                    let shareUrl = new URL(window.location.href);\r\n                    \r\n                    \/\/ Se c'\u00e8 un'immagine caricata, include l'ID nel link\r\n                    if (this.uploadedImageId) {\r\n                        shareUrl.searchParams.set('imageId', this.uploadedImageId);\r\n                    }\r\n                    \r\n                    const url = encodeURIComponent(shareUrl.toString());\r\n                    const text = encodeURIComponent('Guarda questa esperienza AR su Android! \ud83c\udfaf\u2728');\r\n                    const whatsappUrl = `https:\/\/wa.me\/?text=${text}%20${url}`;\r\n                    window.open(whatsappUrl, '_blank');\r\n                }\r\n                \r\n                copyLink() {\r\n                    let shareUrl = new URL(window.location.href);\r\n                    \r\n                    \/\/ Se c'\u00e8 un'immagine caricata, include l'ID nel link\r\n                    if (this.uploadedImageId) {\r\n                        shareUrl.searchParams.set('imageId', this.uploadedImageId);\r\n                    }\r\n                    \r\n                    const url = shareUrl.toString();\r\n                    \r\n                    if (navigator.clipboard && navigator.clipboard.writeText) {\r\n                        navigator.clipboard.writeText(url)\r\n                            .then(() => {\r\n                                this.showNotification('Link copiato negli appunti!', 'success');\r\n                                \r\n                                const button = event.target.closest('.ar-copy-button');\r\n                                if (button) {\r\n                                    const originalHTML = button.innerHTML;\r\n                                    button.innerHTML = `<span>\u2713 Copiato!<\/span>`;\r\n                                    button.style.background = '#10b981';\r\n                                    \r\n                                    setTimeout(() => {\r\n                                        button.innerHTML = originalHTML;\r\n                                        button.style.background = '';\r\n                                    }, 2000);\r\n                                }\r\n                            })\r\n                            .catch(err => {\r\n                                console.error('Errore copia:', err);\r\n                                this.fallbackCopyToClipboard(url);\r\n                            });\r\n                    } else {\r\n                        this.fallbackCopyToClipboard(url);\r\n                    }\r\n                }\r\n                \r\n                fallbackCopyToClipboard(text) {\r\n                    const textArea = document.createElement(\"textarea\");\r\n                    textArea.value = text;\r\n                    textArea.style.position = \"fixed\";\r\n                    textArea.style.top = \"-9999px\";\r\n                    document.body.appendChild(textArea);\r\n                    textArea.focus();\r\n                    textArea.select();\r\n                    \r\n                    try {\r\n                        document.execCommand('copy');\r\n                        this.showNotification('Link copiato negli appunti!', 'success');\r\n                    } catch (err) {\r\n                        console.error('Fallback copy failed:', err);\r\n                        this.showNotification('Impossibile copiare il link', 'error');\r\n                    }\r\n                    \r\n                    document.body.removeChild(textArea);\r\n                }\r\n                \r\n                showNotification(message, type = 'info', duration = 4000) {\r\n                    const existing = document.querySelector('.ar-notification');\r\n                    if (existing) existing.remove();\r\n                    \r\n                    const notification = document.createElement('div');\r\n                    notification.className = `ar-notification ar-notification-${type}`;\r\n                    \r\n                    const backgroundColor = {\r\n                        'error': '#ef4444',\r\n                        'success': '#10b981',\r\n                        'warning': '#f59e0b',\r\n                        'info': '#3b82f6'\r\n                    }[type] || '#3b82f6';\r\n                    \r\n                    notification.style.cssText = `\r\n                        position: fixed;\r\n                        top: 20px;\r\n                        right: 20px;\r\n                        padding: 1rem 1.5rem;\r\n                        background: ${backgroundColor};\r\n                        color: white;\r\n                        border-radius: 0.5rem;\r\n                        box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\r\n                        z-index: 10000;\r\n                        animation: slideIn 0.3s ease-out;\r\n                        max-width: 90vw;\r\n                        font-weight: 500;\r\n                    `;\r\n                    notification.textContent = message;\r\n                    \r\n                    document.body.appendChild(notification);\r\n                    \r\n                    setTimeout(() => {\r\n                        notification.style.animation = 'slideOut 0.3s ease-in';\r\n                        setTimeout(() => notification.remove(), 300);\r\n                    }, duration);\r\n                }\r\n                \r\n                setupKeyboardShortcuts() {\r\n                    document.addEventListener('keydown', (e) => {\r\n                        if (!this.isARActive) return;\r\n                        \r\n                        switch(e.key) {\r\n                            case 'Escape':\r\n                                this.exitAR();\r\n                                break;\r\n                            case '+':\r\n                            case '=':\r\n                                this.scaleImage(1.1);\r\n                                break;\r\n                            case '-':\r\n                            case '_':\r\n                                this.scaleImage(0.9);\r\n                                break;\r\n                            case 'r':\r\n                            case 'R':\r\n                                this.resetImage();\r\n                                break;\r\n                        }\r\n                    });\r\n                }\r\n                \r\n                async startAR() {\r\n                    try {\r\n                        if (this.isStartingAR) {\r\n                            console.log('AR gi\u00e0 in fase di avvio...');\r\n                            return;\r\n                        }\r\n\r\n                        if (this.xrSession || this.isARActive) {\r\n                            this.showNotification(arTranslations.arSessionActive || 'Sessione AR gi\u00e0 attiva', 'warning');\r\n                            return;\r\n                        }\r\n\r\n                        this.isStartingAR = true;\r\n\r\n                        \/\/ Show device checking state\r\n                        const startButton = document.getElementById('ar-start-button');\r\n                        startButton.classList.add('checking-device');\r\n                        startButton.innerHTML = '<span>\ud83d\udd0d Rilevazione dispositivo...<\/span>';\r\n                        this.showNotification('\ud83d\udd0d Controllo compatibilit\u00e0 dispositivo...', 'info');\r\n\r\n                        \/\/ Add delay to make device check more visible\r\n                        await new Promise(resolve => setTimeout(resolve, 1000));\r\n\r\n                        const isMobile = \/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini\/i.test(navigator.userAgent);\r\n                        const isIOS = \/iPad|iPhone|iPod\/.test(navigator.userAgent) && !window.MSStream;\r\n\r\n                        if (!isMobile) {\r\n                            startButton.classList.remove('checking-device');\r\n                            startButton.classList.add('device-error');\r\n                            startButton.innerHTML = '<span>\u26a0\ufe0f Desktop rilevato<\/span>';\r\n                            this.showNotification('\u26a0\ufe0f Dispositivo desktop rilevato! Usa smartphone Android.', 'error');\r\n                            this.highlightCompatibilitySection();\r\n\r\n                            \/\/ Reset button after error animation\r\n                            setTimeout(() => {\r\n                                startButton.classList.remove('device-error');\r\n                                startButton.innerHTML = `<span class=\"ar-button-content\"><span class=\"ar-button-icon\">\u26a1<\/span><span>${arTranslations.startAR || 'Start AR Experience'}<\/span><\/span><div class=\"ar-button-glow\"><\/div>`;\r\n                            }, 2000);\r\n\r\n                            this.isStartingAR = false;\r\n                            return;\r\n                        }\r\n                        \r\n                        if (isIOS) {\r\n                            startButton.classList.remove('checking-device');\r\n                            startButton.classList.add('device-error');\r\n                            startButton.innerHTML = '<span>\ud83c\udf4e iOS rilevato<\/span>';\r\n                            this.showNotification('\ud83c\udf4e iOS rilevato! AR non supportato. Usa dispositivo Android.', 'error');\r\n                            this.checkARCompatibility();\r\n\r\n                            setTimeout(() => {\r\n                                startButton.classList.remove('device-error');\r\n                                startButton.innerHTML = `<span class=\"ar-button-content\"><span class=\"ar-button-icon\">\u26a1<\/span><span>${arTranslations.startAR || 'Start AR Experience'}<\/span><\/span><div class=\"ar-button-glow\"><\/div>`;\r\n                            }, 3000);\r\n\r\n                            this.isStartingAR = false;\r\n                            return;\r\n                        }\r\n\r\n                        if (!('xr' in navigator)) {\r\n                            startButton.classList.remove('checking-device');\r\n                            startButton.classList.add('device-error');\r\n                            startButton.innerHTML = '<span>\u274c WebXR assente<\/span>';\r\n                            this.showNotification('\u274c WebXR non supportato. Usa Chrome su Android.', 'error');\r\n                            this.checkARCompatibility();\r\n\r\n                            setTimeout(() => {\r\n                                startButton.classList.remove('device-error');\r\n                                startButton.innerHTML = `<span class=\"ar-button-content\"><span class=\"ar-button-icon\">\u26a1<\/span><span>${arTranslations.startAR || 'Start AR Experience'}<\/span><\/span><div class=\"ar-button-glow\"><\/div>`;\r\n                            }, 3000);\r\n\r\n                            this.isStartingAR = false;\r\n                            return;\r\n                        }\r\n\r\n                        startButton.innerHTML = '<span>\ud83d\udd0e Controllo WebXR...<\/span>';\r\n                        await new Promise(resolve => setTimeout(resolve, 500));\r\n\r\n                        const isARSupported = await navigator.xr.isSessionSupported('immersive-ar');\r\n                        if (!isARSupported) {\r\n                            startButton.classList.remove('checking-device');\r\n                            startButton.classList.add('device-error');\r\n                            startButton.innerHTML = '<span>\u274c AR non supportato<\/span>';\r\n                            this.showNotification('\u274c AR non supportato su questo dispositivo', 'error');\r\n                            this.checkARCompatibility();\r\n\r\n                            setTimeout(() => {\r\n                                startButton.classList.remove('device-error');\r\n                                startButton.innerHTML = `<span class=\"ar-button-content\"><span class=\"ar-button-icon\">\u26a1<\/span><span>${arTranslations.startAR || 'Start AR Experience'}<\/span><\/span><div class=\"ar-button-glow\"><\/div>`;\r\n                            }, 3000);\r\n\r\n                            this.isStartingAR = false;\r\n                            return;\r\n                        }\r\n\r\n                        \/\/ Success state\r\n                        startButton.classList.remove('checking-device');\r\n                        startButton.innerHTML = '<span>\u2705 Avvio AR...<\/span>';\r\n                        this.showNotification('\u2705 Dispositivo compatibile! Avvio AR...', 'success');\r\n                        \r\n                        document.getElementById('ar-upload-container').style.display = 'none';\r\n                        document.getElementById('ar-viewer-container').style.display = 'block';\r\n                        \r\n                        await this.initializeAR();\r\n                        \r\n                        this.isStartingAR = false;\r\n                        \r\n                    } catch (error) {\r\n                        console.error('Error starting AR:', error);\r\n                        this.showNotification('Errore durante l\\'avvio di AR: ' + error.message, 'error');\r\n                        this.isStartingAR = false;\r\n                        this.exitAR();\r\n                    }\r\n                }\r\n                \r\n                highlightCompatibilitySection() {\r\n                    const sidebar = document.getElementById('ar-compatibility-sidebar');\r\n                    const isMobile = window.innerWidth < 1024;\r\n\r\n                    if (isMobile) {\r\n                        \/\/ On mobile, keep the modal behavior\r\n                        this.showDesktopModal();\r\n                    } else {\r\n                        \/\/ On desktop, highlight the sidebar with DRAMATIC effect\r\n                        if (sidebar) {\r\n                            sidebar.classList.add('highlight');\r\n\r\n                            \/\/ Scroll sidebar into view smoothly\r\n                            sidebar.scrollIntoView({ behavior: 'smooth', block: 'center' });\r\n\r\n\r\n                            \/\/ Update content to show clean but clear desktop warning\r\n                            const compatibility = document.getElementById('ar-compatibility');\r\n                            compatibility.innerHTML = `\r\n                                <div class=\"ar-compat-desktop-warning\" style=\"text-align: center; animation: fadeInUp 0.6s ease-out; padding: 1.5rem;\">\r\n                                    <div style=\"margin-bottom: 1.5rem;\">\r\n                                        <div class=\"ar-desktop-icon\" style=\"font-size: 48px; margin-bottom: 1rem;\">\ud83d\udda5\ufe0f<\/div>\r\n                                        <h3 style=\"color: var(--ar-text-primary); margin-bottom: 0.5rem; font-size: 1.3rem; font-weight: 700;\">\r\n                                            ${arTranslations.desktopDetected || '\u26a0\ufe0f Desktop rilevato'}\r\n                                        <\/h3>\r\n                                        <p style=\"color: var(--ar-text-secondary); margin-bottom: 0; line-height: 1.5; font-size: 1rem;\">\r\n                                            L'AR funziona solo su <strong>smartphone Android<\/strong>\r\n                                        <\/p>\r\n                                    <\/div>\r\n\r\n                                    <div style=\"background: rgba(129, 140, 248, 0.1); padding: 1.25rem; border-radius: 12px; border: 1px solid var(--ar-primary); margin-bottom: 1.5rem;\">\r\n                                        <p style=\"color: var(--ar-text-primary); margin-bottom: 0.75rem; line-height: 1.5; font-size: 0.95rem;\">\r\n                                            \ud83d\udcf1 <strong>Condividi questa pagina<\/strong> sul tuo telefono Android per utilizzare la realt\u00e0 aumentata\r\n                                        <\/p>\r\n                                    <\/div>\r\n\r\n                                    <div class=\"ar-share-buttons\" style=\"display: flex; flex-direction: column; gap: 0.75rem;\">\r\n                                        <button class=\"ar-button ar-button-light\" onclick=\"window.stencilARApp.shareOnWhatsApp()\"\r\n                                                style=\"font-size: 0.95rem; padding: 0.875rem; background: #25D366; color: white; border: none;\">\r\n                                            <span>\ud83d\udcf1 Condividi su WhatsApp<\/span>\r\n                                        <\/button>\r\n                                        <button class=\"ar-button ar-button-light\" onclick=\"window.stencilARApp.copyLink()\"\r\n                                                style=\"font-size: 0.95rem; padding: 0.875rem; background: var(--ar-primary); color: white; border: none;\">\r\n                                            <span>\ud83d\udccb Copia link<\/span>\r\n                                        <\/button>\r\n                                    <\/div>\r\n                                <\/div>\r\n                            `;\r\n\r\n                            window.stencilARApp = this;\r\n\r\n                            \/\/ Add subtle animation CSS\r\n                            const style = document.createElement('style');\r\n                            style.textContent = `\r\n                                @keyframes fadeInUp {\r\n                                    from { opacity: 0; transform: translateY(20px); }\r\n                                    to { opacity: 1; transform: translateY(0); }\r\n                                }\r\n                            `;\r\n                            document.head.appendChild(style);\r\n\r\n                            \/\/ Remove highlight after 8 seconds\r\n                            setTimeout(() => {\r\n                                sidebar.classList.remove('highlight');\r\n                            }, 8000);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                showDesktopModal() {\r\n                    const modal = document.createElement('div');\r\n                    modal.className = 'ar-desktop-modal';\r\n                    modal.innerHTML = `\r\n                        <div class=\"ar-modal-content\">\r\n                            <div class=\"ar-modal-icon\">\ud83d\udcf1<\/div><br>\r\n                            <h2>${arTranslations.desktopDetected || '\u26a0\ufe0f Desktop rilevato'}<\/h2>\r\n                            <p>${arTranslations.desktopMessage || 'L\\'esperienza AR \u00e8 disponibile solo su dispositivi Android con Chrome.'}<\/p>\r\n                            <div class=\"ar-share-container\">\r\n                                <p style=\"color: var(--ar-text-primary);\">${arTranslations.shareOnPhone || 'Condividi questa pagina sul tuo smartphone Android:'}<\/p>\r\n                                <button class=\"ar-share-button ar-whatsapp-button\" onclick=\"window.stencilARApp.shareOnWhatsApp()\">\r\n                                    <span>\ud83d\udcf1 ${arTranslations.shareWhatsApp || 'Condividi su WhatsApp'}<\/span>\r\n                                <\/button>\r\n                                <button class=\"ar-share-button ar-copy-button\" onclick=\"window.stencilARApp.copyLink()\">\r\n                                    <span>\ud83d\udccb ${arTranslations.copyLink || 'Copia link'}<\/span>\r\n                                <\/button>\r\n                            <\/div>\r\n                            <button class=\"ar-modal-close\" style=\"margin-top: 1rem;\">${arTranslations.close || 'Chiudi'}<\/button>\r\n                        <\/div>\r\n                    `;\r\n\r\n                    document.body.appendChild(modal);\r\n                    window.stencilARApp = this;\r\n\r\n                    setTimeout(() => modal.classList.add('show'), 10);\r\n\r\n                    modal.querySelector('.ar-modal-close').addEventListener('click', () => {\r\n                        modal.classList.remove('show');\r\n                        setTimeout(() => modal.remove(), 300);\r\n                    });\r\n                }\r\n                \r\n                async initializeAR() {\r\n                    try {\r\n                        document.getElementById('ar-viewer-container').style.display = 'block';\r\n                        this.isARActive = true;\r\n                        \r\n                        const container = document.getElementById('ar-canvas-container');\r\n                        \r\n                        \/\/ Create renderer con configurazione ottimizzata per esterni\r\n                        this.renderer = new THREE.WebGLRenderer({ \r\n                            antialias: true, \r\n                            alpha: true,\r\n                            preserveDrawingBuffer: true,\r\n                            premultipliedAlpha: true,\r\n                            powerPreference: \"high-performance\",\r\n                            xrCompatible: true\r\n                        });\r\n                        this.renderer.setPixelRatio(window.devicePixelRatio);\r\n                        this.renderer.setSize(window.innerWidth, window.innerHeight);\r\n                        this.renderer.xr.enabled = true;\r\n                        this.renderer.xr.cameraAutoUpdate = true;\r\n                        this.renderer.domElement.style.touchAction = 'none';\r\n                        this.renderer.shadowMap.enabled = true;\r\n                        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;\r\n                        this.renderer.outputEncoding = THREE.sRGBEncoding;\r\n                        this.renderer.toneMapping = THREE.ACESFilmicToneMapping;\r\n                        this.renderer.toneMappingExposure = 1.0;\r\n                        container.appendChild(this.renderer.domElement);\r\n                        \r\n                        \/\/ Create scene\r\n                        this.scene = new THREE.Scene();\r\n                        \r\n                        \/\/ Create camera con FOV maggiore per esterni\r\n                        this.camera = new THREE.PerspectiveCamera(\r\n                            80, \/\/ FOV aumentato per esterni\r\n                            window.innerWidth \/ window.innerHeight,\r\n                            0.01,\r\n                            100 \/\/ Far plane aumentato per distanze maggiori\r\n                        );\r\n                        \r\n                        \/\/ Add lights pi\u00f9 luminose per esterni\r\n                        const ambientLight = new THREE.AmbientLight(0xffffff, 1.2);\r\n                        this.scene.add(ambientLight);\r\n                        \r\n                        const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 2.0);\r\n                        light.position.set(0.5, 1, 0.25);\r\n                        this.scene.add(light);\r\n                        \r\n                        const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);\r\n                        directionalLight.position.set(0, 10, 5);\r\n                        directionalLight.castShadow = true;\r\n                        this.scene.add(directionalLight);\r\n                        \r\n                        \/\/ Carica texture e crea immagine\r\n                        await this.loadImageTexture();\r\n                        \r\n                        \/\/ Setup AR session\r\n                        this.setupARSession();\r\n                        \r\n                        \/\/ Setup controls\r\n                        this.setupARControls();\r\n                        \r\n                        \/\/ Create custom AR button\r\n                        this.createCustomARButton();\r\n                        \r\n                        \/\/ Start render loop\r\n                        this.renderer.setAnimationLoop((timestamp, frame) => {\r\n                            this.render(timestamp, frame);\r\n                        });\r\n                        \r\n                    } catch (error) {\r\n                        console.error('Error initializing AR:', error);\r\n                        this.showNotification(arTranslations.arGenericError + ' ' + error.message, 'error');\r\n                        this.exitAR();\r\n                    }\r\n                }\r\n                \r\n                createCustomARButton() {\r\n                    const arStartButton = document.createElement('button');\r\n                    arStartButton.id = 'custom-ar-button';\r\n                    arStartButton.className = 'ar-start-session-button';\r\n                    arStartButton.innerHTML = `\r\n                        <div class=\"ar-start-content\">\r\n                            <div class=\"ar-start-icon\">\u2b50<\/div>\r\n                            <span class=\"ar-start-text\">${arTranslations.touchToStart || 'Tocca per iniziare AR'}<\/span>\r\n                            <span class=\"ar-start-subtext\">${arTranslations.goodLighting || 'Assicurati di essere in un ambiente ben illuminato'}<\/span>\r\n                        <\/div>\r\n                    `;\r\n                    \r\n                    document.getElementById('ar-viewer-container').appendChild(arStartButton);\r\n                    \r\n                    let isStartingSession = false;\r\n                    \r\n                    arStartButton.addEventListener('click', async () => {\r\n                        if (isStartingSession) {\r\n                            console.log('AR session already starting...');\r\n                            return;\r\n                        }\r\n                        \r\n                        if (this.xrSession || (this.renderer && this.renderer.xr && this.renderer.xr.getSession())) {\r\n                            console.log('AR session already active');\r\n                            this.showNotification(arTranslations.arSessionActive || 'Sessione AR gi\u00e0 attiva', 'warning');\r\n                            return;\r\n                        }\r\n                        \r\n                        isStartingSession = true;\r\n                        \r\n                        try {\r\n                            arStartButton.disabled = true;\r\n                            arStartButton.style.opacity = '0.5';\r\n                            \r\n                            if (!this.renderer || !this.renderer.xr) {\r\n                                throw new Error('XR Renderer not initialized');\r\n                            }\r\n                            \r\n                            const activeSession = await navigator.xr.isSessionSupported('immersive-ar');\r\n                            if (!activeSession) {\r\n                                throw new Error(arTranslations.arNotSupported);\r\n                            }\r\n                            \r\n                            this.renderer.xr.setReferenceSpaceType('local');\r\n                            \r\n                            const sessionInit = {\r\n                                requiredFeatures: ['hit-test'],\r\n                                optionalFeatures: ['dom-overlay', 'local-floor', 'bounded-floor', 'camera-access', 'light-estimation']\r\n                            };\r\n                            \r\n                            const domOverlaySupported = await navigator.xr.isSessionSupported('immersive-ar');\r\n                            if (domOverlaySupported) {\r\n                                sessionInit.domOverlay = { root: document.getElementById('ar-viewer-container') };\r\n                            }\r\n                            \r\n                            console.log('Requesting XR session with init:', sessionInit);\r\n                            const session = await navigator.xr.requestSession('immersive-ar', sessionInit);\r\n                            \r\n                            this.xrSession = session;\r\n                            \r\n                            const endHandler = () => {\r\n                                console.log('XR session ended');\r\n                                this.xrSession = null;\r\n                                isStartingSession = false;\r\n                                \r\n                                if (this.renderer) {\r\n                                    this.renderer.setAnimationLoop(null);\r\n                                }\r\n                                \r\n                                if (arStartButton) {\r\n                                    arStartButton.disabled = false;\r\n                                    arStartButton.style.opacity = '1';\r\n                                    arStartButton.style.display = 'block';\r\n                                }\r\n                            };\r\n                            \r\n                            session.addEventListener('end', endHandler);\r\n                            \r\n                            try {\r\n                                await this.renderer.xr.setSession(session);\r\n                                console.log('Session set successfully');\r\n                            } catch (sessionError) {\r\n                                console.error('Error setting session:', sessionError);\r\n                                \r\n                                session.removeEventListener('end', endHandler);\r\n                                this.xrSession = null;\r\n                                \r\n                                try {\r\n                                    await session.end();\r\n                                } catch (endError) {\r\n                                    console.warn('Error ending failed session:', endError);\r\n                                }\r\n                                \r\n                                throw sessionError;\r\n                            }\r\n                            \r\n                            arStartButton.style.display = 'none';\r\n                            \r\n                            \/\/ Mostra tutorial dopo l'avvio della sessione AR\r\n                            setTimeout(() => {\r\n                                this.showTutorial();\r\n                            }, 1000);\r\n                            \r\n                            const statusText = document.getElementById('ar-status-text');\r\n                            if (statusText) {\r\n                                statusText.textContent = arTranslations.arActive;\r\n                            }\r\n                            \r\n                        } catch (error) {\r\n                            console.error('Error starting AR session:', error);\r\n                            \r\n                            let errorMessage = arTranslations.arGenericError + ' ';\r\n                            \r\n                            if (error.name === 'NotAllowedError') {\r\n                                errorMessage += arTranslations.arPermissionDenied;\r\n                            } else if (error.name === 'NotSupportedError') {\r\n                                errorMessage += arTranslations.arNotSupported;\r\n                            } else if (error.name === 'SecurityError') {\r\n                                errorMessage += arTranslations.arSecurityError;\r\n                            } else if (error.name === 'InvalidStateError') {\r\n                                errorMessage = arTranslations.arSessionActive;\r\n                            } else {\r\n                                errorMessage += error.message || arTranslations.arGenericError;\r\n                            }\r\n                            \r\n                            this.showNotification(errorMessage, 'error');\r\n                            \r\n                            arStartButton.disabled = false;\r\n                            arStartButton.style.opacity = '1';\r\n                            arStartButton.style.display = 'block';\r\n                            \r\n                            isStartingSession = false;\r\n                        }\r\n                    });\r\n                }\r\n                \r\n                async loadImageTexture() {\r\n                    return new Promise((resolve, reject) => {\r\n                        const statusText = document.getElementById('ar-status-text');\r\n                        if (statusText) {\r\n                            statusText.textContent = arTranslations.loadingImage;\r\n                        }\r\n                        \r\n                        const loader = new THREE.TextureLoader();\r\n                        \r\n                        const loadTimeout = setTimeout(() => {\r\n                            reject(new Error(arTranslations.loadingImage));\r\n                        }, 30000);\r\n                        \r\n                        loader.load(\r\n                            this.uploadedImageUrl,\r\n                            (texture) => {\r\n                                clearTimeout(loadTimeout);\r\n                                \r\n                                \/\/ Configura la texture\r\n                                texture.minFilter = THREE.LinearFilter;\r\n                                texture.magFilter = THREE.LinearFilter;\r\n                                texture.encoding = THREE.sRGBEncoding;\r\n                                texture.needsUpdate = true;\r\n                                \r\n                                \/\/ Calcola dimensioni\r\n                                const aspectRatio = texture.image.width \/ texture.image.height;\r\n                                let width = 0.5;\r\n                                let height = width \/ aspectRatio;\r\n                                \r\n                                \/\/ Limita dimensioni massime\r\n                                const maxSize = 1;\r\n                                if (width > maxSize || height > maxSize) {\r\n                                    if (width > height) {\r\n                                        width = maxSize;\r\n                                        height = width \/ aspectRatio;\r\n                                    } else {\r\n                                        height = maxSize;\r\n                                        width = height * aspectRatio;\r\n                                    }\r\n                                }\r\n                                \r\n                                \/\/ Crea materiale senza modifiche al colore\r\n                                const material = new THREE.MeshStandardMaterial({\r\n                                    map: texture,\r\n                                    side: THREE.DoubleSide,\r\n                                    transparent: true,\r\n                                    opacity: 0.98, \/\/ Trasparenza leggera come richiesto\r\n                                    depthWrite: true,\r\n                                    depthTest: true,\r\n                                    \/\/ Rimuoviamo emissive per mantenere i colori originali\r\n                                    roughness: 1, \/\/ Superficie opaca, non riflettente\r\n                                    metalness: 0  \/\/ Nessuna metallicit\u00e0\r\n                                });\r\n                                \r\n                                \/\/ Crea geometria\r\n                                const geometry = new THREE.PlaneGeometry(width, height);\r\n                                \r\n                                \/\/ Crea mesh\r\n                                this.imagePlane = new THREE.Mesh(geometry, material);\r\n                                this.imagePlane.visible = false;\r\n                                this.imagePlane.castShadow = true;\r\n                                this.imagePlane.receiveShadow = true;\r\n                                \r\n                                \/\/ Crea gruppo per l'immagine\r\n                                this.imageGroup = new THREE.Group();\r\n                                \r\n                                \/\/ Crea container interno per gestire la rotazione base\r\n                                this.imagePlaneContainer = new THREE.Group();\r\n                                this.imagePlaneContainer.add(this.imagePlane);\r\n                                this.imageGroup.add(this.imagePlaneContainer);\r\n                                \r\n                                \/\/ Aggiungi alla scena\r\n                                this.scene.add(this.imageGroup);\r\n                                \r\n                                \/\/ Crea reticolo\r\n                                this.createReticle();\r\n                                \r\n                                console.log('Image loaded successfully', {\r\n                                    width: width,\r\n                                    height: height,\r\n                                    texture: texture\r\n                                });\r\n                                \r\n                                if (statusText) {\r\n                                    statusText.textContent = arTranslations.imageReady;\r\n                                }\r\n                                \r\n                                resolve();\r\n                            },\r\n                            (xhr) => {\r\n                                if (xhr.lengthComputable) {\r\n                                    const percentComplete = (xhr.loaded \/ xhr.total) * 100;\r\n                                    if (statusText) {\r\n                                        statusText.textContent = arTranslations.loadingPercent.replace('%s', Math.round(percentComplete));\r\n                                    }\r\n                                }\r\n                            },\r\n                            (error) => {\r\n                                clearTimeout(loadTimeout);\r\n                                console.error('Error loading texture:', error);\r\n                                reject(error);\r\n                            }\r\n                        );\r\n                    });\r\n                }\r\n                \r\n                createReticle() {\r\n                    \/\/ Crea gruppo per il reticolo con matrixAutoUpdate false\r\n                    this.reticle = new THREE.Group();\r\n                    this.reticle.matrixAutoUpdate = false;\r\n                    this.reticle.visible = false;\r\n                    \r\n                    \/\/ Crea un gruppo interno per ruotare gli elementi del reticolo\r\n                    this.reticleVisuals = new THREE.Group();\r\n                    \r\n                    \/\/ Crea anello del reticolo\r\n                    const geometry = new THREE.RingGeometry(0.15, 0.2, 32);\r\n                    const material = new THREE.MeshBasicMaterial({\r\n                        color: 0x00ff00,\r\n                        opacity: 0.75,\r\n                        transparent: true,\r\n                        side: THREE.DoubleSide\r\n                    });\r\n                    const ring = new THREE.Mesh(geometry, material);\r\n                    this.reticleVisuals.add(ring);\r\n                    \r\n                    \/\/ Aggiungi punto centrale\r\n                    const centerGeometry = new THREE.CircleGeometry(0.05, 32);\r\n                    const centerMaterial = new THREE.MeshBasicMaterial({\r\n                        color: 0x00ff00,\r\n                        opacity: 0.9,\r\n                        transparent: true,\r\n                        side: THREE.DoubleSide\r\n                    });\r\n                    const centerDot = new THREE.Mesh(centerGeometry, centerMaterial);\r\n                    this.reticleVisuals.add(centerDot);\r\n                    \r\n                    \/\/ Aggiungi linee di riferimento\r\n                    const lineLength = 0.3;\r\n                    const lineMaterial = new THREE.LineBasicMaterial({\r\n                        color: 0x00ff00,\r\n                        opacity: 0.5,\r\n                        transparent: true\r\n                    });\r\n                    \r\n                    \/\/ Linea orizzontale\r\n                    const hLineGeometry = new THREE.BufferGeometry().setFromPoints([\r\n                        new THREE.Vector3(-lineLength\/2, 0, 0),\r\n                        new THREE.Vector3(lineLength\/2, 0, 0)\r\n                    ]);\r\n                    const hLine = new THREE.Line(hLineGeometry, lineMaterial);\r\n                    this.reticleVisuals.add(hLine);\r\n                    \r\n                    \/\/ Linea verticale\r\n                    const vLineGeometry = new THREE.BufferGeometry().setFromPoints([\r\n                        new THREE.Vector3(0, 0, -lineLength\/2),\r\n                        new THREE.Vector3(0, 0, lineLength\/2)\r\n                    ]);\r\n                    const vLine = new THREE.Line(vLineGeometry, lineMaterial);\r\n                    this.reticleVisuals.add(vLine);\r\n                    \r\n                    \/\/ Ruota il gruppo visuale di 90 gradi per essere parallelo alla superficie\r\n                    this.reticleVisuals.rotation.x = -Math.PI \/ 2;\r\n                    \r\n                    this.reticle.add(this.reticleVisuals);\r\n                    this.scene.add(this.reticle);\r\n                }\r\n                \r\n                setupARSession() {\r\n                    this.hitTestSource = null;\r\n                    this.hitTestSourceRequested = false;\r\n                    this.isPlaced = false;\r\n                    \r\n                    \/\/ Gestione orientamento\r\n                    window.addEventListener('orientationchange', () => {\r\n                        if (this.camera && this.renderer) {\r\n                            const width = window.innerWidth;\r\n                            const height = window.innerHeight;\r\n                            this.camera.aspect = width \/ height;\r\n                            this.camera.updateProjectionMatrix();\r\n                            this.renderer.setSize(width, height);\r\n                        }\r\n                    });\r\n                    \r\n                    \/\/ Event handlers\r\n                    this.sessionStartHandler = () => {\r\n                        document.getElementById('ar-status-text').textContent = arTranslations.arActive;\r\n                        this.showNotification(arTranslations.moveDevice, 'info', 6000);\r\n                        \r\n                        const customButton = document.getElementById('custom-ar-button');\r\n                        if (customButton) customButton.style.display = 'none';\r\n                    };\r\n                    \r\n                    this.sessionEndHandler = () => {\r\n                        console.log('AR session ended (sessionend event)');\r\n                        this.xrSession = null;\r\n                        \r\n                        if (this.isARActive) {\r\n                            setTimeout(() => {\r\n                                this.exitAR();\r\n                            }, 100);\r\n                        }\r\n                    };\r\n                    \r\n                    this.sessionInterruptHandler = () => {\r\n                        document.getElementById('ar-status-text').textContent = arTranslations.trackingLost;\r\n                        this.showNotification(arTranslations.trackingLost + ', ' + arTranslations.moveDevice.toLowerCase(), 'warning');\r\n                    };\r\n                    \r\n                    this.sessionResumeHandler = () => {\r\n                        document.getElementById('ar-status-text').textContent = arTranslations.trackingRestored.replace('!', '');\r\n                        this.showNotification(arTranslations.trackingRestored, 'success');\r\n                    };\r\n                    \r\n                    if (this.renderer && this.renderer.xr) {\r\n                        this.renderer.xr.addEventListener('sessionstart', this.sessionStartHandler);\r\n                        this.renderer.xr.addEventListener('sessionend', this.sessionEndHandler);\r\n                        this.renderer.xr.addEventListener('sessioninterrupt', this.sessionInterruptHandler);\r\n                        this.renderer.xr.addEventListener('sessionresume', this.sessionResumeHandler);\r\n                    }\r\n                }\r\n                \r\n                setupARControls() {\r\n                    \/\/ Exit button\r\n                    const exitButton = document.getElementById('ar-exit-button');\r\n                    if (exitButton) {\r\n                        let isExiting = false;\r\n                        exitButton.addEventListener('click', () => {\r\n                            if (isExiting) {\r\n                                console.log('Exit already in progress...');\r\n                                return;\r\n                            }\r\n                            isExiting = true;\r\n                            \r\n                            exitButton.disabled = true;\r\n                            exitButton.style.opacity = '0.5';\r\n                            \r\n                            this.exitAR();\r\n                            \r\n                            setTimeout(() => {\r\n                                isExiting = false;\r\n                                if (exitButton) {\r\n                                    exitButton.disabled = false;\r\n                                    exitButton.style.opacity = '1';\r\n                                }\r\n                            }, 2000);\r\n                        });\r\n                    }\r\n                    \r\n                    \/\/ Place button\r\n                    const placeButton = document.getElementById('ar-place-button');\r\n                    if (placeButton) {\r\n                        placeButton.addEventListener('click', () => {\r\n                            this.placeImage();\r\n                        });\r\n                    }\r\n                    \r\n                    \/\/ Reset button\r\n                    const resetButton = document.getElementById('ar-reset-button');\r\n                    if (resetButton) {\r\n                        resetButton.addEventListener('click', () => {\r\n                            this.resetImage();\r\n                        });\r\n                    }\r\n                    \r\n                    \/\/ Outdoor mode toggle\r\n                    const outdoorToggle = document.getElementById('ar-outdoor-toggle');\r\n                    if (outdoorToggle) {\r\n                        outdoorToggle.addEventListener('click', () => {\r\n                            this.toggleOutdoorMode();\r\n                        });\r\n                    }\r\n                    \r\n                    \/\/ Touch controls\r\n                    this.setupTouchControls();\r\n                    \r\n                    \/\/ Tap to place in AR view\r\n                    if (this.renderer && this.renderer.domElement) {\r\n                        this.renderer.domElement.addEventListener('click', (event) => {\r\n                            if (!this.isPlaced && this.reticle && this.reticle.visible) {\r\n                                this.placeImage();\r\n                            }\r\n                        });\r\n                        \r\n                        this.renderer.domElement.addEventListener('touchstart', (event) => {\r\n                            if (event.touches.length === 1 && !this.isPlaced && this.reticle && this.reticle.visible) {\r\n                                event.preventDefault();\r\n                                this.placeImage();\r\n                            }\r\n                        }, { passive: false });\r\n                    }\r\n                }\r\n                \r\n                toggleOutdoorMode() {\r\n                    this.outdoorMode = !this.outdoorMode;\r\n                    const outdoorToggle = document.getElementById('ar-outdoor-toggle');\r\n                    \r\n                    if (this.outdoorMode) {\r\n                        \/\/ Modalit\u00e0 esterni attivata\r\n                        outdoorToggle.classList.add('ar-outdoor-active');\r\n                        outdoorToggle.innerHTML = `\r\n                            <span style=\"font-size: 24px;\">\ud83c\udfe0<\/span>\r\n                            <span style=\"font-size: 16px; margin-left: 8px;\">${arTranslations.indoor}<\/span>\r\n                        `;\r\n                        \r\n                        \/\/ Aumenta la scala base per esterni\r\n                        this.defaultScale = 3;\r\n                        if (this.imagePlane && this.imagePlane.visible) {\r\n                            this.currentScale = this.currentScale * 3;\r\n                            this.imageGroup.scale.set(this.currentScale, this.currentScale, this.currentScale);\r\n                        }\r\n                        \r\n                        \/\/ Aumenta dimensione reticolo\r\n                        if (this.reticleVisuals) {\r\n                            this.reticleVisuals.scale.set(3, 3, 3);\r\n                        }\r\n                        \r\n                        this.showNotification(arTranslations.outdoorActivated, 'info');\r\n                    } else {\r\n                        \/\/ Modalit\u00e0 interni\r\n                        outdoorToggle.classList.remove('ar-outdoor-active');\r\n                        outdoorToggle.innerHTML = `\r\n                            <span style=\"font-size: 24px;\">\ud83c\udfe2<\/span>\r\n                            <span style=\"font-size: 16px; margin-left: 8px;\">${arTranslations.outdoor || 'Outdoor'}<\/span>\r\n                        `;\r\n                        \r\n                        \/\/ Ripristina scala normale\r\n                        this.defaultScale = 1;\r\n                        if (this.imagePlane && this.imagePlane.visible) {\r\n                            this.currentScale = this.currentScale \/ 3;\r\n                            this.imageGroup.scale.set(this.currentScale, this.currentScale, this.currentScale);\r\n                        }\r\n                        \r\n                        \/\/ Dimensione reticolo normale\r\n                        if (this.reticleVisuals) {\r\n                            this.reticleVisuals.scale.set(1, 1, 1);\r\n                        }\r\n                        \r\n                        this.showNotification(arTranslations.indoorActivated, 'info');\r\n                    }\r\n                }\r\n                \r\n                setupTouchControls() {\r\n                    let initialDistance = null;\r\n                    let initialAngle = null;\r\n                    let initialScale = 1;\r\n                    let initialRotation = 0;\r\n                    \r\n                    const handleTouchStart = (e) => {\r\n                        if (!this.imagePlane || !this.imagePlane.visible) return;\r\n                        if (e.touches.length === 2) {\r\n                            e.preventDefault();\r\n                            initialDistance = this.getTouchesDistance(e);\r\n                            initialAngle = this.getTouchesAngle(e);\r\n                            initialScale = this.currentScale;\r\n                            initialRotation = this.placedRotation;\r\n                        }\r\n                    };\r\n                    \r\n                    const handleTouchMove = (e) => {\r\n                        if (!this.imagePlane || !this.imagePlane.visible) return;\r\n                        if (e.touches.length === 2 && initialDistance !== null) {\r\n                            e.preventDefault();\r\n                            \r\n                            \/\/ Pinch to zoom\r\n                            const currentDistance = this.getTouchesDistance(e);\r\n                            const scaleFactor = currentDistance \/ initialDistance;\r\n                            this.currentScale = Math.max(0.1, Math.min(3, initialScale * scaleFactor));\r\n                            this.imageGroup.scale.set(this.currentScale, this.currentScale, this.currentScale);\r\n                            \r\n                            \/\/ Rotate with two fingers - INVERTED\r\n                            const currentAngle = this.getTouchesAngle(e);\r\n                            const angleDelta = currentAngle - initialAngle;\r\n                            \/\/ Inverti la direzione della rotazione\r\n                            this.placedRotation = initialRotation - angleDelta;\r\n                            \r\n                            \/\/ Applica la rotazione in base all'orientamento della superficie\r\n                            this.applyRotationOnSurface();\r\n                        }\r\n                    };\r\n                    \r\n                    const handleTouchEnd = (e) => {\r\n                        if (e.touches.length < 2) {\r\n                            initialDistance = null;\r\n                            initialAngle = null;\r\n                        }\r\n                    };\r\n                    \r\n                    if (this.renderer && this.renderer.domElement) {\r\n                        this.renderer.domElement.addEventListener('touchstart', handleTouchStart, { passive: false });\r\n                        this.renderer.domElement.addEventListener('touchmove', handleTouchMove, { passive: false });\r\n                        this.renderer.domElement.addEventListener('touchend', handleTouchEnd, { passive: false });\r\n                    }\r\n                }\r\n                \r\n                getTouchesDistance(event) {\r\n                    const dx = event.touches[0].clientX - event.touches[1].clientX;\r\n                    const dy = event.touches[0].clientY - event.touches[1].clientY;\r\n                    return Math.sqrt(dx * dx + dy * dy);\r\n                }\r\n                \r\n                getTouchesAngle(event) {\r\n                    const x1 = event.touches[0].clientX;\r\n                    const y1 = event.touches[0].clientY;\r\n                    const x2 = event.touches[1].clientX;\r\n                    const y2 = event.touches[1].clientY;\r\n                    return Math.atan2(y2 - y1, x2 - x1);\r\n                }\r\n                \r\n                detectSurfaceOrientation(hitPose) {\r\n                    \/\/ Estrai la matrice dalla pose\r\n                    const matrix = new THREE.Matrix4();\r\n                    matrix.fromArray(hitPose.transform.matrix);\r\n                    \r\n                    \/\/ Estrai i vettori base dalla matrice\r\n                    const xAxis = new THREE.Vector3();\r\n                    const yAxis = new THREE.Vector3();\r\n                    const zAxis = new THREE.Vector3();\r\n                    matrix.extractBasis(xAxis, yAxis, zAxis);\r\n                    \r\n                    \/\/ La normale della superficie \u00e8 l'asse Y della matrice di trasformazione\r\n                    const currentNormal = yAxis.normalize();\r\n                    \r\n                    \/\/ Aggiungi alla storia dei hit test per stabilizzazione\r\n                    this.hitTestHistory.push({\r\n                        normal: currentNormal.clone(),\r\n                        timestamp: Date.now(),\r\n                        pose: hitPose\r\n                    });\r\n                    \r\n                    \/\/ Mantieni solo gli ultimi N campioni\r\n                    if (this.hitTestHistory.length > this.hitTestHistorySize) {\r\n                        this.hitTestHistory.shift();\r\n                    }\r\n                    \r\n                    \/\/ Calcola la normale media per maggiore stabilit\u00e0\r\n                    const averageNormal = new THREE.Vector3(0, 0, 0);\r\n                    for (const hit of this.hitTestHistory) {\r\n                        averageNormal.add(hit.normal);\r\n                    }\r\n                    averageNormal.divideScalar(this.hitTestHistory.length);\r\n                    averageNormal.normalize();\r\n                    \r\n                    this.surfaceNormal = averageNormal;\r\n                    \r\n                    \/\/ Calcola l'angolo con l'asse Y mondiale (verticale)\r\n                    const worldUp = new THREE.Vector3(0, 1, 0);\r\n                    const dotProduct = this.surfaceNormal.dot(worldUp);\r\n                    \r\n                    \/\/ Calcola l'angolo in gradi per debug e visualizzazione\r\n                    this.surfaceAngle = Math.acos(Math.abs(dotProduct)) * (180 \/ Math.PI);\r\n                    \r\n                    \/\/ Calcola la confidence basata sulla consistenza dei campioni\r\n                    let consistency = 0;\r\n                    if (this.hitTestHistory.length > 1) {\r\n                        for (let i = 1; i < this.hitTestHistory.length; i++) {\r\n                            const similarity = this.hitTestHistory[i].normal.dot(this.hitTestHistory[i-1].normal);\r\n                            consistency += similarity;\r\n                        }\r\n                        consistency \/= (this.hitTestHistory.length - 1);\r\n                        this.surfaceConfidence = Math.max(0, Math.min(1, consistency));\r\n                    }\r\n                    \r\n                    \/\/ Determina orientamento con threshold migliorato\r\n                    \/\/ Usa abs(dotProduct) per gestire normali che puntano in entrambe le direzioni\r\n                    const absDotProduct = Math.abs(dotProduct);\r\n                    \r\n                    if (absDotProduct > 0.85) {\r\n                        \/\/ Superficie decisamente orizzontale (pavimento\/soffitto)\r\n                        this.surfaceOrientation = 'horizontal';\r\n                        return 'horizontal';\r\n                    } else if (absDotProduct < this.verticalSurfaceThreshold) {\r\n                        \/\/ Superficie decisamente verticale (muro)\r\n                        this.surfaceOrientation = 'vertical';\r\n                        return 'vertical';\r\n                    } else {\r\n                        \/\/ Superficie inclinata - determina in base alla predominanza\r\n                        if (absDotProduct < 0.5) {\r\n                            this.surfaceOrientation = 'vertical';\r\n                            return 'vertical';\r\n                        } else {\r\n                            this.surfaceOrientation = 'horizontal';\r\n                            return 'horizontal';\r\n                        }\r\n                    }\r\n                }\r\n                \r\n                updatePlaceButton(surfaceDetected) {\r\n                    const placeButton = document.getElementById('ar-place-button');\r\n                    const bottomControls = document.getElementById('ar-bottom-controls');\r\n                    const statusText = document.getElementById('ar-status-text');\r\n                    const surfaceIndicator = document.getElementById('ar-surface-indicator');\r\n                    const surfaceType = document.getElementById('ar-surface-type');\r\n                    \r\n                    if (surfaceDetected) {\r\n                        if (placeButton && !placeButton.classList.contains('ar-button-ready')) {\r\n                            placeButton.classList.add('ar-button-ready');\r\n                            if (bottomControls) bottomControls.style.display = 'flex';\r\n                            placeButton.style.display = 'block';\r\n                            \r\n                            \/\/ Aggiorna testo in base al tipo di superficie con info confidence\r\n                            let surfaceText = this.surfaceOrientation === 'horizontal' ? arTranslations.floor : arTranslations.wall;\r\n                            let confidenceText = this.surfaceConfidence > 0.8 ? ' ' + arTranslations.stable : '';\r\n                            let angleText = this.surfaceOrientation === 'vertical' ? ` ${Math.round(this.surfaceAngle)}\u00b0` : '';\r\n                            \r\n                            if (statusText) {\r\n                                statusText.textContent = `\u2713 ${surfaceText}${angleText} ${arTranslations.surfaceDetected}`;\r\n                            }\r\n                            \r\n                            \/\/ Mostra indicatore tipo superficie con icone migliorate\r\n                            if (surfaceIndicator && surfaceType) {\r\n                                const icon = this.surfaceOrientation === 'horizontal' ? '\u2b1c' : '\ud83c\udfe2';\r\n                                surfaceType.textContent = `${icon} ${surfaceText}${angleText}`;\r\n                                surfaceIndicator.className = `ar-surface-indicator ${this.surfaceOrientation}`;\r\n                                surfaceIndicator.style.display = 'block';\r\n                                \r\n                                \/\/ Aggiungi classe per confidence\r\n                                if (this.surfaceConfidence > 0.8) {\r\n                                    surfaceIndicator.classList.add('high-confidence');\r\n                                } else {\r\n                                    surfaceIndicator.classList.remove('high-confidence');\r\n                                }\r\n                            }\r\n                            \r\n                            \/\/ Vibrazione solo quando confidence \u00e8 alta\r\n                            if ('vibrate' in navigator && this.surfaceConfidence > 0.7) {\r\n                                navigator.vibrate(50);\r\n                            }\r\n                        }\r\n                    } else {\r\n                        if (placeButton) placeButton.classList.remove('ar-button-ready');\r\n                        if (!this.isPlaced && bottomControls) {\r\n                            bottomControls.style.display = 'none';\r\n                        }\r\n                        if (statusText) {\r\n                            if (this.surfaceOrientation === 'vertical') {\r\n                                statusText.textContent = arTranslations.pointToWall;\r\n                            } else {\r\n                                statusText.textContent = arTranslations.lookForSurface;\r\n                            }\r\n                        }\r\n                        if (surfaceIndicator) surfaceIndicator.style.display = 'none';\r\n                    }\r\n                }\r\n                \r\n                placeImage() {\r\n                    if (this.reticle && this.reticle.visible && !this.isPlaced && this.lastHitPose) {\r\n                        \/\/ Verifica confidence minima per posizionamento\r\n                        if (this.surfaceConfidence < this.minConfidenceThreshold && this.hitTestHistory.length < 5) {\r\n                            this.showNotification(arTranslations.continueMoving, 'warning');\r\n                            return;\r\n                        }\r\n                        \r\n                        \/\/ Copia ESATTAMENTE la trasformazione del reticolo\r\n                        this.imageGroup.matrix.copy(this.reticle.matrix);\r\n                        this.imageGroup.matrix.decompose(\r\n                            this.imageGroup.position,\r\n                            this.imageGroup.quaternion,\r\n                            this.imageGroup.scale\r\n                        );\r\n                        \r\n                        \/\/ Reset delle trasformazioni\r\n                        this.imagePlaneContainer.position.set(0, 0, 0);\r\n                        this.imagePlaneContainer.rotation.set(0, 0, 0);\r\n                        this.imagePlaneContainer.scale.set(1, 1, 1);\r\n                        this.imagePlaneContainer.quaternion.set(0, 0, 0, 1);\r\n                        this.imagePlaneContainer.matrixAutoUpdate = true;\r\n                        \r\n                        \/\/ APPROCCIO UNIFICATO: usa sempre la stessa logica\r\n                        \/\/ Il reticolo ha Y che punta fuori dalla superficie (normale)\r\n                        \/\/ La PlaneGeometry ha Z che punta fuori dal piano\r\n                        \/\/ Quindi dobbiamo sempre allineare Z dell'immagine con Y del reticolo\r\n                        \r\n                        \/\/ Questo si ottiene ruotando di -90\u00b0 attorno all'asse X\r\n                        \/\/ sia per pavimenti che per muri!\r\n                        this.imagePlaneContainer.rotation.x = -Math.PI \/ 2;\r\n                        \r\n                        if (this.surfaceOrientation === 'vertical') {\r\n                            \/\/ Per i muri, l'immagine risulta ruotata di 90\u00b0 in senso antiorario\r\n                            \/\/ Correggiamo ruotando di 90\u00b0 in senso orario attorno a Z\r\n                            this.imagePlane.rotation.z = -Math.PI \/ 2;\r\n                            \r\n                            \/\/ Offset dal muro\r\n                            const offset = this.surfaceNormal.clone().multiplyScalar(0.005);\r\n                            this.imageGroup.position.add(offset);\r\n                        } else {\r\n                            \/\/ Per il pavimento l'orientamento \u00e8 gi\u00e0 corretto\r\n                            this.imagePlane.rotation.z = 0;\r\n                        }\r\n                        \r\n                        \/\/ Assicurati che l'immagine sia visibile\r\n                        this.imagePlane.visible = true;\r\n                        \r\n                        \/\/ Applica la scala base (maggiore per modalit\u00e0 esterni)\r\n                        const baseScale = this.outdoorMode ? 3 : 1;\r\n                        \/\/ Scala aggiuntiva per superfici verticali (solitamente i muri sono pi\u00f9 grandi)\r\n                        const verticalScaleMultiplier = this.surfaceOrientation === 'vertical' ? 1.5 : 1;\r\n                        this.currentScale = baseScale * verticalScaleMultiplier;\r\n                        this.imageGroup.scale.set(this.currentScale, this.currentScale, this.currentScale);\r\n                        \r\n                        this.isPlaced = true;\r\n                        this.reticle.visible = false;\r\n                        this.placedRotation = 0;\r\n                        \r\n                        console.log('Image placed', {\r\n                            position: this.imageGroup.position,\r\n                            quaternion: this.imageGroup.quaternion,\r\n                            surfaceOrientation: this.surfaceOrientation,\r\n                            surfaceAngle: this.surfaceAngle,\r\n                            surfaceConfidence: this.surfaceConfidence,\r\n                            outdoorMode: this.outdoorMode,\r\n                            scale: this.currentScale\r\n                        });\r\n                        \r\n                        const statusText = document.getElementById('ar-status-text');\r\n                        if (statusText) {\r\n                            const surfaceType = this.surfaceOrientation === 'vertical' ? arTranslations.onWall : arTranslations.onFloor;\r\n                            const modeText = this.outdoorMode ? ' ' + arTranslations.outdoorMode : ' ' + arTranslations.indoorMode;\r\n                            statusText.textContent = `${arTranslations.imagePlaced} ${surfaceType}${modeText}`;\r\n                        }\r\n                        \r\n                        const bottomControls = document.getElementById('ar-bottom-controls');\r\n                        const placeButton = document.getElementById('ar-place-button');\r\n                        \r\n                        if (bottomControls) bottomControls.style.display = 'flex';\r\n                        if (placeButton) placeButton.style.display = 'none';\r\n                        \r\n                        \/\/ Nascondi indicatore superficie\r\n                        const indicator = document.getElementById('ar-surface-indicator');\r\n                        if (indicator) indicator.style.display = 'none';\r\n                        \r\n                        \/\/ Messaggio specifico per tipo di superficie\r\n                        const interactionHint = this.surfaceOrientation === 'vertical' \r\n                            ? arTranslations.pinchInstruction\r\n                            : arTranslations.pinchInstructionFloor;\r\n                        this.showNotification(interactionHint, 'info', 5000);\r\n                        \r\n                        \/\/ Hide tutorial\r\n                        const tutorial = document.getElementById('ar-tutorial-overlay');\r\n                        if (tutorial) tutorial.style.display = 'none';\r\n                    }\r\n                }\r\n                \r\n                applyRotationOnSurface() {\r\n                    if (!this.imagePlane || !this.imagePlane.visible) return;\r\n                    \r\n                    if (this.surfaceOrientation === 'vertical') {\r\n                        \/\/ Per superfici verticali, mantieni la rotazione base di -90\u00b0 \r\n                        \/\/ e aggiungi la rotazione dell'utente\r\n                        this.imagePlane.rotation.z = -Math.PI \/ 2 + this.placedRotation;\r\n                    } else {\r\n                        \/\/ Per superfici orizzontali, rotazione standard attorno all'asse Z\r\n                        this.imagePlane.rotation.z = this.placedRotation;\r\n                    }\r\n                }\r\n                \r\n                scaleImage(factor) {\r\n                    if (!this.imagePlane || !this.imagePlane.visible) return;\r\n                    \r\n                    this.currentScale = Math.max(0.1, Math.min(3, this.currentScale * factor));\r\n                    this.imageGroup.scale.set(this.currentScale, this.currentScale, this.currentScale);\r\n                }\r\n                \r\n                resetImage() {\r\n                    if (!this.imagePlane) return;\r\n                    \r\n                    this.isPlaced = false;\r\n                    this.imagePlane.visible = false;\r\n                    this.currentScale = 1;\r\n                    this.imageGroup.scale.set(1, 1, 1);\r\n                    this.imageGroup.rotation.set(0, 0, 0);\r\n                    \r\n                    \/\/ Resetta le rotazioni del container e dell'immagine\r\n                    if (this.imagePlaneContainer) {\r\n                        this.imagePlaneContainer.rotation.set(0, 0, 0);\r\n                    }\r\n                    this.imagePlane.rotation.set(0, 0, 0);\r\n                    this.imagePlane.quaternion.set(0, 0, 0, 1);\r\n                    \r\n                    this.surfaceOrientation = 'unknown';\r\n                    this.surfaceNormal.set(0, 1, 0);\r\n                    this.lastHitPose = null;\r\n                    this.placedRotation = 0;\r\n                    \r\n                    \/\/ Resetta anche la scala del reticolo visuale basandosi sulla modalit\u00e0\r\n                    if (this.reticleVisuals) {\r\n                        const reticleScale = this.outdoorMode ? 3 : 1;\r\n                        this.reticleVisuals.scale.set(reticleScale, reticleScale, reticleScale);\r\n                    }\r\n                    \r\n                    const statusText = document.getElementById('ar-status-text');\r\n                    if (statusText) {\r\n                        statusText.textContent = arTranslations.lookForSurface.replace('Move device to find ', 'Find a ');\r\n                    }\r\n                    \r\n                    const bottomControls = document.getElementById('ar-bottom-controls');\r\n                    const placeButton = document.getElementById('ar-place-button');\r\n                    \r\n                    if (bottomControls) bottomControls.style.display = 'none';\r\n                    if (placeButton) placeButton.style.display = 'block';\r\n                    \r\n                    \/\/ Nascondi indicatore superficie\r\n                    const indicator = document.getElementById('ar-surface-indicator');\r\n                    if (indicator) indicator.style.display = 'none';\r\n                    \r\n                    this.showNotification(arTranslations.repositionImage, 'info');\r\n                }\r\n                \r\n                \r\n                async addLogoToCanvas(ctx, width, height) {\r\n                    return new Promise((resolve) => {\r\n                        const logo = new Image();\r\n                        logo.onload = () => {\r\n                            \/\/ Calcola dimensioni e posizione del logo\r\n                            const logoSize = Math.min(width, height) * 0.1;\r\n                            const padding = logoSize * 0.3;\r\n                            const logoX = padding;\r\n                            const logoY = height - logoSize - padding;\r\n                            \r\n                            \/\/ Aggiungi ombra al logo per visibilit\u00e0\r\n                            ctx.save();\r\n                            ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';\r\n                            ctx.shadowBlur = 10;\r\n                            ctx.shadowOffsetX = 2;\r\n                            ctx.shadowOffsetY = 2;\r\n                            \r\n                            \/\/ Disegna il logo\r\n                            ctx.drawImage(logo, logoX, logoY, logoSize, logoSize);\r\n                            ctx.restore();\r\n                            \r\n                            resolve();\r\n                        };\r\n                        logo.onerror = () => {\r\n                            console.warn('Unable to load logo');\r\n                            resolve();\r\n                        };\r\n                        logo.src = this.logoUrl;\r\n                    });\r\n                }\r\n                \r\n                render(timestamp, frame) {\r\n                    if (!this.renderer || !this.scene || !this.camera) {\r\n                        console.warn('AR components not available');\r\n                        return;\r\n                    }\r\n                    \r\n                    if (frame) {\r\n                        try {\r\n                            const session = this.renderer.xr.getSession();\r\n                            if (!session) return;\r\n                            \r\n                            const referenceSpace = this.renderer.xr.getReferenceSpace();\r\n                            if (!referenceSpace) return;\r\n                            \r\n                            \/\/ Request hit test source una sola volta\r\n                            if (!this.hitTestSourceRequested && !this.hitTestSource && session) {\r\n                                this.hitTestSourceRequested = true;\r\n                                \r\n                                session.requestReferenceSpace('viewer').then((viewerSpace) => {\r\n                                    this.viewerSpace = viewerSpace;\r\n                                    \r\n                                    session.requestHitTestSource({ space: viewerSpace })\r\n                                        .then((source) => {\r\n                                            this.hitTestSource = source;\r\n                                            console.log('Hit test source created successfully');\r\n                                        })\r\n                                        .catch((error) => {\r\n                                            console.error('Error creating hit test source:', error);\r\n                                            this.showNotification(arTranslations.hitTestError, 'warning');\r\n                                        });\r\n                                });\r\n                            }\r\n                            \r\n                            \/\/ Esegui hit test\r\n                            if (this.hitTestSource && !this.isPlaced) {\r\n                                const hitTestResults = frame.getHitTestResults(this.hitTestSource);\r\n                                \r\n                                if (hitTestResults.length > 0) {\r\n                                    \/\/ Filtra e valuta i risultati hit test\r\n                                    let bestHit = null;\r\n                                    let bestScore = -1;\r\n                                    \r\n                                    for (const hit of hitTestResults) {\r\n                                        const pose = hit.getPose(referenceSpace);\r\n                                        if (!pose) continue;\r\n                                        \r\n                                        \/\/ Calcola uno score basato su vari fattori\r\n                                        const matrix = new THREE.Matrix4().fromArray(pose.transform.matrix);\r\n                                        const position = new THREE.Vector3();\r\n                                        position.setFromMatrixPosition(matrix);\r\n                                        \r\n                                        \/\/ Distanza dalla camera (preferisci hit pi\u00f9 vicini)\r\n                                        const distance = position.length();\r\n                                        const distanceScore = 1 \/ (1 + distance * 0.5);\r\n                                        \r\n                                        \/\/ Calcola normale per valutare l'orientamento\r\n                                        const yAxis = new THREE.Vector3();\r\n                                        matrix.extractBasis(new THREE.Vector3(), yAxis, new THREE.Vector3());\r\n                                        const normal = yAxis.normalize();\r\n                                        \r\n                                        \/\/ Score basato sull'orientamento desiderato\r\n                                        let orientationScore = 1;\r\n                                        const dotUp = Math.abs(normal.dot(new THREE.Vector3(0, 1, 0)));\r\n                                        \r\n                                        \/\/ Se stiamo cercando superfici verticali, premiamo quelle con dot product basso\r\n                                        if (this.surfaceOrientation === 'vertical' && this.lastValidHit) {\r\n                                            orientationScore = 1 - dotUp;\r\n                                        }\r\n                                        \r\n                                        const totalScore = distanceScore * orientationScore;\r\n                                        \r\n                                        if (totalScore > bestScore) {\r\n                                            bestScore = totalScore;\r\n                                            bestHit = { hit, pose };\r\n                                        }\r\n                                    }\r\n                                    \r\n                                    if (bestHit && bestHit.pose && this.reticle) {\r\n                                        \/\/ Salva l'ultima pose per il posizionamento\r\n                                        this.lastHitPose = bestHit.pose;\r\n                                        this.lastValidHit = bestHit;\r\n                                        \r\n                                        \/\/ Rileva l'orientamento della superficie\r\n                                        this.detectSurfaceOrientation(bestHit.pose);\r\n                                        \r\n                                        \/\/ Applica direttamente la matrice al reticolo\r\n                                        this.reticle.visible = true;\r\n                                        this.reticle.matrix.fromArray(bestHit.pose.transform.matrix);\r\n                                        \r\n                                        \/\/ Animazione del reticolo con feedback visivo per tipo superficie\r\n                                        if (this.reticleVisuals) {\r\n                                            const baseScale = this.outdoorMode ? 3 : 1;\r\n                                            const pulseScale = 1 + Math.sin(timestamp * 0.003) * 0.1;\r\n                                            \r\n                                            \/\/ Colore diverso per superfici verticali\r\n                                            const reticleMaterial = this.reticleVisuals.children[0].material;\r\n                                            if (this.surfaceOrientation === 'vertical') {\r\n                                                reticleMaterial.color.setHex(0x00ffff); \/\/ Cyan for walls\r\n                                            } else {\r\n                                                reticleMaterial.color.setHex(0x00ff00); \/\/ Green for floors\r\n                                            }\r\n                                            \r\n                                            \/\/ Scala con confidence\r\n                                            const confidenceScale = 0.7 + (this.surfaceConfidence * 0.3);\r\n                                            const finalScale = baseScale * pulseScale * confidenceScale;\r\n                                            this.reticleVisuals.scale.set(finalScale, finalScale, finalScale);\r\n                                        }\r\n                                        \r\n                                        this.updatePlaceButton(true);\r\n                                    }\r\n                                } else {\r\n                                    \/\/ Nessun hit trovato\r\n                                    if (this.reticle) this.reticle.visible = false;\r\n                                    this.updatePlaceButton(false);\r\n                                    \r\n                                    \/\/ Reset della history se non ci sono hit per un po'\r\n                                    if (this.hitTestHistory.length > 0) {\r\n                                        const lastHitAge = Date.now() - this.hitTestHistory[this.hitTestHistory.length - 1].timestamp;\r\n                                        if (lastHitAge > 1000) {\r\n                                            this.hitTestHistory = [];\r\n                                            this.surfaceConfidence = 0;\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n                            \r\n                            \/\/ Animazione floating solo per immagini su superfici orizzontali\r\n                            if (this.imagePlaneContainer && this.imagePlane && this.imagePlane.visible) {\r\n                                if (this.surfaceOrientation === 'horizontal') {\r\n                                    \/\/ Floating effect per pavimenti\r\n                                    const floatOffset = Math.sin(timestamp * 0.001) * 0.005;\r\n                                    this.imagePlaneContainer.position.y = floatOffset;\r\n                                } else {\r\n                                    \/\/ Nessun floating per muri - rimane statico\r\n                                    this.imagePlaneContainer.position.set(0, 0, 0);\r\n                                }\r\n                            }\r\n                            \r\n                        } catch (error) {\r\n                            console.error('Error during AR rendering:', error);\r\n                        }\r\n                    }\r\n                    \r\n                    \/\/ Render della scena\r\n                    if (this.renderer && this.scene && this.camera) {\r\n                        try {\r\n                            this.renderer.render(this.scene, this.camera);\r\n                        } catch (renderError) {\r\n                            console.error('Error during render:', renderError);\r\n                        }\r\n                    }\r\n                }\r\n                \r\n                showTutorial() {\r\n                    const tutorialOverlay = document.getElementById('ar-tutorial-overlay');\r\n                    \r\n                    if (!tutorialOverlay) {\r\n                        console.error('Tutorial overlay not found');\r\n                        return;\r\n                    }\r\n                    \r\n                    const steps = [\r\n                        document.getElementById('ar-tutorial-step-1'),\r\n                        document.getElementById('ar-tutorial-step-2'),\r\n                        document.getElementById('ar-tutorial-step-3'),\r\n                        document.getElementById('ar-tutorial-step-4')\r\n                    ];\r\n                    \r\n                    let currentStep = 0;\r\n                    let tutorialInterval;\r\n                    \r\n                    const showStep = (index) => {\r\n                        steps.forEach((step, i) => {\r\n                            if (step) {\r\n                                step.style.display = i === index ? 'block' : 'none';\r\n                            }\r\n                        });\r\n                    };\r\n                    \r\n                    const closeTutorial = () => {\r\n                        if (tutorialInterval) {\r\n                            clearInterval(tutorialInterval);\r\n                        }\r\n                        tutorialOverlay.style.opacity = '0';\r\n                        setTimeout(() => {\r\n                            tutorialOverlay.style.display = 'none';\r\n                            if (this.outdoorMode) {\r\n                                this.showNotification(arTranslations.outdoorActivated, 'info');\r\n                            } else {\r\n                                this.showNotification(arTranslations.outdoorModeHint, 'info', 5000);\r\n                            }\r\n                        }, 300);\r\n                    };\r\n                    \r\n                    const nextStep = () => {\r\n                        currentStep++;\r\n                        if (currentStep < steps.length) {\r\n                            showStep(currentStep);\r\n                        } else {\r\n                            closeTutorial();\r\n                        }\r\n                    };\r\n                    \r\n                    \/\/ Mostra il primo step\r\n                    tutorialOverlay.style.display = 'flex';\r\n                    setTimeout(() => {\r\n                        tutorialOverlay.style.opacity = '1';\r\n                    }, 10);\r\n                    showStep(0);\r\n                    \r\n                    \/\/ Auto advance tutorial\r\n                    tutorialInterval = setInterval(() => {\r\n                        nextStep();\r\n                    }, 4000);\r\n                    \r\n                    \/\/ Skip button\r\n                    const skipButton = document.getElementById('ar-tutorial-skip');\r\n                    if (skipButton) {\r\n                        const skipTutorial = (e) => {\r\n                            if (e) {\r\n                                e.preventDefault();\r\n                                e.stopPropagation();\r\n                            }\r\n                            closeTutorial();\r\n                        };\r\n                        \r\n                        skipButton.addEventListener('click', skipTutorial);\r\n                        skipButton.addEventListener('touchstart', skipTutorial);\r\n                    }\r\n                    \r\n                    \/\/ Advance on tap\r\n                    const handleBackgroundClick = (e) => {\r\n                        if (e.target.id === 'ar-tutorial-skip' || \r\n                            e.target.closest('#ar-tutorial-skip')) {\r\n                            return;\r\n                        }\r\n                        \r\n                        if (e.target === tutorialOverlay) {\r\n                            nextStep();\r\n                        }\r\n                    };\r\n                    \r\n                    tutorialOverlay.addEventListener('click', handleBackgroundClick);\r\n                }\r\n                \r\n                exitAR() {\r\n                    console.log('Starting exitAR...');\r\n                    \r\n                    if (this.isExiting) {\r\n                        console.log('Exit already in progress...');\r\n                        return;\r\n                    }\r\n                    \r\n                    this.isExiting = true;\r\n                    this.isARActive = false;\r\n                    \r\n                    \/\/ Ferma il render loop\r\n                    if (this.renderer) {\r\n                        try {\r\n                            this.renderer.setAnimationLoop(null);\r\n                            console.log('Animation loop stopped');\r\n                        } catch (e) {\r\n                            console.warn('Error stopping animation loop:', e);\r\n                        }\r\n                    }\r\n                    \r\n                    \/\/ Termina la sessione XR\r\n                    const terminateSession = async () => {\r\n                        if (this.xrSession) {\r\n                            const session = this.xrSession;\r\n                            this.xrSession = null;\r\n                            \r\n                            try {\r\n                                await session.end();\r\n                                console.log('XR session terminated successfully');\r\n                            } catch (error) {\r\n                                console.warn('Error closing XR session:', error);\r\n                            }\r\n                        }\r\n                    };\r\n                    \r\n                    terminateSession().finally(() => {\r\n                        \/\/ Mostra notifica e ricarica la pagina\r\n                        this.showNotification(arTranslations.closingAr, 'info', 1500);\r\n                        \r\n                        setTimeout(() => {\r\n                            \/\/ Ricarica la pagina\r\n                            window.location.reload();\r\n                        }, 1000);\r\n                    });\r\n                }\r\n            }\r\n            \r\n            \/\/ Initialize app when DOM is ready\r\n            if (document.readyState === 'loading') {\r\n                document.addEventListener('DOMContentLoaded', () => {\r\n                    if (typeof THREE !== 'undefined') {\r\n                        new StencilARApp();\r\n                    } else {\r\n                        console.error('Three.js not available');\r\n                        document.getElementById('ar-compatibility').innerHTML = `\r\n                            <div class=\"ar-compat-error\">\r\n                                <p>${arTranslations.errorLoadingLibraries.split('.')[0]}.<\/p>\r\n                            <\/div>\r\n                        `;\r\n                    }\r\n                });\r\n            } else {\r\n                if (typeof THREE !== 'undefined') {\r\n                    new StencilARApp();\r\n                } else {\r\n                    console.error('Three.js non disponibile');\r\n                }\r\n            }\r\n        <\/script>\r\n        \r\n            <\/div>\n<\/div>\n<!-- \/module plain text -->        <\/div>\n                        <\/div>\n        <\/div>\n        <\/div>\n<!--\/themify_builder_content-->","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"footnotes":""},"class_list":["post-137468","page","type-page","status-publish","hentry","has-post-title","has-post-date","has-post-category","has-post-tag","has-post-comment","has-post-author",""],"_links":{"self":[{"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/pages\/137468","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/comments?post=137468"}],"version-history":[{"count":6,"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/pages\/137468\/revisions"}],"predecessor-version":[{"id":151478,"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/pages\/137468\/revisions\/151478"}],"wp:attachment":[{"href":"https:\/\/www.cuttalo.com\/en\/wp-json\/wp\/v2\/media?parent=137468"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}