<!DOCTYPE html>
<html lang="es-ES" dir="ltr">
    <head>
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet">
        <link rel="shortcut icon" href="./images/favicon.ico" />
        <link rel="apple-touch-icon" sizes="180x180" href="./images/apple-touch-icon.png">
        <link rel="icon" type="image/png" sizes="32x32" href="./images/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="./images/favicon-16x16.png">
        <link rel="manifest" href="./images/site.webmanifest">
        <title>Identificador Interactivo de Componentes del Torno CNC</title>
    </head>
    <!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-KFS6S0B3H2"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-KFS6S0B3H2');
</script>
        <style>
            :root {
                --colormax: #ffffff;
                --colormin: none;
                --colorview: none;
                --displaycancel: none;
                --displaysound: visible;
                --led_incrcont : 1;
                --led_x1: 1;
                --led_x10: 0;
                --led_x100: 0;
                --led_spindleauto: 1;
                --led_spindleplus: 0;
                --led_spindle100: 1;
                --led_spindleminus: 0;
                --led_spindlecw: 1;
                --led_spindleccw: 0;
                --led_incrcont: 1;
                --led_slowfast: 1;
                --led_coolantauto: 1;
                --led_toolindex: 0;
                --led_feedhold: 0;
                --shadowemergency: 1;
            }
            body {
                margin: 0 auto;
                background-color: #000000;
                padding: 0px;
            }
            .parent {
                display: grid;
                grid-template-columns: repeat(10, 1fr);
                grid-template-rows: repeat(10, 1fr);
                height: 100vh;
            }
            .Monitor {
                grid-column: span 9 / span 9;
                grid-row: span 10 / span 10;
                grid-row-start: 1;
                display: flex;
                flex-direction: column;
                background: #202020;
                padding: 0px;
            }
            .Canvas {
                height: 100%;
                width: auto;
                border: 0px;
                color: white;
                display: flex;
                align-content: center;
                justify-content: center;
                text-align: center;
            }
            .modal-container {
                visibility: hidden;
                position: fixed;
                z-index: 100;
                width: 100%;
                height: 100vh;
                top: 0;
                left: 0;
                background: rgba(0,0,0,0.75);
                display: flex;
                justify-content: center;
                align-items: center;
            }
            .modal {
                display: flex;
                flex-direction: row;
                justify-content: start;
                width: 30%;
                height: 40%;
                overflow: hidden;
                min-width: 60ch;
                border-radius: 10px;
                background: #ffffff;
            }
            .closemodal {
                padding-top: 20px;
                padding-bottom: 20px;  
            }
            .info{
                display: flex;
                flex-direction: column;
                justify-content: space-around;
                align-items: stretch;
                width: 90%;
                padding: 5px 30px;
            }
            .Bar{
                display: flex;
                flex-direction: column;
                left: 90%;
                background-color: #3a3a3a;
                border: none;
                width: 65px;
                text-align: center;
            }
            .text {
                display: flex;
                align-items: start;
                justify-content: center;
                color: black;
                font-weight: normal;
                font-family: Arial, Helvetica, sans-serif;
            }
            .title {
                display: grid;
                padding-top: 20px;
                padding-bottom: 20px;
                text-align: center;
                font-size: 22px;
            }
            .comments {
                padding-top: 10px;
                font-size: 18px;
            }
            a {
                font-size: 18px;
            }
            .lastline {
                display: flex;
                flex-wrap: nowrap;
                flex-direction: row;
                justify-content: space-between;
            }
            .copyright .version {
                font-size: 14px;
            }
            #Panel1 {
				position: absolute;
				z-index: 4;
				top: 5px;
				right: 10px;
				margin-right: 0px;
                margin-top: 0px;
                padding: 0px;
				width: 300px;
				height: 400px;
				background-color: rgba(51, 51, 51, 0.9);;
				border-radius: 0.5em;
				/*text-align : justify;*/
				/*align-items: center;*/
				color: white;
                font-weight: normal;
                font-family: Arial, Helvetica, sans-serif;
                display: flex;
                flex-direction: column;
                /*line-height: 1.6;*/
			}
            #Panel2 {
				position: absolute;
				z-index: 4;
				bottom: 5px;
				right: 10px;
				margin-right: 0px;
                margin-top: 0px;
				width: 300px;
				height: 500px;
				background-color: rgba(51, 51, 51, 0.9);;
				border-radius: 0.5em;
                padding-bottom: 15px;
				text-align : center;
				align-items: center;
				color: white;
                font-weight: normal;
                font-family: Arial, Helvetica, sans-serif;
			}
            h1 {
                margin-top: 10px;
                font-size: 32px;
                margin-bottom: 10px;
            }
            .titletext {
                text-align: center;
            }
            .line {
				height: 2px;
				background-color: #987;
                text-align: center;
                margin-left: 20px;
                margin-right: 20px;
            }
            .infotext {
                height: 290px;
				text-align : justify;
                margin-top: 10px;
                margin-left: 16px;
                margin-right: 16px;
				align-items: center;
                text-align: justify;
				color: white;
				font-weight: normal;
                font-family: Arial, Helvetica, sans-serif;
                line-height: 1.6;
                overflow-y: auto;
			}
            .left {
                text-align: left;
                margin-left: 0px;
                padding-left: 10px;
            }
            .right {
                text-align: right;
                margin-right: 0px;
                border: 0px;
                padding-right: 10px;
            }
            #progressBar {
                position: absolute;
                width: 200px;
                height: 24px;
                justify-content: center;
                align-self: center;
            }
            .progressBarText {
                position: absolute;
                width: 100px;
                height: 30px;
                align-self: center;
                justify-self: center;
                transform: translateY(30px);
				color: white;
                font-weight: normal;
                font-family: Arial, Helvetica, sans-serif;
            }
            .setup {
                display: flex;
                flex-direction: row;
                justify-content: space-between;
                align-content: center;
                margin-top: auto;
                padding-top: 5px;
                /*padding-top: 10px;*/
                height: 31px;
                
                /*margin-bottom: 5px;*/
            }
            .svg {
                padding-left: 12px;
                padding-right: 12px;
            }
            #PartsTable.hide1 tr > *:nth-child(1) {
                display: none;
            }
            #PartsTable.hide2 tr > *:nth-child(2) {
                display: none;
            }
            #PartsTable.visible1 tr > *:nth-child(1) {
                display: inline;
            }
            #PartsTable.visible2 tr > *:nth-child(2) {
                display: flex;
            }
        </style>
        <script type="importmap">
            {
                "imports": {
                    "three": "./js/three.module.js",
                    "three/addons/": "./js/"
                }
            }
        </script>
    <body>
        <div id="parent" class="parent">
            <div id="ModalContainer" class="modal-container">
                <div class="modal">
                    <div class="info">
                        <div class="text title">Identificador Interactivo de Componentes <br>del Torno CNC<br><b>VIWA T400</b></div>
                        <div class="text comments">Comentarios, sugerencias o solicitudes</div>
                            <a class="text a" href="mailto:fer.montemayor@gmail.com?subject=PT400" aria-label="Email" style="--color: #000000; --background-color: transparent;">
                                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <title id="email"> Email </title> 
                                    <path d="M0 3v18h24v-18h-24zm6.623 7.929l-4.623 5.712v-9.458l4.623 3.746zm-4.141-5.929h19.035l-9.517 7.713-9.518-7.713zm5.694 7.188l3.824 3.099 3.83-3.104 5.612 6.817h-18.779l5.513-6.812zm9.208-1.264l4.616-3.741v9.348l-4.616-5.607z"></path>
                                </svg>
                            </a>
                        <div class="lastline">
                            <div class="text version">versión: 1.0</div>
                            <div class="text copyright">&copy;2025 Fernando Montemayor</div>
                        </div>
                    </div>
                    <div class="Bar">
                        <div id="CloseB" class="closemodal" title="Cerrar la ventana">
                            <svg id="Close" height="24" width="24" viewBox="0 0 8.75 9.75" xml:space="preserve" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
                                <g style="cursor:pointer">
                                    <path id="rect3" style="fill:#ffffff;stroke:none;stroke-width:0.344816;stroke-linecap:square" d="m 6.2845833,2.6436667 a 0.244,0.244 0 0 0 -0.109497,0.06348 l -1.299683,1.300476 -1.300476,-1.298889 a 0.244,0.244 0 0 0 -0.34674,0 l -0.520508,0.519715 a 0.246,0.246 0 0 0 0,0.34674 l 1.300476,1.300476 -1.300476,1.299683 a 0.247,0.247 0 0 0 0,0.346741 l 0.520508,0.518921 a 0.245,0.245 0 0 0 0.34674,0.0016 l 1.300476,-1.30127 1.300476,1.30127 a 0.245,0.245 0 0 0 0.347535,0 l 0.518921,-0.520508 a 0.247,0.247 0 0 0 0,-0.346741 l -1.300477,-1.299683 1.300477,-1.300476 a 0.247,0.247 0 0 0 0,-0.347534 l -0.520508,-0.520508 a 0.244,0.244 0 0 0 -0.237244,-0.06348 z"/>
                                    <path style="fill:#5488a3" d="M7.922 0H1.828A1.83 1.83 0 0 0 0 1.828v6.094A1.83 1.83 0 0 0 1.828 9.75h6.094A1.83 1.83 0 0 0 9.75 7.922V1.828A1.83 1.83 0 0 0 7.922 0m-.879 6.523-.52.52a.245.245 0 0 1-.347 0L4.875 5.742l-1.3 1.301a.245.245 0 0 1-.347-.001l-.52-.519a.247.247 0 0 1 0-.347l1.3-1.3-1.3-1.3a.246.246 0 0 1 0-.347l.52-.52a.244.244 0 0 1 .347 0l1.3 1.299 1.3-1.3a.244.244 0 0 1 .347 0l.52.52a.247.247 0 0 1 0 .348l-1.3 1.3 1.3 1.3a.247.247 0 0 1 0 .347" id="path2"/>
                                </g>
                            </svg>
                        </div>
                    </div>
                </div>
            </div>
            <div id="Monitor" class="Monitor">
                <div id="Canvas" class="Canvas" title="Rotación con botón izquierdo sostenido&#10;Acercamiento con giro de rueda&#10;Desplazamiento con botón derecho sostenido">
                    <progress value="0" max="100" id="progressBar" class="progressBar"></progress>
                    <div id="progressBarText" class="progressBarText">Cargando...</div>
                </div>
            </div>
            <div id="Panel1">
				<h1 id="title" class="titletext">Información</h1>
                <div class="line"></div>
				<div id="infotext" class="infotext">Coloca el puntero del mouse sobre algún componente de tu interés. El componente se resalta cuando se mueve el puntero del mouse sobre el.</div>
                <div class="setup">
                    <div id="Audios" class="svg" title="Activar/Desactivar el audio">
                        <svg id="Speaker" width="24" height="24" viewBox="0 0 3.6 3.6" style="fill: #ffffff; stroke: #ffffff; stroke-width: 0.260133; stroke-linejoin: round; cursor:pointer" version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
                            <path id="SpeakerDraw" d="M 1.8671852,0.52584073 0.97471966,1.2977605 H 0.13006657 V 2.2911058 H 0.96192106 L 1.8671852,3.0741593 Z"/>
                            <g id="VolumenUp" style="display: var(--displaysound); fill: none; stroke: #ffffff; stroke-width: 0.265362; stroke-linecap: round; stroke-dasharray: none;">
                                <path d="m 2.3151869,1.2454217 a 1.0145202,1.0145202 0 0 1 0,1.1133708 M 2.6845763,0.87603227 a 1.5608002,1.5608002 0 0 1 0,1.85214963 M 3.0227497,0.53785889 a 2.018635,2.018635 0 0 1 0,2.52849641"/>
                            </g>
                            <g id="VolumenDown" style="display: var(--displaycancel); fill: #ffffff; stroke-width: 0.00644517;">
                                <path d="M 3.0738768,1.799994 3.5603514,1.3135258 c 0.049336,-0.049342 0.049336,-0.1293065 0,-0.1786294 -0.049346,-0.049336 -0.1293066,-0.049336 -0.1786292,0 L 2.8952478,1.6213653 2.4087777,1.1348964 c -0.04932,-0.049336 -0.1292994,-0.049336 -0.1786286,0 -0.04932,0.049323 -0.04932,0.1292872 0,0.1786294 L 2.7166104,1.799994 2.2301356,2.2864692 c -0.04932,0.04932 -0.04932,0.1293004 0,0.1786291 0.024669,0.024666 0.056982,0.037007 0.089308,0.037007 0.032329,0 0.064661,-0.01232 0.08931,-0.037007 L 2.8952284,1.9786225 3.3817027,2.4650983 c 0.024664,0.024666 0.056981,0.037007 0.089308,0.037007 0.03233,0 0.064659,-0.01232 0.089308,-0.037007 0.049337,-0.049337 0.049337,-0.1292994 0,-0.1786291 z"/>
                            </g>
                        </svg>
                    </div>
                    <div id="Lang" class="svg" title="Cambiar el idioma">
                        <svg id="Language" style="cursor:pointer;fill:#ffffff" width="24" height="24" viewBox="0 0 1.56 1.56" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
                            <path d="M 1.17,0.5601 H 1.0626 L 0.9366,0.89370002 A 0.87000002,0.87000002 0 0 1 0.618,0.7473 0.86280003,0.86280003 0 0 0 0.8313,0.3126 h 0.1563 a 0.06,0.06 0 0 0 0,-0.12 H 0.59010004 V 0.06 a 0.06,0.06 0 1 0 -0.12,0 V 0.1926 H 0.0723 a 0.06,0.06 0 0 0 0,0.12 H 0.2289 A 0.86189997,0.86189997 0 0 0 0.4419,0.7473 0.88529998,0.88529998 0 0 1 0.0981,0.90000004 0.06034569,0.06034569 0 0 0 0.111,1.02 0.0483,0.0483 0 0 0 0.1242,1.0185 0.97680001,0.97680001 0 0 0 0.5301,0.83099997 0.96,0.96 0 0 0 0.894,1.008 L 0.6849,1.56 H 0.84 L 0.921,1.3272 H 1.3092 L 1.3911,1.56 H 1.5477 Z M 0.711,0.3126 A 0.71280001,0.71280001 0 0 1 0.53099998,0.6684 0.7113,0.7113 0 0 1 0.351,0.3126 Z M 0.9714,1.1871 1.1163,0.77219998 1.26,1.1871 Z" style="stroke-width: 0.03"/>
                        </svg>
                    </div>
                    <div id="Fontup" class="svg" title="Aumentar el tamaño del texto">
                        <svg id="FontUp" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" size="24" height="24" width="24" style="color:#ffffff; opacity:1; cursor:pointer" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
                            <g aria-label="A" id="text2873" style="color: #ffffff; font-size: 28px; line-height: 1.25; font-family: 'Times New Roman'; -inkscape-font-specification: 'Times New Roman, Normal'; fill: #ffffff; fill-opacity: 1; stroke: none;" transform="matrix(1.2190476,0,0,1.2190476,6.1761764e-7,-2.8190472)">
                                <path d="M 12.591796,15.792969 H 5.414062 L 4.1562495,18.71875 q -0.4648438,1.080078 -0.4648438,1.613281 0,0.423828 0.3964844,0.751953 0.4101563,0.314453 1.75,0.410157 V 22 H -5.0663948e-7 V 21.494141 Q 1.1621089,21.289062 1.5039057,20.960937 2.2011714,20.304687 3.0488276,18.294922 L 9.570312,3.0371094 h 0.478516 l 6.453125,15.4218746 q 0.779296,1.859375 1.408203,2.419922 0.642578,0.546875 1.777343,0.615235 V 22 h -7.314453 v -0.505859 q 1.107422,-0.05469 1.490235,-0.369141 0.396484,-0.314453 0.396484,-0.765625 0,-0.601563 -0.546875,-1.900391 z M 12.208984,14.78125 9.0644526,7.2890625 5.8378901,14.78125 Z" style="fill: #ffffff; fill-opacity: 1; stroke: none"/>
                            </g>
                            <path d="m 20.168793,9.1908259 c -0.203114,0 -0.397959,-0.080637 -0.541545,-0.2243502 C 19.483571,8.8229017 19.402893,8.6280491 19.402893,8.4249344 V 2.6153001 l -1.755451,1.755451 c -0.145008,0.1450115 -0.336993,0.224655 -0.542263,0.224655 -0.205266,0 -0.397253,-0.079642 -0.541243,-0.224655 -0.145008,-0.1439894 -0.224662,-0.3369976 -0.224662,-0.5412386 0,-0.2042407 0.07967,-0.3972486 0.224662,-0.5412382 L 19.62756,0.22465991 c 0.07071,-0.071586 0.155018,-0.12836544 0.247947,-0.16696696 0.09292,-0.03849946 0.192702,-0.0582087059 0.293286,-0.05770831547 0.09089,0 0.18075,0.01634947547 0.266537,0.04902805547 l 0.02143,0.0071481 c 0.09538,0.03860158 0.181973,0.09629963 0.254278,0.16952005 l 3.063613,3.06259346 c 0.07132,0.07088 0.128068,0.1552228 0.166666,0.2481528 C 23.980052,3.6292544 24,3.728924 24,3.8295125 c 0,0.1005888 -0.01999,0.2002584 -0.05873,0.2930857 -0.03862,0.09293 -0.09528,0.1772811 -0.166658,0.2481529 -0.145007,0.1450115 -0.336994,0.224655 -0.54226,0.224655 -0.205269,0 -0.397254,-0.079642 -0.541244,-0.224655 l -1.75641,-1.7564718 v 5.8106551 c 0,0.2031147 -0.08065,0.3979673 -0.224358,0.5415413 -0.143586,0.143692 -0.33843,0.2243502 -0.541547,0.2243502 z" style="color: #ffffff; fill: #ffffff; fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 0;"/>
                        </svg>
                    </div>
                    <div id="Fontdown" class="svg" title="Disminuir el tamaño del texto">
                        <svg id="FontDown" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" size="24" height="24" width="24" style="color:#ffffff; opacity:1; cursor:pointer" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
                            <path d="m 20.170474,0 c 0.20312,0 0.397965,0.08089579 0.541546,0.22499215 0.143686,0.14399353 0.224363,0.33939856 0.224363,0.54309908 V 6.5943992 l 1.755453,-1.7604895 c 0.145012,-0.1454272 0.336995,-0.2252991 0.542257,-0.2252991 0.205266,0 0.397251,0.079879 0.541242,0.2252991 C 23.920346,4.9783131 24,5.1718747 24,5.3767019 24,5.581529 23.92035,5.7750907 23.775335,5.9194932 l -3.06362,3.0724076 c -0.07067,0.071797 -0.15502,0.1287322 -0.247952,0.1674435 -0.09294,0.03861 -0.192697,0.05838 -0.293289,0.057878 -0.09089,0 -0.180753,-0.016402 -0.266533,-0.049177 l -0.02144,-0.00755 c -0.09538,-0.03864 -0.181978,-0.096495 -0.25428,-0.1699343 L 16.564597,5.9194696 c -0.07138,-0.071074 -0.128059,-0.1556686 -0.166662,-0.2488648 -0.0387,-0.093093 -0.05862,-0.1930497 -0.05862,-0.2939273 0,-0.1008767 0.01993,-0.2008327 0.05861,-0.2939265 0.03862,-0.093196 0.09528,-0.1777899 0.166662,-0.2488648 0.145006,-0.1454272 0.336996,-0.2252999 0.54226,-0.2252999 0.205262,0 0.397248,0.07987 0.541238,0.2252999 l 1.756476,1.7615126 V 0.76809123 c 0,-0.20370052 0.08066,-0.39910555 0.224361,-0.54309908 C 19.772508,0.08089646 19.967352,0 20.170471,0 Z" style="color: #ffffff; fill: #ffffff; fill-rule: nonzero; stroke: none; stroke-width: 0; stroke-opacity: 1; fill-opacity: 1;"/>
                            <g aria-label="A" id="text14689" style="color: #ffffff; font-size: 21.3333px; line-height: 1.25; font-family: 'Times New Roman'; -inkscape-font-specification: 'Times New Roman, Normal'; fill: #000000; stroke: none; fill-opacity: 1;" transform="matrix(1.0212071,0,0,1.0241357,0,1.4690146)">
                                <path d="M 9.5937348,17.270841 H 4.1249935 l -0.9583318,2.229163 q -0.3541661,0.822915 -0.3541661,1.229165 0,0.322916 0.3020828,0.572915 0.3124995,0.239583 1.3333312,0.3125 V 22 H 0 v -0.385416 q 0.88541527,-0.15625 1.1458315,-0.406249 0.5312492,-0.5 1.1770815,-2.031247 L 7.2916551,7.5521062 H 7.6562379 L 12.572897,19.302088 q 0.593749,1.416664 1.072915,1.843747 0.489582,0.416666 1.354164,0.468749 V 22 H 9.4270684 v -0.385416 q 0.8437486,-0.04167 1.1354146,-0.28125 0.302083,-0.239583 0.302083,-0.583332 0,-0.458333 -0.416666,-1.447914 z M 9.3020686,16.500009 6.9062391,10.791684 4.4479096,16.500009 Z" style="fill: #ffffff; fill-opacity: 1"/>
                            </g>
                        </svg>
                    </div>
                    <div id="Information" class="svg" title="Ingresar a la ventana de información">
                        <svg id="Info" fill="#ffffff" width="24" height="24" viewBox="0 0 6.35 6.35" style="color:#ffffff; opacity:1; cursor:pointer" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
                            <path style="stroke-linecap:square;stroke-linejoin:round;stroke-width:1.0795;stroke-dasharray:none" d="M3.176 0A3.18 3.18 0 0 0 0 3.176a3.174 3.174 0 0 0 6.021 1.405 1.6 1.6 0 0 1-.375.138 2.91 2.91 0 0 1-2.47 1.369 2.914 2.914 0 1 1 2.467-4.46 1.6 1.6 0 0 1 .375.136A3.17 3.17 0 0 0 3.176 0"/>
                            <path d="M4.022 4.94h-.596V2.854a.3.3 0 0 0-.298-.298h-.596a.298.298 0 0 0 0 .596h.298V4.94h-.596a.298.298 0 0 0 0 .596h1.788a.298.298 0 0 0 0-.596m-.894-2.922a.596.596 0 1 0-.596-.596.596.596 0 0 0 .596.596" style="fill:#fff;stroke-width:1.65548" transform="translate(.522 .478)scale(.84794)"/>
                        </svg>
                    </div>
                </div>
			</div>
            <div id="Panel2">
                <h2></h2>
                <div id="output"></div>
            </div>
        </div>

        <script type="module">
            import * as THREE from 'three';
            import { OrbitControls } from './js/addons/controls/OrbitControls.js';
            import { RoomEnvironment } from './js/addons/environments/RoomEnvironment.js';
            import { GLTFLoader } from './js/addons/loaders/GLTFLoader.js';
            import { RGBELoader } from './js/addons/loaders/RGBELoader.js';
            import { EffectComposer } from './js/addons/postprocessing/EffectComposer.js';
			import { RenderPass } from './js/addons/postprocessing/RenderPass.js';
			import { ShaderPass } from './js/addons/postprocessing/ShaderPass.js';
			import { OutlinePass } from './js/addons/postprocessing/OutlinePass.js';
			import { OutputPass } from './js/addons/postprocessing/OutputPass.js';
			import { FXAAShader } from './js/addons/shaders/FXAAShader.js';
    
            const version = 1.0;
            const author = "Fernando Montemayor Ibarra";
            const year = 2025;
            let outputHTML = "";
            
            let PartsNames = [
                "Base",
                "Cabinet",
                "Front door",
                "Left door",
                "Right door",
                "Rear door",
                "Electrical cabinet door",
                "Electrical panel",
                "Coolant tank",
                "Lubricant pump",
                "Main switch",
                "Bed",
                "Headstock",
                "Chuck",
                "Z-axis",
                "X-axis",
                "Tool turret",
                "Flexible pipe",
                "Tailstock",
                "Lamp" ];

            let Partes = {
                "Base": "base",
                "Cabina": "cover",
                "Puerta frontal": "frontdoor",
                "Puerta izquierda": "leftdoor",
                "Puerta derecha": "rightdoor",
                "Puerta trasera": "backdoor",
                "Puerta gabinete eléctrico": "electronicdoor",
                "Tablero eléctrico": "electronics",
                "Depósito de refrigerante": "coolant",
                "Bomba lubricante": "pump",
                "Interruptor principal": "onoff",
                "Bancada": "bed",
                "Cabezal": "head",
                "Mandril": "chuck",
                "Eje Z": "zaxis",
                "Eje X": "xaxis",
                "Torreta de herramientas": "toolsturret",
                "Manguera flexible": "pipe",
                "Contrapunto": "tailstock",
                "Lámpara": "lamp"
            };
            
            let view = 1;
            let screen = 0;
            let container, renderer, scene, camera, controls;
            let light, lightOn = 1;
            let Machine = new THREE.Group();
            let Bed    = new THREE.Object3D();
            let Zaxis  = new THREE.Object3D();
            let Xaxis  = new THREE.Object3D();
            let Turret  = new THREE.Object3D();
            let Spindle = new THREE.Object3D();
            let Cover = new THREE.Object3D();
            let Switch = new THREE.Object3D();
            let Light = new THREE.Object3D();
            let Base  = new THREE.Object3D();
            let Pipe  = new THREE.Object3D();
            let Pump  = new THREE.Object3D();
            let Oil  = new THREE.Object3D();
            let Head  = new THREE.Object3D();
            let Container = new THREE.Object3D();
            let Electronics = new THREE.Object3D();
            let Tailstock = new THREE.Object3D();
            let RightDoor = new THREE.Object3D();
            let LeftDoor = new THREE.Object3D();
            let BackDoor = new THREE.Object3D();
            let ElectronicDoor = new THREE.Object3D();
            let FrontDoor = new THREE.Object3D();
            let Lamp = new THREE.Object3D();
            let composer, effectFXAA, outlinePass;
            let scale = 1000;
            let selectedObjects = [];
            const raycaster = new THREE.Raycaster();
			const mouse = new THREE.Vector2();
            let mousePosition;
            let offset = [0,0];
            let isDown = false;
            let b=0;
            let indexES, indexEN;
            let voices = window.speechSynthesis.getVoices();
            let changemsg = "";
            let msg = "";
            let lang = 1;
            let speech = 1;
            let select = 0;
            const life = "Jesus is Lord";

            const allVoices = new Promise(function (resolve, reject) {
                let voices = window.speechSynthesis.getVoices();
                if (voices.length !== 0) {
                    resolve(voices);
                } else {
                    window.speechSynthesis.addEventListener("voiceschanged", function () {
                        voices = window.speechSynthesis.getVoices();
                        resolve(voices);
                    });
                }
            });

            allVoices.then((voices) => {
            //console.log("All voices:", voices);
                //let voces="";
                if (voices.length != 0) {
                for (var i = 0; i < voices.length; i++) {
                    //voces += i+" "+voices[i].lang+' '+voices[i].name+'\n';
                    if (voices[i].name == "Microsoft Zira - English (United States)") {
                        indexEN = voices[i];
                    }
                    if (voices[i].name == "Microsoft Sabina Desktop - Spanish (Mexico)") {
                        indexES = voices[i];
                    }
                }
                }
            });

            let Messages = {
                "Intro": {
                    "title": "Information",
                    "titulo": "Información",
                    "text" : "Place the mouse pointer over some part of your interest. Part highlights when mouse pointer is moved over it.",
                    "texto": "Coloca el puntero del mouse sobre algún componente de tu interés. El componente se resalta cuando se mueve el puntero del mouse sobre el.",
                },
                "Cover" :
                {
                    "title": "Cabin",
                    "titulo": "Cabina",
                    "text" : "The cabin is the structural component that fully encloses and protects the machine, preventing direct contact between the operator and the moving parts. Its main function is to prevent potential harm to the personnel, particularly in situations where tools collide with the workpieces during machining.",
                    "texto": "La cabina es el componente estructural que envuelve y protege integralmente la máquina, evitando el contacto directo del operador con las partes móviles. Su función principal es prevenir daños al personal, en especial en situaciones de colisión entre herramientas y piezas en proceso de maquinado.",
                },
                "Guia" :
                {
                    "title": "Guides",
                    "titulo": "Guias",
                    "text" : "The guides are prismatic or flat elements, precision-ground and hardened, placed on the bed of the machine. Their critical function is to ensure the precise alignment of key components, such as the fixed headstock, tailstock, and the Z-axis, which directly affects the accuracy and overall performance of the lathe.",
                    "texto": "Las guías son elementos prismáticos o planos, rectificados y templados, ubicados sobre la bancada. Su función crítica es asegurar el alineamiento preciso de los componentes principales, como el cabezal fijo, el contrapunto y el eje Z, lo que determina directamente la precisión y el rendimiento global del torno.",
                },
                "Servomotor" :
                {
                    "title": "Servomotor",
                    "titulo": "Servomotor",
                    "text" : "The servomotor is an actuator that combines an electric motor with a feedback system to precisely control the movements of the Z-axis. This component regulates position, speed, and acceleration with high accuracy, allowing for exact control of the tool's displacement during the machining process.",
                    "texto": "El servomotor es un actuador que combina un motor eléctrico con un sistema de retroalimentación para controlar de manera precisa los movimientos del eje Z. Este componente regula la posición, velocidad y aceleración con alta precisión, permitiendo un control exacto del desplazamiento de la herramienta durante el proceso de maquinado.",
                },
                "Bed" :
                {
                    "title": "Bed",
                    "titulo": "Bancada",
                    "text" : "The bed is the base and support structure of the lathe, providing the necessary rigidity and stability for the machine's proper operation. All vital components for machining operations are mounted on it, ensuring the integrity and precision of the processes.",
                    "texto": "La bancada constituye la estructura base y de soporte del torno, proporcionando la rigidez y estabilidad necesarias para el correcto funcionamiento de la máquina. Sobre ella se montan todos los componentes vitales para las operaciones de maquinado, garantizando la integridad y precisión de los procesos.",
                },
                "Zaxis" :
                {
                    "title": "Z-axis",
                    "titulo": "Eje Z",
                    "text" : "The Z-axis is the main axis responsible for the longitudinal movement of the tool. This displacement allows the tool to penetrate and advance during the machining process of the workpiece.",
                    "texto": "El eje Z es el eje principal encargado del movimiento longitudinal de la herramienta. Este desplazamiento permite la penetración y el avance de la herramienta de corte en el proceso de maquinado de la pieza de trabajo.",
                },
                "Xaxis" :
                {
                    "title": "X-axis",
                    "titulo": "Eje X",
                    "text" : "The X-axis performs the transverse movement, perpendicular to the Z-axis. This displacement allows the proper execution of cuts and horizontal tool movements on the workpiece.",
                    "texto": " El eje X realiza el movimiento transversal, perpendicular al eje Z. Este desplazamiento permite la correcta ejecución de cortes y desplazamientos horizontales de la herramienta sobre la pieza de trabajo.",
                },
                "Turret" :
                {
                    "title": "Tool turret",
                    "titulo": "Torreta de herramientas",
                    "text" : "The tool turret is a device that allows multiple tool holders to be mounted on a single support, enabling quick and precise tool changes without stopping the machining process. It typically holds up to 4 tool holders and is essential for optimizing cycle times.",
                    "texto": "La torreta de herramientas es un dispositivo que permite montar múltiples portaherramientas en un solo soporte, facilitando el cambio rápido y preciso de herramientas sin necesidad de detener el proceso de maquinado. Usualmente puede alojar hasta 4 portaherramientas y es fundamental para optimizar tiempos de ciclo.",
                },
                "Holder" :
                {
                    "title": "Holder",
                    "titulo": "Portainserto",
                    "text" : "The tool holder is a component that holds the cutting insert, ensuring its stability and precision during machining operations. Also known as a tool clamp, its primary function is to guarantee the insert stays in its cutting position without variations.",
                    "texto": "El portainserto es un componente que sujeta el inserto de corte, asegurando su estabilidad y precisión durante las operaciones de maquinado. También se le conoce como portaherramienta, y su función principal es garantizar que el inserto mantenga su posición de corte sin variaciones.",
                },
                "Insert" :
                {
                    "title": "Insert",
                    "titulo": "Inserto",
                    "text" : "Inserts are small, replaceable cutting plates mounted on the cutting tool. Their function is to make precise and efficient cuts on the workpiece, allowing high repeatability and speed during the process.",
                    "texto": "Los insertos son plaquitas de corte pequeñas y reemplazables que se montan en la herramienta de corte. Su función es realizar cortes precisos y eficientes en la pieza de trabajo, permitiendo una alta repetibilidad y velocidad en el proceso.",
                },
                "Seat" :
                {
                    "title": "Seat",
                    "titulo": "Asiento",
                    "text" : "The seat is the plate that supports and positions the insert within the tool holder, ensuring its correct alignment and stability during cutting.",
                    "texto": "El asiento es la placa que soporta y posiciona el inserto dentro del portainsertos, asegurando su correcta alineación y estabilidad durante el corte.",
                },
                "Clamp" :
                {
                    "title": "Clamp",
                    "titulo": "Brida",
                    "text" : "The clamp is the component that holds the insert firmly against the seat in the tool holder, preventing unwanted movement during the machining process.",
                    "texto": "La brida es el componente que mantiene firmemente el inserto presionado sobre el asiento en el portainsertos, evitando desplazamientos indeseados durante el proceso de maquinado.",
                },
                "ClampScrew" :
                {
                    "title": "Clamp Screw",
                    "titulo": "Tornillo de sujeción",
                    "text" : "The clamping screw is the element that connects the clamp to the tool holder, ensuring the fixture of the assembly and maintaining precision in securing the insert during cutting operations.",
                    "texto": "El tornillo de sujeción es el elemento que une la brida con el portainsertos, asegurando la fijación del conjunto y manteniendo la precisión en la sujeción del inserto durante las operaciones de corte.",
                },
                "TorxScrew" :
                {
                    "title": "Lock pin",
                    "titulo": "Tornillo pasador",
                    "text" : "The pin screw fixes the seat to the tool holder and acts as a guide for the insert, ensuring its proper positioning and stability during machining.",
                    "texto": "El tornillo pasador fija el asiento al portainsertos y actúa como guía para el inserto, asegurando su correcta ubicación y estabilidad durante el maquinado.",
                },
                "Light" :
                {
                    "title": "Light",
                    "titulo": "Lámpara",
                    "text" : "The lamp provides additional lighting to the CNC machine’s work area, improving visibility during operations. Its function is controlled via the AUX 7 button.",
                    "texto": "La lámpara proporciona iluminación adicional en el área de trabajo de la máquina CNC, mejorando la visibilidad durante las operaciones. Su funcionamiento se controla mediante la tecla AUX 7.",
                },
                "Chuck" :
                {
                    "title": "Chuck",
                    "titulo": "Mandril",
                    "text" : "The chuck is the clamping device used to secure cylindrical workpieces to the main spindle. Its design allows for quick and secure adjustments, ensuring the stability of the workpiece during the machining process.",
                    "texto": "El mandril es el dispositivo de sujeción que se utiliza para fijar piezas cilíndricas al husillo principal. Su diseño permite un ajuste rápido y seguro, garantizando la estabilidad de la pieza durante el proceso de maquinado.",
                },
                "Jaw" :
                {
                    "title": "Jaws",
                    "titulo": "Mordazas",
                    "text" : "The jaws are clamping elements used in the chuck to secure the workpiece. Made from hardened steel, they have serrated surfaces that ensure a firm grip during cutting operations.",
                    "texto": "Las mordazas son elementos de sujeción que se emplean en el mandril para asegurar la pieza de trabajo. Fabricadas en acero endurecido, poseen una superficie dentada que asegura un agarre firme durante las operaciones de corte.",
                },
                "Workpiece" :
                {
                    "title": "Workpiece",
                    "titulo": "Pieza de trabajo",
                    "text" : "The workpiece is the material to be shaped through various machining operations, with the final result being a precise cylindrical shape that meets the required specifications.",
                    "texto": "La pieza de trabajo es el material a conformarse mediante diferentes operaciones de maquinado, cuyo resultado final es cilíndrico ajustado a las especificaciones requeridas.",
                },
                "Switch" :
                {
                    "title": "Main switch",
                    "titulo": "Interruptor principal",
                    "text" : "The main switch controls the electrical power supply to the CNC machine, allowing for safe and efficient operation of turning the machine on and off.",
                    "texto": "El interruptor principal controla el suministro eléctrico de la máquina CNC, permitiendo encender y apagar la máquina de forma segura y eficiente.",
                },
                "Base" :
                {
                    "title": "Base",
                    "titulo": "Base",
                    "text" : "The base is the fundamental structure that supports the entire machine, including the main motor, coolant tank, and bed. It provides the necessary stability for the correct operation of all components.",
                    "texto": "La base es la estructura fundamental que soporta toda la máquina, incluyendo el motor principal, el contenedor de refrigerante y la bancada. Proporciona la estabilidad necesaria para el correcto funcionamiento de todos los componentes.",
                },
                "LevelingLeg" :
                {
                    "title": "Leveling foot",
                    "titulo": "Pie nivelador",
                    "text" : "The leveling foot is a device that allows for adjusting and stabilizing the lathe on uneven or unlevel surfaces, ensuring its correct installation and operation.",
                    "texto": "El pie nivelador es un dispositivo que permite ajustar y estabilizar el torno sobre superficies irregulares o no niveladas, garantizando su correcta instalación y funcionamiento.",
                },
                "Pipe" :
                {
                    "title": "Flexible pipe",
                    "titulo": "Manguera flexible",
                    "text" : "The flexible hose is the conduit that carries the coolant from the cooling system to the cutting area. Its main function is to prevent overheating of the tool and workpiece during the machining process.",
                    "texto": "La manguera flexible es el conducto que transporta el refrigerante desde el sistema de refrigeración hacia la zona de corte. Su función principal es evitar el sobrecalentamiento de la herramienta y la pieza de trabajo durante el proceso de maquinado.",
                },
                "Pump" :
                {
                    "title": "Lubricant pump",
                    "titulo": "Bomba de lubricante",
                    "text" : "The lubricant pump is responsible for supplying oil to the moving parts of the lathe, reducing friction and wear on components, which improves the machine’s lifespan and machining accuracy.",
                    "texto": "La bomba de lubricante es responsable de suministrar aceite a las partes móviles del torno, reduciendo la fricción y el desgaste de los componentes, lo que mejora la vida útil de la máquina y la precisión del maquinado.",
                },
                "Oil" :
                {
                    "title": "Lubricating oil",
                    "titulo": "Aceite lubricante",
                    "text" : "Lubricating oil is used to reduce friction and wear on the lathe’s moving parts, minimizing heat generation during operations and protecting the elements from corrosion.",
                    "texto": "El aceite lubricante se utiliza para reducir la fricción y el desgaste de los componentes móviles del torno, minimizando el calor generado durante las operaciones y protegiendo los elementos contra la corrosión.",
                },
                "Head" :
                {
                    "title": "Headstock",
                    "titulo": "Cabezal fijo",
                    "text" : "The fixed headstock is the unit permanently mounted on the left end of the bed. It contains the spindle, which is responsible for transmitting motion to the workpiece.",
                    "texto": "El cabezal fijo es la unidad montada permanentemente en el extremo izquierdo de la bancada. Contiene el husillo, responsable de la transmisión de movimiento a la pieza de trabajo.",
                },
                "Belt" :
                {
                    "title": "Belts",
                    "titulo": "Bandas",
                    "text" : "The belts are transmission components that transfer the rotational movement from the main motor to the spindle. They are typically flat or U-shaped to ensure efficient and precise transmission.",
                    "texto": "Las bandas son componentes de transmisión que se encargan de transferir el movimiento rotativo del motor principal al husillo. Suelen ser bandas planas o en forma de V para garantizar una transmisión eficiente y precisa.",
                },
                "Encoder" :
                {
                    "title": "Encoder",
                    "titulo": "Encoder",
                    "text" : "The encoder is a measurement device that converts the rotational movement of the spindle into electrical signals. Its function is to monitor the position, speed, and acceleration of the spindle, providing precise feedback to the control system.",
                    "texto": "El encoder es un dispositivo de medición que convierte el movimiento rotatorio del husillo en señales eléctricas. Su función es monitorear la posición, velocidad y aceleración del husillo, proporcionando retroalimentación precisa al sistema de control.",
                },
                "Spindle" :
                {
                    "title": "Spindle",
                    "titulo": "Husillo",
                    "text" : "The spindle is the axis responsible for transmitting rotational movement to the chuck and workpiece. It is usually hollow to allow the passage of tools or cooling systems.",
                    "texto": "El husillo es el eje encargado de transmitir el movimiento de rotación al mandril y a la pieza de trabajo. Generalmente es hueco para permitir el paso de herramientas o sistemas de refrigeración.",
                },
                "Container" :
                {
                    "title": "Coolant Tank",
                    "titulo": "Contenedor de refrigerante",
                    "text" : "The coolant tank is the reservoir that stores the coolant fluid used to cool both the cutting tool and the workpiece, keeping the operating temperature within safe limits.",
                    "texto": "El contenedor de refrigerante es el depósito que almacena el líquido refrigerante utilizado para enfriar tanto la herramienta de corte como la pieza de trabajo, manteniendo la temperatura de operación dentro de los límites seguros.",
                },
                "CoolantPump" :
                {
                    "title": "Coolant Pump",
                    "titulo": "Bomba de refrigerante",
                    "text" : "The coolant pump is the mechanism that pushes the coolant fluid from the tank to the machine’s cutting zones, helping maintain a stable temperature and preventing overheating during machining.",
                    "texto": "La bomba de refrigerante es el mecanismo que impulsa el líquido refrigerante desde el contenedor hacia las zonas de corte de la máquina, ayudando a mantener una temperatura estable y a prevenir el sobrecalentamiento durante el maquinado.",
                },
                "Driver" :
                {
                    "title": "Driver",
                    "titulo": "Servocontroladores",
                    "text" : "Servo controllers are devices that supply power to the servomotors and manage the execution of programmed or manual movement commands. They are essential for ensuring precise control of the machine’s axes.",
                    "texto": "Los servocontroladores son dispositivos que alimentan a los servomotores y gestionan la ejecución de las órdenes de movimiento programadas o manuales. Son esenciales para garantizar el control preciso de los ejes de la máquina.",
                },
                "VFD" :
                {
                    "title": "Variable Frequency Drive",
                    "titulo": "Variador de Frecuencia",
                    "text" : "The frequency converter (VFD) adjusts the frequency of the electric current feeding the main motor, allowing the rotation speed of the spindle to be regulated to suit the specific needs of each operation.",
                    "texto": "El variador de frecuencia (VFD) ajusta la frecuencia de la corriente eléctrica que alimenta al motor principal, lo que permite regular la velocidad de rotación del husillo y adaptarla a las necesidades específicas de cada operación.",
                },
                "Raceway" :
                {
                    "title": "Wire Duct Slotted",
                    "titulo": "Canaleta ranurada",
                    "text" : "The grooved channel is used to organize and protect electrical cables in the control panel of the electrical cabinet, ensuring that the cables are well-managed and secure.",
                    "texto": "La canaleta ranurada se utiliza para organizar y proteger los cables eléctricos en el tablero de control del armario eléctrico, asegurando que los cables estén bien gestionados y seguros.",
                },
                "PLC" :
                {
                    "title": "Programmable Logic Controller",
                    "titulo": "Control Lógico Programable",
                    "text" : "The PLC is a control system that manages the auxiliary functions of the CNC lathe, such as activating lubrication, controlling the automatic tool changer, managing the coolant pump, and monitoring machine system failures.",
                    "texto": "El PLC es un sistema de control que gestiona las funciones auxiliares del torno CNC, como la activación de la lubricación, el control del cambiador automático de herramientas, la gestión de la bomba de refrigerante y el monitoreo de fallas en los sistemas de la máquina.",
                },
                "Tailstock" :
                {
                    "title": "Tailstock",
                    "titulo": "Contrapunto",
                    "text" : "The tailstock, also known as the moving headstock, is a component that slides along the bed’s guides. Its main function is to hold large workpieces, minimizing vibrations, and sometimes it holds rotating tools for specific operations.",
                    "voice": "Press this button to increase the current spindle speed by 10% in automatic spindle mode. In manual spindle mode, the spindle speed increases by 5% up to a maximum speed of 3000 rpm. The LED lights up if the spindle speed is set above 100%.",
                    "texto": "El contrapunto, también conocido como cabezal móvil, es un componente que se desplaza sobre las guías de la bancada. Su función principal es sujetar piezas de gran tamaño, minimizando las vibraciones, y en ocasiones puede albergar herramientas rotativas para operaciones específicas.",
                    "voz"  : "El contrapunto, también conocido como cabezal móvil, es un componente que se desplaza sobre las guías de la bancada. Su función principal es sujetar piezas de gran tamaño, minimizando las vibraciones, y en ocasiones puede albergar herramientas rotativas para operaciones específicas."
                },
                "RightDoor" :
                {
                    "title": "Right door",
                    "titulo": "Puerta derecha",
                    "text" : "The right door provides access to the tailstock and its associated components, facilitating maintenance and adjustment.",
                    "texto": "La puerta derecha ofrece acceso al contrapunto y a sus componentes asociados, facilitando su mantenimiento y ajuste.",
                },
                "LeftDoor" :
                {
                    "title": "Left door",
                    "titulo": "Puerta izquierda",
                    "text" : "The left door provides access to the pulleys, belts, motors, and encoder of the moving headstock, allowing for necessary maintenance and adjustments.",
                    "texto": "La puerta izquierda da acceso a las poleas, bandas, motores y encoder del cabezal móvil, permitiendo su mantenimiento y ajustes pertinentes.",
                },
                "BackDoor" :
                {
                    "title": "Rear door",
                    "titulo": "Puerta trasera",
                    "text" : "The rear door provides access to the servomotor of the X-axis, located at the back of the machine, allowing for inspection.",
                    "texto": "La puerta trasera proporciona acceso al servomotor del eje X, ubicado en la parte posterior de la máquina, permitiendo su inspección.",
                },
                "ElectronicDoor" :
                {
                    "title": "Electrical cabinet door",
                    "titulo": "Puerta del armario eléctrico",
                    "text" : "The electrical cabinet door provides access to the CNC lathe’s electrical control panel. It facilitates inspection, maintenance, and adjustment of internal electrical components such as servo controllers, frequency converters, and other control devices.",
                    "texto": "La puerta del armario eléctrico proporciona acceso al tablero de control del sistema eléctrico del torno CNC. Facilita la inspección, mantenimiento y ajuste de los componentes eléctricos internos, como los servocontroladores, variadores de frecuencia y demás dispositivos de control.",
                },
                "FrontDoor" :
                {
                    "title": "Front door",
                    "titulo": "Puerta frontal",
                    "text" : "The front door is a sliding access that allows entry to the interior of the machine. Its main function is to protect the operator from flying debris and chips during machining. Equipped with a safety window, it enables the operator to view the process while maintaining protection from potential risks.",
                    "texto": "La puerta frontal es un acceso deslizante que permite la entrada al interior de la máquina. Su función principal es proteger al operador de proyectiles y virutas expulsadas durante el maquinado. Equipada con una ventana de seguridad, permite la visualización del proceso sin comprometer la protección del operario frente a posibles riesgos.",
                },
            }

            outputHTML += "<table id='PartsTable' width='300'>";

            let tValues = Object.entries(Partes);
            tValues.forEach((item) => {
                outputHTML += "<tr>";
                outputHTML += "<td class='left' >" + item[0] + "</td>";
                outputHTML += "<td class='left' >" + item[0] + "</td>";

                outputHTML += "<td class='right'>" + "<input type='checkbox' id='"+ item[1] + "' name='" + item[1] + "' checked />" + "</td>";
                outputHTML +="</tr>";
            })
            outputHTML += "</table>";

            document.getElementById("output").innerHTML = outputHTML;

            let row = document.getElementById("PartsTable").rows;
            for (let i = 0; i < PartsNames.length; i++) {
                let col = row[i].cells;
                col[1].innerHTML = PartsNames[i];
            }
            document.getElementById("PartsTable").classList.toggle("hide2");
            
            init();
            animate();

            Speaker.addEventListener("click", ()=>{ToggleAudio()}, false);
            Language.addEventListener("click", ()=>{ToggleLang()}, false);
            FontUp.addEventListener("click", ()=>{FontSize("infotext",2)}, false);
            FontDown.addEventListener("click", ()=>{FontSize("infotext",-2)}, false);
            Info.addEventListener("click", ()=>{ModalWindow(1)}, false);
            Close.addEventListener("click", ()=>{ModalWindow(0)}, false);

            const progressBar = document.getElementById('progressBar');

            let manager = new THREE.LoadingManager(allLoadersDone);
            let loader = new GLTFLoader(manager).setPath( './models/' );

            manager.onStart = function (item, loaded, total) {
                console.log('Loading started');
            };

            manager.onProgress = function (item, loaded, total) {
                progressBar.value = (loaded / total * 100);         
                //console.log(item, loaded, total);
                //console.log('Loaded:', Math.round(loaded / total * 100, 2) + '%')
                if(progressBar.value == 100) {
                    document.getElementById("progressBar").remove();
                    document.getElementById("progressBarText").remove()}
            };

            manager.onError = function (url) {
                console.log('Error loading');
            };

            function init() {
                container = document.getElementById("Canvas");
                renderer = new THREE.WebGLRenderer({antialias:true});
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.toneMapping = THREE.ReinhardToneMapping; //ACESFilmicToneMapping;
                renderer.shadowMap.enabled = true;
                renderer.shadowMapEnabled = true;
                renderer.shadowMapSoft = true;
                container.appendChild( renderer.domElement );
                renderer.setSize(container.clientWidth, container.clientHeight);
                const environment = new RoomEnvironment();
                const pmremGenerator = new THREE.PMREMGenerator (renderer);
                scene = new THREE.Scene();
                scene.background = new THREE.Color( 0x202020) ; //0x7E7E7E );
                
                camera = new THREE.PerspectiveCamera( 40, container.clientWidth / container.clientHeight, 1, 10000 );
                camera.position.set( 0, 0, 3800 );
                
                controls = new OrbitControls( camera, renderer.domElement );
                controls.minDistance = 1; //
				controls.maxDistance = 4000; //
                controls.maxPolarAngle = Math.PI / 2; //
                Lights();

                window.addEventListener( 'resize', onWindowResize, false );
                renderer.domElement.style.touchAction = 'none';
				renderer.domElement.addEventListener( 'pointermove', onPointerMove );
                renderer.domElement.addEventListener( 'pointerdown', onPointerDown );
                //renderer.domElement.addEventListener( 'pointerup', onPointerUp );

                
                new RGBELoader()
                    .setPath( './textures/' ) //'./textures/equirectangular/' )
                    .load( 'neutral.hdr', function ( texture ) { //'royal_esplanade_1k.hdr', function ( texture ) {
                        texture.mapping = THREE.EquirectangularReflectionMapping;
                        scene.environment = texture;
                        LoadModels();
                    });
                
                // postprocessing
				composer = new EffectComposer( renderer );
				const renderPass = new RenderPass( scene, camera );
				composer.addPass( renderPass );
				outlinePass = new OutlinePass( new THREE.Vector2( container.clientWidth, container.clientHeight ), scene, camera );
                outlinePass.edgeStrength = 10;
                outlinePass.pulsePeriod = 1.5;
                outlinePass.edgeThickness = 5;
                outlinePass.edgeGlow = 0.5;
                outlinePass.visibleEdgeColor.set('white');
                outlinePass.hiddenEdgeColor.set('black' );
				composer.addPass( outlinePass );

                const outputPass = new OutputPass();
				composer.addPass( outputPass );
				effectFXAA = new ShaderPass( FXAAShader );
				effectFXAA.uniforms[ 'resolution' ].value.set( 1 / container.clientWidth, 1 / container.clientHeight );
				composer.addPass( effectFXAA );
            }

            function LoadModels() {
                loader.load('Bed.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Bed = gltf.scene;
                });
                loader.load('Cover.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Cover = gltf.scene;
                });
                loader.load('Zaxis.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    //gltf.scene.position.set(0,-181,0);
                    Zaxis = gltf.scene;
                });
                loader.load('Xaxis.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    //gltf.scene.position.set(0,-181,-288.9);
                    Xaxis = gltf.scene;
                });
                loader.load('Turret.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    //gltf.scene.position.set(75, -61.100, -377.5);
                    Turret = gltf.scene;
                });
                loader.load('Spindle.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Spindle = gltf.scene;
                });
                loader.load('Switch.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Switch = gltf.scene;
                });
                loader.load('Base.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Base = gltf.scene;
                });
                loader.load('Pipe.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    gltf.scene.position.set(-303,-4, -324);
                    Pipe = gltf.scene;
                });
                loader.load('Pump.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Pump = gltf.scene;
                });
                
                loader.load('Head.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Head = gltf.scene;
                });
                loader.load('Container.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Container = gltf.scene;
                });
                loader.load('Electronics.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Electronics = gltf.scene;
                });
                loader.load('Tailstock.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    Tailstock = gltf.scene;
                });
                loader.load('RightDoor.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    RightDoor = gltf.scene;
                });
                loader.load('LeftDoor.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    LeftDoor = gltf.scene;
                });
                loader.load('BackDoor.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    BackDoor = gltf.scene;
                });
                loader.load('ElectronicDoor.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    ElectronicDoor = gltf.scene;
                });
                loader.load('FrontDoor.glb', (gltf) => {
                    gltf.scene.scale.set(scale,scale,scale);
                    FrontDoor = gltf.scene;
                });
                        
            }

            function Lights() {
                scene.add( new THREE.AmbientLight(0xffffff, 1) );
                light = new THREE.DirectionalLight(0xffffff,4);                 
                light.position.set(287,185,-539);
                light.target.position.set(287, 0, 0);
                light.castShadow = true;
                light.shadowDarkness = 1.5;
                light.shadowCameraVisible = true; 
                const geometry = new THREE.CylinderGeometry( 52, 52, 302, 32 ); 
                const material = new THREE.MeshStandardMaterial({
                    emissive: 0xffffff,
                    emissiveIntensity: 100,
                    color: 0xffffff,
                    roughness: 0
                });
                Lamp = new THREE.Mesh( geometry, material );
                Lamp.rotateZ(Math.PI/2);
                Lamp.name = "Light";
                //Lamp.add(cylinder)
                light.add( Lamp );
            }

            function animate() {
                requestAnimationFrame( animate );
                Update();
                renderer.render( scene, camera );
                composer.render();
            }

            function onWindowResize() {
                camera.aspect = container.clientWidth / container.clientHeight;
                camera.updateProjectionMatrix();
                renderer.setSize( container.clientWidth, container.clientHeight );
                composer.setSize( container.clientWidth, container.clientHeight );
				effectFXAA.uniforms[ 'resolution' ].value.set( 1 / container.clientWidth, 1 / container.clientHeight );
            }

            function Update() {
                Show(base, Base);
                Show(cover, Cover);
                Show(frontdoor, FrontDoor);
                Show(pump, Pump);
                Show(pipe, Pipe);
                Show(coolant, Container);
                Show(onoff, Switch);
                Show(leftdoor, LeftDoor);
                Show(rightdoor, RightDoor);
                Show(backdoor, BackDoor);
                Show(electronicdoor, ElectronicDoor);
                Show(electronics, Electronics);
                Show(tailstock, Tailstock);
                Show(chuck, Spindle);
                Show(bed, Bed);
                Show(head, Head);
                Show(zaxis, Zaxis);
                Show(xaxis, Xaxis);
                Show(toolsturret, Turret);
                Show(lamp, Lamp);
            }

            function Show(obj, Object) {
                (obj.checked == true) ? Object.visible = true : Object.visible = false;
                (obj.checked == true) ? Object.position.set(0,0,0) : Object.position.set(0,0,5000);
            }
            
            function changeContent(){
                document.getElementById("PartsTable").classList.toggle("hide1");
                document.getElementById("PartsTable").classList.toggle("visible2");
            }

            function ModalWindow(e) {
                if (e===1){
                    ModalContainer.style.setProperty('visibility', 'visible');
                }
                if (e===0){
                    ModalContainer.style.setProperty('visibility', 'hidden');
                }
            }

            function ToggleAudio(){
                speechSynthesis.cancel();
                speech =! speech;
                if(speech==0){
                    Speaker.style.setProperty('--displaycancel', '#ffffff');
                    Speaker.style.setProperty('--displaysound', 'none');
                }
                if(speech==1){
                    Speaker.style.setProperty('--displaysound', '#ffffff');
                    Speaker.style.setProperty('--displaycancel', 'none');
                }             
            }

            function ToggleLang(){
                speechSynthesis.cancel();
                lang =! lang;
                    //(lang==0) ? GearB.setAttribute('title',"Enter settings window") : GearB.setAttribute('title',"Ingresar a la ventana de configuración");
                    //(lang==0) ? CloseB.setAttribute('title',"Close window") : CloseB.setAttribute('title',"Cerrar ventana");
                    (lang==0) ? Audios.setAttribute('title',"Turn audio on/off") : Audios.setAttribute('title',"Activar/Desactivar el audio");
                    (lang==0) ? Lang.setAttribute('title',"Change language") : Lang.setAttribute('title',"Cambiar el idioma");
                    (lang==0) ? Fontup.setAttribute('title',"Increase text size") : Fontup.setAttribute('title',"Aumentar el tamaño del texto");
                    (lang==0) ? Fontdown.setAttribute('title',"Decrease text size") : Fontdown.setAttribute('title',"Disminuir el tamaño del texto");
                    (lang==0) ? document.getElementById('title').innerHTML = Messages.Intro.title : document.getElementById('title').innerHTML = Messages.Intro.titulo;
                    (lang==0) ? document.getElementById('infotext').innerHTML = Messages.Intro.text : document.getElementById('infotext').innerHTML = Messages.Intro.texto;
                    changeContent();
                //(lang==0) ? Message.innerHTML = changemsg.text : Message.innerHTML = changemsg.texto;
                //Messages(changemsg);                                
            }

            function FontSize(id, factor){
                let txt = document.getElementById(id);
                console.log(txt)
                let style = window.getComputedStyle(txt, null).getPropertyValue('font-size');
                let currentSize = parseFloat(style);
                let size = currentSize + factor;
                if(size>24){size = 24}
                if(size<14){size = 14}
                txt.style.fontSize = (size) + 'px';
            }

            function allLoadersDone() {
                Machine.add(Base);
                Machine.add(Cover);
                Machine.add(Switch);
                Machine.add(FrontDoor);
                Machine.add(RightDoor);
                Machine.add(LeftDoor);
                Machine.add(BackDoor);
                Machine.add(ElectronicDoor);
                Machine.add(Container);
                Machine.add(Pump);
                Machine.add(Oil);
                Machine.add(Electronics);
                Machine.add(Head);
                Machine.add(Tailstock);
                Machine.add(Xaxis);
                Machine.add(Turret);
                Machine.add(Zaxis);
                Machine.add(Pipe);
                Machine.add(Bed);
                Machine.add(Spindle);
                scene.add(Machine);
                Machine.add(light);
            }

            function onPointerMove( event ) {
				if ( event.isPrimary === false ) return;
				mouse.x = ( event.clientX / container.clientWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / container.clientHeight ) * 2 + 1;
				checkIntersection();
			}

            function onPointerDown( event ) {
				if ( event.isPrimary === false ) return;
				mouse.x = ( event.clientX / container.clientWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / container.clientHeight ) * 2 + 1;
				//checkIntersection();
                select = 1;
                console.log("Si funciona el clic")
			}

            function onPointerUp( event ) {
				if ( event.isPrimary === false ) return;
				mouse.x = ( event.clientX / container.clientWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / container.clientHeight ) * 2 + 1;
				//checkIntersection();
                //select = 0;
                console.log("Si levanta el clic")
			}
			
            function addSelectedObject( object ) {
				selectedObjects = [];
				selectedObjects.push( object );
			}

			function checkIntersection() {
				raycaster.setFromCamera( mouse, camera );
				const intersects = raycaster.intersectObject( scene, true );
				if ( intersects.length > 0 ) {
					let selectedObject = intersects[0].object;
						//Activar para reconocer el nombre de la malla del objeto
                        //console.log(selectedObject);
                    if(selectedObject.name == "Cover_1" || selectedObject.name == "Cover_2") {Message(Messages.Cover);}
                    if(selectedObject.name == 'Bed_1') {Message(Messages.Bed);}
                    if(selectedObject.name == 'Bed_2') {Message(Messages.Servomotor);}
                    if(selectedObject.name == 'Bed_3') {Message(Messages.Guia);}
                    if(selectedObject.name == 'Zaxis_1' || selectedObject.name == 'Zaxis_2') {Message(Messages.Zaxis);}
                    if(selectedObject.name == 'Xaxis_1' || selectedObject.name == 'Xaxis_2' || selectedObject.name == 'Xaxis_3') {Message(Messages.Xaxis);}
                    if(selectedObject.name == 'Turret_1' || selectedObject.name == 'Turret_2' || selectedObject.name == 'Turret_3') {Message(Messages.Turret);}
                    if(selectedObject.name == 'Holder1' || selectedObject.name == 'Holder3') {Message(Messages.Holder);}
                    if(selectedObject.name == 'Insert1' || selectedObject.name == 'Insert3') {Message(Messages.Insert);}
                    if(selectedObject.name == 'Seat') {Message(Messages.Seat);}
                    if(selectedObject.name == 'Clamp') {Message(Messages.Clamp);}
                    if(selectedObject.name == 'ClampScrew') {Message(Messages.ClampScrew);}
                    if(selectedObject.name == 'TorxScrew') {Message(Messages.TorxScrew);}
                    if(selectedObject.name == 'Light') {Message(Messages.Light);}
                    if(selectedObject.name == 'Spindle') {Message(Messages.Chuck);}
                    if(selectedObject.name == 'Jaw1' || selectedObject.name == 'Jaw2' ||selectedObject.name == 'Jaw3') {Message(Messages.Jaw);}
                    if(selectedObject.name == 'Workpiece') {Message(Messages.Workpiece);}
                    if(selectedObject.name == 'Switch_1' || selectedObject.name == 'Switch_2' || selectedObject.name == 'Switch_3') {Message(Messages.Switch);}
                    if(selectedObject.name == 'Base_1') {Message(Messages.Base);}
                    if(selectedObject.name == 'Base_2') {Message(Messages.LevelingLeg);}
                    if(selectedObject.name == 'Pipe_1' || selectedObject.name == 'Pipe_2') {Message(Messages.Pipe);}
                    if(selectedObject.name == 'Pump_1' || selectedObject.name == 'Pump_2' ||selectedObject.name == 'Pump_3' || selectedObject.name == 'Pump_4' ||selectedObject.name == 'Pump_5') {Message(Messages.Pump);}
                    if(selectedObject.name == 'Oil') {Message(Messages.Oil);}
                    if(selectedObject.name == 'Head_1') {Message(Messages.Head);}
                    if(selectedObject.name == 'Head_2') {Message(Messages.Belt);}
                    if(selectedObject.name == 'Head_3') {Message(Messages.Spindle);}
                    if(selectedObject.name == 'Head_4') {Message(Messages.Encoder);}
                    if(selectedObject.name == 'Container_1') {Message(Messages.Container);}
                    if(selectedObject.name == 'Container_2') {Message(Messages.CoolantPump);}
                    if(selectedObject.name == 'Electronics_1') {Message(Messages.Driver);}
                    if(selectedObject.name == 'Electronics_5') {Message(Messages.VFD);}
                    if(selectedObject.name == 'Electronics_2' || selectedObject.name == 'Electronics_3') {Message(Messages.Raceway);}
                    if(selectedObject.name == 'Electronics_4') {Message(Messages.PLC);}
                    if(selectedObject.name == 'Tailstock_1' || selectedObject.name == 'Tailstock_2' || selectedObject.name == 'Tailstock_3') {Message(Messages.Tailstock);}
                    if(selectedObject.name == 'RightDoor') {Message(Messages.RightDoor);}
                    if(selectedObject.name == 'LeftDoor') {Message(Messages.LeftDoor);}
                    if(selectedObject.name == 'BackDoor') {Message(Messages.BackDoor);}
                    if(selectedObject.name == 'ElectronicDoor') {Message(Messages.ElectronicDoor);}
                    if(selectedObject.name == 'FrontDoor_1' || selectedObject.name == 'FrontDoor_2') { Message(Messages.FrontDoor);}
                       
					addSelectedObject( selectedObject );
					outlinePass.selectedObjects = selectedObjects;
                }   
                else {
                    (lang == 1) ? document.getElementById('title').textContent = Messages.Intro.titulo : document.getElementById('title').textContent = Messages.Intro.title;
				    (lang == 1) ? document.getElementById('infotext').textContent = Messages.Intro.texto : document.getElementById('infotext').textContent = Messages.Intro.text;
					outlinePass.selectedObjects = [];
                    speechSynthesis.cancel();
                    select = 0;
				}
            }

            function Message(msg) {
                speechSynthesis.cancel();
                changemsg = msg;
                let utterance = new SpeechSynthesisUtterance();

                //utterance = new SpeechSynthesisUtterance();
                (lang == 1) ? document.getElementById('title').textContent = msg.titulo : document.getElementById('title').textContent = msg.title;
				(lang == 1) ? document.getElementById('infotext').textContent = msg.texto : document.getElementById('infotext').textContent = msg.text;
                (lang == 1) ? utterance.lang= "es-MX" : utterance.lang= "en-US";
                (lang == 1) ? utterance.voice= indexES : utterance.voice= indexEN;
                if (speech == 1) {
                    //(lang == 1) ? Message.innerHTML = msg.texto : Message.innerHTML = msg.text;
					//(lang == 1) ? document.getElementById('title').textContent = msg.titulo : document.getElementById('title').textContent = msg.title;
					//(lang == 1) ? document.getElementById('infotext').textContent = msg.texto : document.getElementById('infotext').textContent = msg.text;
                    (lang == 1) ? utterance.text = msg.titulo + ". " + msg.texto : utterance.text = msg.title + ". " + msg.text ;
                    //console.log(msg.voz);
                    //(lang == 1) ? utterance.lang= "es-MX" : utterance.lang= "en-US";
                    //(lang == 1) ? utterance.voice= indexES : utterance.voice= indexEN;
                //}
                //else {
                //    (lang == 1) ? Message.innerHTML = msg.texto : Message.innerHTML = msg.text;
                //}
                    speechSynthesis.speak(utterance);
                }
            }

			Panel1.addEventListener('mousedown', function(e) {
                isDown = true;
                offset = [Panel1.offsetLeft - e.clientX, Panel1.offsetTop - e.clientY];
            }, true);

            Panel2.addEventListener('mousedown', function(e) {
                isDown = true;
                offset = [Panel2.offsetLeft - e.clientX, Panel2.offsetTop - e.clientY];
            }, true);

            document.addEventListener('mouseup', function() { isDown = false;}, false);

            Panel1.addEventListener('mousemove', function(event) {
                event.preventDefault();
                if (isDown) {
                    mousePosition = {
                        x : event.clientX,
                        y : event.clientY
                    };
                    Panel1.style.left = (mousePosition.x + offset[0]) + 'px';
                    Panel1.style.top  = (mousePosition.y + offset[1]) + 'px';
                }
            }, true);

            Panel2.addEventListener('mousemove', function(event) {
                event.preventDefault();
                if (isDown) {
                    mousePosition = {
                        x : event.clientX,
                        y : event.clientY
                    };
                    Panel2.style.left = (mousePosition.x + offset[0]) + 'px';
                    Panel2.style.top  = (mousePosition.y + offset[1]) + 'px';
                }
            }, true);
        
        </script>
    </body>
</html>