{"id":353,"date":"2026-07-03T13:14:09","date_gmt":"2026-07-03T16:14:09","guid":{"rendered":"https:\/\/jandaiadosul.ufpr.br\/spei\/?page_id=353"},"modified":"2026-07-03T15:32:14","modified_gmt":"2026-07-03T18:32:14","slug":"353-2","status":"publish","type":"page","link":"https:\/\/jandaiadosul.ufpr.br\/spei\/353-2\/","title":{"rendered":""},"content":{"rendered":"\n    \n    \n    <title>Nexus Inova\u00e7\u00e3o | Superf\u00edcie 3D<\/title>\n    \n    \n    <!-- Google Fonts -->\n    \n    \n    \n\n\n\n    \n        :root {\n            &#8211;color-primary: #00f0ff;\n            &#8211;color-secondary: #a855f7;\n            &#8211;color-bg: #03030c;\n        }\n\n        * {\n            box-sizing: border-box;\n            margin: 0;\n            padding: 0;\n            cursor: none !important; \/* Oculta o cursor nativo em toda a p\u00e1gina *\/\n        }\n\n        body {\n            background-color: var(&#8211;color-bg);\n            background-image: radial-gradient(circle at 50% 50%, rgba(15, 7, 34, 0.6) 0%, rgba(3, 3, 12, 1) 100%), url(&#8216;innovation_bg.png&#8217;);\n            background-size: cover;\n            background-position: center;\n            background-repeat: no-repeat;\n            min-height: 100vh;\n            overflow: hidden;\n            position: relative;\n        }\n\n        \/* Custom Cursor *\/\n        .custom-cursor {\n            width: 30px;\n            height: 30px;\n            border: 2px solid var(&#8211;color-primary);\n            border-radius: 50%;\n            position: fixed;\n            transform: translate(-50%, -50%);\n            pointer-events: none;\n            z-index: 9999;\n            transition: width 0.2s, height 0.2s, background-color 0.2s, border-color 0.2s;\n            mix-blend-mode: difference;\n        }\n\n        .custom-cursor-dot {\n            width: 6px;\n            height: 6px;\n            background-color: var(&#8211;color-primary);\n            border-radius: 50%;\n            position: fixed;\n            transform: translate(-50%, -50%);\n            pointer-events: none;\n            z-index: 9999;\n        }\n\n        #webgl-canvas {\n            position: fixed;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            z-index: 1;\n        }\n\n        \/* Flash de luz branca transi\u00e7\u00e3o *\/\n        #flash-overlay {\n            position: fixed;\n            top: 0;\n            left: 0;\n            width: 100vw;\n            height: 100vh;\n            background-color: #ffffff;\n            opacity: 0;\n            pointer-events: none;\n            z-index: 10000;\n            transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1);\n        }\n\n        #flash-overlay.active {\n            opacity: 1;\n        }\n    \n\n\n\n    <!-- Cursores Personalizados -->\n    <div class=\"custom-cursor\" id=\"custom-cursor\"><\/div>\n    <div class=\"custom-cursor-dot\" id=\"custom-cursor-dot\"><\/div>\n\n    <!-- Flash de Transi\u00e7\u00e3o -->\n    <div id=\"flash-overlay\"><\/div>\n\n    <!-- Canvas para renderizar a superf\u00edcie 3D -->\n    \n\n    <!-- Biblioteca Three.js -->\n    \n\n\n\n    \n        \/\/ &#8212; 1. CONFIGURA\u00c7\u00c3O DO CURSOR PERSONALIZADO &#8212;\n        const cursor = document.getElementById(&#8216;custom-cursor&#8217;);\n        const cursorDot = document.getElementById(&#8216;custom-cursor-dot&#8217;);\n        \n        let mouseX = window.innerWidth \/ 2;\n        let mouseY = window.innerHeight \/ 2;\n        let cursorX = mouseX;\n        let cursorY = mouseY;\n        let dotX = mouseX;\n        let dotY = mouseY;\n\n        window.addEventListener(&#8216;mousemove&#8217;, (e) =&gt; {\n            mouseX = e.clientX;\n            mouseY = e.clientY;\n        });\n\n        function animateCursor() {\n            cursorX += (mouseX &#8211; cursorX) * 0.15;\n            cursorY += (mouseY &#8211; cursorY) * 0.15;\n            cursor.style.left = `${cursorX}px`;\n            cursor.style.top = `${cursorY}px`;\n\n            dotX += (mouseX &#8211; dotX) * 0.35;\n            dotY += (mouseY &#8211; dotY) * 0.35;\n            cursorDot.style.left = `${dotX}px`;\n            cursorDot.style.top = `${dotY}px`;\n\n            requestAnimationFrame(animateCursor);\n        }\n        animateCursor();\n\n        \/\/ &#8212; 2. CONFIGURA\u00c7\u00c3O DA CENA THREE.JS &#8212;\n        const canvas = document.getElementById(&#8216;webgl-canvas&#8217;);\n        const clock = new THREE.Clock();\n        \n        const mouse3D = new THREE.Vector2(0, 0);\n        window.addEventListener(&#8216;mousemove&#8217;, (e) =&gt; {\n            mouse3D.x = (e.clientX \/ window.innerWidth) * 2 &#8211; 1;\n            mouse3D.y = -(e.clientY \/ window.innerHeight) * 2 + 1;\n        });\n\n        const scene = new THREE.Scene();\n        const camera = new THREE.PerspectiveCamera(45, window.innerWidth \/ window.innerHeight, 0.1, 100);\n        camera.position.z = 8;\n\n        const renderer = new THREE.WebGLRenderer({\n            canvas: canvas,\n            antialias: true,\n            alpha: true,\n            powerPreference: &#8220;high-performance&#8221;\n        });\n        renderer.setSize(window.innerWidth, window.innerHeight);\n        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));\n        renderer.toneMapping = THREE.ACESFilmicToneMapping;\n        renderer.toneMappingExposure = 1.2;\n\n        const textureLoader = new THREE.TextureLoader();\n        let bgMesh = null;\n        let glassMesh = null;\n        let mouseLight = null;\n        let textMeshes = [];\n        let isTransitioning = false;\n        let activeTextures = {};\n\n        const raycaster = new THREE.Raycaster();\n\n        \/\/ Fallback\/Gera\u00e7\u00e3o de textura de fundo em caso de erro ou file:\/\/\n        function createProceduralTexture() {\n            const canvas = document.createElement(&#8216;canvas&#8217;);\n            canvas.width = 1024;\n            canvas.height = 1024;\n            const ctx = canvas.getContext(&#8216;2d&#8217;);\n\n            const grad = ctx.createRadialGradient(512, 512, 50, 512, 512, 700);\n            grad.addColorStop(0, &#8216;#12042b&#8217;);\n            grad.addColorStop(0.4, &#8216;#030514&#8217;);\n            grad.addColorStop(1, &#8216;#010103&#8217;);\n            ctx.fillStyle = grad;\n            ctx.fillRect(0, 0, 1024, 1024);\n\n            ctx.strokeStyle = &#8216;rgba(0, 240, 255, 0.12)&#8217;;\n            ctx.lineWidth = 1.5;\n            \n            const points = [];\n            for (let i = 0; i  0.6\n                });\n            }\n\n            ctx.beginPath();\n            for (let i = 0; i &lt; points.length; i++) {\n                for (let j = i + 1; j &lt; points.length; j++) {\n                    const dx = points[i].x &#8211; points[j].x;\n                    const dy = points[i].y &#8211; points[j].y;\n                    const dist = Math.sqrt(dx*dx + dy*dy);\n                    if (dist &lt; 260) {\n                        ctx.moveTo(points[i].x, points[i].y);\n                        ctx.lineTo(points[j].x, points[j].y);\n                    }\n                }\n            }\n            ctx.stroke();\n\n            for (let i = 0; i  930 &amp;&amp; fontSize &gt; 40) {\n                fontSize -= 4;\n                ctx.font = `bold ${fontSize}px &#8220;Saira Extra Condensed&#8221;, sans-serif`;\n            }\n            \n            \/\/ 1. Degrad\u00ea de preenchimento (Azul Glacial Cristalino de alto contraste)\n            const fillGrad = ctx.createLinearGradient(0, 30, 0, 220);\n            fillGrad.addColorStop(0, &#8216;#ffffff&#8217;);      \/\/ Brilho superior reflexivo\n            fillGrad.addColorStop(0.35, &#8216;#cbf3ff&#8217;);   \/\/ Azul gelo claro\n            fillGrad.addColorStop(0.7, &#8216;#00ddff&#8217;);    \/\/ Ciano neon brilhante\n            fillGrad.addColorStop(1, &#8216;#004c99&#8217;);      \/\/ Tom azul escuro profundo na base\n            \n            ctx.fillStyle = fillGrad;\n            \n            \/\/ Sombra suave interna para dar volume \u00e0s letras individuais\n            ctx.shadowColor = &#8216;rgba(0, 240, 255, 0.45)&#8217;;\n            ctx.shadowBlur = 14;\n            ctx.shadowOffsetY = 4;\n            \n            ctx.fillText(text, 512, 128);\n            \n            \/\/ Reseta sombra para manter os contornos das bordas n\u00edtidos\n            ctx.shadowColor = &#8216;transparent&#8217;;\n            ctx.shadowBlur = 0;\n            ctx.shadowOffsetY = 0;\n            \n            \/\/ 2. Contorno do vidro (Simula chanfragem reflexiva)\n            \/\/ Contorno ciano externo m\u00e9dio\n            ctx.strokeStyle = &#8216;rgba(0, 240, 255, 0.45)&#8217;;\n            ctx.lineWidth = 5;\n            ctx.strokeText(text, 512, 128);\n            \n            \/\/ Contorno branco interno muito fino\n            ctx.strokeStyle = &#8216;rgba(255, 255, 255, 0.8)&#8217;;\n            ctx.lineWidth = 1.5;\n            ctx.strokeText(text, 512, 128);\n            \n            const texture = new THREE.CanvasTexture(canvas);\n            texture.minFilter = THREE.LinearFilter;\n            texture.magFilter = THREE.LinearFilter;\n            return texture;\n        }\n\n        \/\/ Carrega assets necess\u00e1rios (somente o background)\n        function loadAssets(callback) {\n            let loadedCount = 0;\n            const totalAssets = 1;\n            const assets = {};\n            \n            function checkLoaded() {\n                loadedCount++;\n                if (loadedCount === totalAssets) {\n                    callback(assets);\n                }\n            }\n            \n            \/\/ Background\n            const isLocalFile = window.location.protocol === &#8216;file:&#8217;;\n            if (isLocalFile) {\n                assets.bg = createProceduralTexture();\n                checkLoaded();\n            } else {\n                textureLoader.load(&#8216;innovation_bg.png&#8217;, \n                    (tex) =&gt; { assets.bg = tex; checkLoaded(); },\n                    undefined,\n                    () =&gt; { \n                        assets.bg = createProceduralTexture(); \n                        checkLoaded();\n                    }\n                );\n            }\n        }\n\n        \/\/ Garante carregamento da fonte antes de iniciar o Three.js\n        document.fonts.ready.then(() =&gt; {\n            loadAssets((loadedAssets) =&gt; {\n                activeTextures = loadedAssets;\n                initScene();\n            });\n        });\n\n        \/\/ &#8212; 4. INICIALIZA\u00c7\u00c3O DOS ELEMENTOS DA CENA &#8212;\n        let dirLight1, dirLight2, ambientLight;\n\n        function initScene() {\n            activeTextures.bg.wrapS = THREE.ClampToEdgeWrapping;\n            activeTextures.bg.wrapT = THREE.ClampToEdgeWrapping;\n            activeTextures.bg.minFilter = THREE.LinearFilter;\n\n            \/\/ Fundo\n            const bgGeometry = new THREE.PlaneGeometry(60, 40);\n            const bgMaterial = new THREE.MeshBasicMaterial({ map: activeTextures.bg });\n            bgMesh = new THREE.Mesh(bgGeometry, bgMaterial);\n            bgMesh.position.z = -5;\n            scene.add(bgMesh);\n\n            \/\/ ILUMINA\u00c7\u00c3O\n            ambientLight = new THREE.AmbientLight(0x0e0e22, 1.8);\n            scene.add(ambientLight);\n\n            dirLight1 = new THREE.DirectionalLight(0x00f0ff, 2.5);\n            dirLight1.position.set(-8, 8, 6);\n            scene.add(dirLight1);\n\n            dirLight2 = new THREE.DirectionalLight(0xa855f7, 2.0);\n            dirLight2.position.set(8, -8, 6);\n            scene.add(dirLight2);\n\n            mouseLight = new THREE.PointLight(0xffffff, 5.0, 18);\n            mouseLight.position.set(0, 0, 2.5);\n            scene.add(mouseLight);\n\n            \/\/ Dados de posicionamento e links das palavras (Coordenadas ajustadas para evitar sobreposi\u00e7\u00e3o)\n            const wordsData = [\n                { key: &#8216;parcerias&#8217;, text: &#8216;Parcerias&#8217;, url: &#8216;parcerias.html&#8217;, x: -4.0, y: 2.0, z: -2, baseScale: 1.45 },\n                { key: &#8216;empreender&#8217;, text: &#8216;Empreendedorismo&#8217;, url: &#8216;empreender.html&#8217;, x: 3.7, y: 1.8, z: -2.2, baseScale: 1.3 },\n                { key: &#8216;spei&#8217;, text: &#8216;SPEI&#8217;, url: null, x: 0.0, y: 0.0, z: -2.1, baseScale: 1.4 }, \/\/ Sem link!\n                { key: &#8216;inovacao&#8217;, text: &#8216;Inova\u00e7\u00e3o&#8217;, url: &#8216;inovacao.html&#8217;, x: -3.7, y: -2.0, z: -2.2, baseScale: 1.5 },\n                { key: &#8216;noticias&#8217;, text: &#8216;Not\u00edcias&#8217;, url: &#8216;noticias.html&#8217;, x: 4.0, y: -1.8, z: -2, baseScale: 1.45 }\n            ];\n\n            wordsData.forEach(data =&gt; {\n                \/\/ Desenha a textura dos caracteres da palavra\n                const texture = createWordTexture(data.text);\n                \n                \/\/ Propor\u00e7\u00e3o baseada no canvas da palavra (1024\/256 = 4.0)\n                const aspect = 4.0;\n                \n                \/\/ Alturas significativamente aumentadas para maior tamanho na tela\n                let textHeight = 1.05; \n                if (data.key === &#8216;empreender&#8217;) {\n                    textHeight = 1.4; \/\/ Propor\u00e7\u00e3o maior para &#8220;Empreendedorismo&#8221; n\u00e3o ficar comprimida\n                } else if (data.key === &#8216;spei&#8217;) {\n                    textHeight = 1.2; \/\/ Altura ideal de destaque central para o SPEI\n                }\n                const geometry = new THREE.PlaneGeometry(aspect * textHeight, textHeight);\n                \n                \/\/ Material Frontal (Crispado, Degrad\u00ea de alto contraste)\n                const frontMaterial = new THREE.MeshPhysicalMaterial({ \n                    map: texture, \n                    transparent: true,\n                    opacity: 1.0,                \n                    transmission: 0.0,           \/\/ Sem transpar\u00eancia para manter contraste\n                    roughness: 0.08,             \n                    metalness: 0.05,              \n                    ior: 1.5,                   \n                    clearcoat: 1.0,              \n                    clearcoatRoughness: 0.05,\n                    emissive: new THREE.Color(0x000000), \n                    emissiveIntensity: 0.0,      \n                    depthWrite: false \n                });\n\n                \/\/ Material da Extrus\u00e3o (Cria profundidade escura nas laterais)\n                const extrusionMaterial = new THREE.MeshPhysicalMaterial({\n                    map: texture,\n                    transparent: true,\n                    opacity: 0.85,\n                    transmission: 0.0,\n                    color: new THREE.Color(0x1a3a66), \n                    roughness: 0.25,\n                    metalness: 0.1,\n                    clearcoat: 0.5,\n                    clearcoatRoughness: 0.2,\n                    emissive: new THREE.Color(0x000000),\n                    emissiveIntensity: 0.0,\n                    depthWrite: false\n                });\n                \n                \/\/ Empilhamento Volum\u00e9trico (26 camadas) para criar o corpo 3D dos caracteres\n                const wordGroup = new THREE.Group();\n                wordGroup.position.set(data.x, data.y, data.z);\n                \n                const layersCount = 26;      \n                const layerSpacing = 0.024;  \/\/ Espessura do volume tridimensional\n                \n                let frontMesh = null;\n                for (let i = 0; i  textureAspect) {\n                    bgTexture.repeat.set(1, textureAspect \/ screenAspect);\n                    bgTexture.offset.set(0, (1 &#8211; textureAspect \/ screenAspect) \/ 2);\n                } else {\n                    bgTexture.repeat.set(screenAspect \/ textureAspect, 1);\n                    bgTexture.offset.set((1 &#8211; screenAspect \/ textureAspect) \/ 2, 0);\n                }\n            }\n        }\n        window.addEventListener(&#8216;resize&#8217;, resize);\n\n        \/\/ &#8212; 6. EVENTO DE CLIQUE (TRANSI\u00c7\u00c3O) &#8212;\n        window.addEventListener(&#8216;click&#8217;, () =&gt; {\n            if (isTransitioning) return;\n\n            raycaster.setFromCamera(mouse3D, camera);\n            const intersects = raycaster.intersectObjects(textMeshes);\n\n            if (intersects.length &gt; 0) {\n                const clickedMesh = intersects[0].object;\n                \n                \/\/ Se a palavra n\u00e3o tiver URL associada (como o SPEI central), ignore o clique\n                if (!clickedMesh.targetUrl) return;\n\n                isTransitioning = true;\n\n                \/\/ Ativa flash branco CSS\n                const flashOverlay = document.getElementById(&#8216;flash-overlay&#8217;);\n                flashOverlay.classList.add(&#8216;active&#8217;);\n\n                \/\/ Anima luzes e c\u00e2mera\n                const startT = clock.getElapsedTime();\n                function flashLoop() {\n                    const elapsed = clock.getElapsedTime() &#8211; startT;\n                    if (elapsed  {\n                    window.location.href = clickedMesh.targetUrl;\n                }, 800);\n            }\n        });\n\n        \/\/ &#8212; 7. LOOP DE ANIMA\u00c7\u00c3O (RENDER) &#8212;\n        function animate() {\n            requestAnimationFrame(animate);\n\n            const time = clock.getElapsedTime();\n\n            \/\/ Interatividade do mouse na luz de ponto\n            if (mouseLight &amp;&amp; camera &amp;&amp; !isTransitioning) {\n                const vector = new THREE.Vector3(mouse3D.x, mouse3D.y, 0.5);\n                vector.unproject(camera);\n                const dir = vector.sub(camera.position).normalize();\n                const distance = -camera.position.z \/ dir.z;\n                const targetPos = camera.position.clone().add(dir.multiplyScalar(distance));\n\n                mouseLight.position.x += (targetPos.x &#8211; mouseLight.position.x) * 0.12;\n                mouseLight.position.y += (targetPos.y &#8211; mouseLight.position.y) * 0.12;\n                mouseLight.position.z = 2.0;\n            }\n\n            \/\/ Raycasting para Hover\n            if (!isTransitioning) {\n                raycaster.setFromCamera(mouse3D, camera);\n                const intersects = raycaster.intersectObjects(textMeshes);\n                \n                let hoveredObj = null;\n                if (intersects.length &gt; 0) {\n                    hoveredObj = intersects[0].object;\n                }\n\n                \/\/ Efeito no cursor personalizado (funciona tamb\u00e9m no SPEI, pois \u00e9 interativo e oscila)\n                if (hoveredObj) {\n                    cursor.style.width = &#8217;60px&#8217;;\n                    cursor.style.height = &#8217;60px&#8217;;\n                    \/\/ Se n\u00e3o for clic\u00e1vel (SPEI), usa uma cor de cursor diferente (ex: ciano original) em vez de roxo\n                    if (!hoveredObj.targetUrl) {\n                        cursor.style.borderColor = &#8216;var(&#8211;color-primary)&#8217;;\n                        cursor.style.backgroundColor = &#8216;rgba(0, 240, 255, 0.08)&#8217;;\n                    } else {\n                        cursor.style.borderColor = &#8216;var(&#8211;color-secondary)&#8217;;\n                        cursor.style.backgroundColor = &#8216;rgba(168, 85, 247, 0.12)&#8217;;\n                    }\n                } else {\n                    cursor.style.width = &#8217;30px&#8217;;\n                    cursor.style.height = &#8217;30px&#8217;;\n                    cursor.style.borderColor = &#8216;var(&#8211;color-primary)&#8217;;\n                    cursor.style.backgroundColor = &#8216;transparent&#8217;;\n                }\n\n                \/\/ Interpola\u00e7\u00e3o suave de foco e emissivo\n                textMeshes.forEach(mesh =&gt; {\n                    if (mesh === hoveredObj) {\n                        mesh.isHovered = true;\n                        \n                        \/\/ Valores Alvo para Hover (Brilho ciano forte na frente)\n                        mesh.targetEmissiveIntensity = 0.9;      \n                        mesh.targetEmissiveColor = new THREE.Color(0x00f0ff); \n                        mesh.targetScale = mesh.scaleFactor * 1.12;\n                    } else {\n                        mesh.isHovered = false;\n\n                        \/\/ Valores Alvo Padr\u00e3o (Sem brilho para manter contraste)\n                        mesh.targetEmissiveIntensity = 0.0;\n                        mesh.targetEmissiveColor = new THREE.Color(0x000000);\n                        mesh.targetScale = mesh.scaleFactor;\n                    }\n\n                    \/\/ Interpola\u00e7\u00e3o aplicada unicamente ao material da frente (frontMaterial)\n                    mesh.frontMaterial.emissiveIntensity += (mesh.targetEmissiveIntensity &#8211; mesh.frontMaterial.emissiveIntensity) * 0.15;\n                    mesh.frontMaterial.emissive.lerp(mesh.targetEmissiveColor, 0.15);\n                    mesh.frontMaterial.needsUpdate = true;\n\n                    \/\/ Escala tridimensional do grupo\n                    const group = mesh.wordGroup;\n                    const s = group.scale.x + (mesh.targetScale &#8211; group.scale.x) * 0.15;\n                    group.scale.set(s, s, 1);\n                });\n            }\n\n            \/\/ Flutua\u00e7\u00e3o 3D e rota\u00e7\u00e3o reativa com oscila\u00e7\u00e3o no hover\n            textMeshes.forEach(mesh =&gt; {\n                const group = mesh.wordGroup;\n                \n                group.position.y = mesh.initialY + Math.sin(time * 0.8 + mesh.phase) * 0.15;\n                group.position.x = mesh.initialX + Math.cos(time * 0.4 + mesh.phase) * 0.1;\n                group.rotation.z = Math.sin(time * 0.3 + mesh.phase) * 0.04;\n                \n                if (!isTransitioning) {\n                    \/\/ Interpola\u00e7\u00e3o suave do progresso do hover\n                    if (mesh.isHovered) {\n                        mesh.hoverProgress += (1.0 &#8211; mesh.hoverProgress) * 0.10;\n                    } else {\n                        mesh.hoverProgress += (0.0 &#8211; mesh.hoverProgress) * 0.10;\n                    }\n\n                    \/\/ Rota\u00e7\u00e3o padr\u00e3o (acompanha o mouse estaticamente)\n                    const standardRotY = Math.sin(time * 0.1 + mesh.phase) * 0.05 + mouse3D.x * 0.32;\n                    const standardRotX = mouse3D.y * 0.25;\n\n                    \/\/ Rota\u00e7\u00e3o oscilante de hover (oscila de um lado para o outro revelando o volume 3D)\n                    const swingRotY = Math.sin(time * 5.5) * 0.30 + mouse3D.x * 0.15;\n                    const swingRotX = Math.cos(time * 3.5) * 0.12 + mouse3D.y * 0.15;\n\n                    \/\/ Mistura as rota\u00e7\u00f5es de forma suave usando lerp\n                    group.rotation.y = THREE.MathUtils.lerp(standardRotY, swingRotY, mesh.hoverProgress);\n                    group.rotation.x = THREE.MathUtils.lerp(standardRotX, swingRotX, mesh.hoverProgress);\n                }\n            });\n\n            \/\/ Deforma a malha de vidro frontal para gerar refra\u00e7\u00f5es\n            if (glassMesh) {\n                const geometry = glassMesh.geometry;\n                const position = geometry.attributes.position;\n                \n                for (let i = 0; i &lt; position.count; i++) {\n                    const x = position.getX(i);\n                    const y = position.getY(i);\n\n                    const z1 = Math.sin(x * 0.2 + time * 0.7) * Math.cos(y * 0.2 + time * 0.7) * 0.45;\n                    const z2 = Math.sin(x * 0.45 &#8211; time * 0.5) * Math.cos(y * 0.35 + time * 0.4) * 0.2;\n                    const z3 = Math.cos(x * 0.1 + y * 0.1 + time * 0.3) * 0.3;\n\n                    const dx = x &#8211; mouseLight.position.x;\n                    const dy = y &#8211; mouseLight.position.y;\n                    const dist = Math.sqrt(dx * dx + dy * dy);\n                    const mouseGlowEffect = Math.sin(dist * 0.7 &#8211; time * 2.5) * Math.exp(-dist * 0.12) * 0.35;\n\n                    position.setZ(i, z1 + z2 + z3 + mouseGlowEffect);\n                }\n\n                geometry.computeVertexNormals();\n                position.needsUpdate = true;\n\n                glassMesh.rotation.y = Math.sin(time * 0.05) * 0.04;\n                glassMesh.rotation.x = Math.cos(time * 0.05) * 0.02;\n            }\n\n            renderer.render(scene, camera);\n        }\n    \n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nexus Inova\u00e7\u00e3o | Superf\u00edcie 3D :root { &#8211;color-primary: #00f0ff; &#8211;color-secondary: #a855f7; &#8211;color-bg: #03030c; } * { box-sizing: border-box; margin: 0; padding: 0; cursor: none !important; \/* Oculta o cursor nativo em toda a p\u00e1gina *\/ } body { background-color: var(&#8211;color-bg); background-image: radial-gradient(circle at 50% 50%, rgba(15, 7, 34, 0.6) 0%, rgba(3, 3, 12, 1) 100%), [&hellip;]<\/p>\n","protected":false},"author":3605,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-353","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/pages\/353","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/users\/3605"}],"replies":[{"embeddable":true,"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/comments?post=353"}],"version-history":[{"count":6,"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/pages\/353\/revisions"}],"predecessor-version":[{"id":398,"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/pages\/353\/revisions\/398"}],"wp:attachment":[{"href":"https:\/\/jandaiadosul.ufpr.br\/spei\/wp-json\/wp\/v2\/media?parent=353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}