Cómo hacer botones y estilos en realidad aumentada WebAR

¿Qué tipo de botones podemos crear para nuestras aplicaciones de realidad aumentada WebAR?

Cómo hacer botones y estilos en realidad aumentada WebAR

La Realidad Aumentada (AR) tiene un factor «wow» innegable. Ver un modelo 3D aparecer sobre tu escritorio o en la pared de tu sala, anclado al mundo real, sigue pareciendo magia. Pero, ¿qué pasa después del primer impacto? El usuario ve el modelo y piensa: … ¿y ahora qué?

Aquí es donde la mayoría de las demos de AR fallan y donde las verdaderas aplicaciones brillan. La diferencia radica en la interactividad, y el puente hacia esa interactividad es la Interfaz de Usuario (UI).

Ahora que hablamos de UI. Te invito a que visites este post:

En el proyecto que acabamos de construir, no nos conformamos con mostrar un solo modelo; creamos un selector dinámico. Pero más importante aún, no nos conformamos con botones grises estándar. Creamos una experiencia.

La Importancia de Invertir en Diseño

Antes de continuar te invito a probar la herramienta de realidad aumentada empezando desde cero para hacer realidad aumentada en minutos y gratis, no necesitas código. Herramienta AR (No code): Crea Realidad Aumentada Fácil y Gratis con este Editor Web

En una aplicación de Realidad Aumentada, la interfaz no es un simple adorno; es una parte fundamental de la experiencia por varias razones:

  • Guía al Usuario: Un botón bien diseñado no solo es un objetivo de clic. Su color, su animación o incluso su texto («Ver Siguiente», «Más Información») le dice al usuario qué puede hacer. Elimina la fricción y la adivinanza.
  • Genera Engagement (Compromiso): Seamos honestos: los botones animados son satisfactorios. Un botón que tiembla (shake), uno que tiene un pulso (pulse) o uno con un complejo efecto flip 3D como nuestro «Botón 7», invitan a ser presionados. Este feedback visual hace que la aplicación se sienta viva y receptiva.
  • Refuerza la Identidad: El estilo de tu interfaz (colores, tipografías, animaciones) le da personalidad a tu aplicación. Transforma un demo técnico genérico en una aplicación pulida y profesional que representa una marca o una idea.

En nuestra app, el «Botón Inicial» es simple y funcional. El «Botón 2» tiembla, quizás sugiriendo una acción «divertida». El «Botón 4» tiene un flip, dando una sensación de cambio drástico. El «Botón 7» es complejo y llamativo, perfecto para una «acción principal». Esta variedad estilística no es aleatoria; es diseño intencional.

Las Tecnologías Detrás de Escena

Para lograr esta fusión de AR e interfaz de usuario, utilizamos un «stack» de tecnologías web moderno y accesible:

  • HTML (El Esqueleto): Proporciona la estructura básica de la página, definiendo dónde va la escena de AR y dónde va el contenedor de botones.
  • CSS (La Personalidad): Aquí es donde ocurre el secreto del diseño. CSS nos permite tomar simples elementos <button> y <a> y darles vida con colores, sombras, bordes redondeados y, lo más importante, @keyframes (animaciones) y transitions (transiciones).
  • JavaScript (El Cerebro): Es el director de orquesta. JS «escucha» los clics en nuestros botones estilizados y ejecuta la lógica principal: oculta el modelo 3D actual y muestra el nuevo.
  • A-Frame (El Escenario AR): Este increíble framework de Mozilla convierte el HTML en un mundo 3D y de Realidad Virtual. Nos permite declarar elementos 3D (<a-gltf-model>) con la misma facilidad que una imagen (<img>).
  • MindAR (El Lente Mágico): Esta librería es la pieza clave que conecta A-Frame con la cámara de tu dispositivo. Se encarga de encontrar el marcador (la imagen objetivo) y anclar nuestra escena de A-Frame sobre él.

Pasemos al codigo y hablemos del HTML:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MindAR 8 Modelos</title>

<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mind-ar@1.2.5/dist/mindar-image-aframe.prod.js"></script>

<link rel="stylesheet" href="style.css">
<script src="main.js" defer></script>
</head>
<body>

<div class="mindar-container">

<div class="controls">
<button id="btnInicial" class="btn-inicial">Inicial</button>
<button id="btn1" class="btn-1">Botón 1</button>
<button id="btn2" class="btn-2">Botón 2</button>
<button id="btn3" class="btn-3">Botón 3</button>
<button id="btn4" class="btn-4">Botón 4</button>
<button id="btn5" class="btn-5">Botón 5</button>
<button id="btn6" class="btn-6">Botón 6</button>

<a href="#" id="btn7" class="btn-7">
<span data-attr="Botón">Botón</span>
<span data-attr=" 7"> 7</span>
</a>
</div>

<a-scene
mindar-image="imageTargetSrc: ./targets.mind;"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false">

<a-assets>
<a-asset-item id="model0" src="./Astronauta.glb"></a-asset-item>
<a-asset-item id="model1" src="./Fox-Female-Animations.glb"></a-asset-item>
<a-asset-item id="model2" src="./Rhino.glb"></a-asset-item>
<a-asset-item id="model3" src="./shiba.glb"></a-asset-item>
<a-asset-item id="model4" src="./Turtle.glb"></a-asset-item>
<a-asset-item id="model5" src="./Wolf.glb"></a-asset-item>
<a-asset-item id="model6" src="./Fox-Female 2 -No Animations.glb"></a-asset-item>
<a-asset-item id="model7" src="./Bird.glb"></a-asset-item>
</a-assets>

<a-camera position="0 0 0" look-controls="enabled: false"></a-camera>

<a-entity mindar-image-target="targetIndex: 0">

<a-gltf-model id="modelo-0" src="#model0" visible="true" position="0 0 0" rotation="0 -90 0" scale="3 3 3"></a-gltf-model>

<a-gltf-model id="modelo-1" src="#model1" visible="false" position="0 -1 0" rotation="0 -90 0" scale="0.5 0.5 0.5"></a-gltf-model>
<a-gltf-model id="modelo-2" src="#model2" visible="false" position="0 0 0" rotation="0 -90 0" scale="3 3 3"></a-gltf-model>
<a-gltf-model id="modelo-3" src="#model3" visible="false" position="0 0 0" scale="1 1 1"></a-gltf-model>
<a-gltf-model id="modelo-4" src="#model4" visible="false" position="0 0 0" rotation="0 -90 0" scale="3 3 3"></a-gltf-model>
<a-gltf-model id="modelo-5" src="#model5" visible="false" position="0 -1 0" rotation="0 -90 0" scale="0.5 0.5 0.5"></a-gltf-model>
<a-gltf-model id="modelo-6" src="#model6" visible="false" position="0 0 0" rotation="0 -90 0" scale="3 3 3"></a-gltf-model>
<a-gltf-model id="modelo-7" src="#model7" visible="false" position="0 0 0" rotation="0 -90 0" scale="3 3 3"></a-gltf-model>

</a-entity>
</a-scene>
</div>
</body>
</html>

pasemos a al Javascript que es el encargado de hacer basicamente todo:

document.addEventListener('DOMContentLoaded', () => {const btnInicial = document.querySelector("#btnInicial");
const btn1 = document.querySelector("#btn1");
const btn2 = document.querySelector("#btn2");
const btn3 = document.querySelector("#btn3");
const btn4 = document.querySelector("#btn4");
const btn5 = document.querySelector("#btn5");
const btn6 = document.querySelector("#btn6");
const btn7 = document.querySelector("#btn7");

const models = {
0: document.querySelector("#modelo-0"),
1: document.querySelector("#modelo-1"),
2: document.querySelector("#modelo-2"),
3: document.querySelector("#modelo-3"),
4: document.querySelector("#modelo-4"),
5: document.querySelector("#modelo-5"),
6: document.querySelector("#modelo-6"),
7: document.querySelector("#modelo-7")
};

/**
* Función central para cambiar la visibilidad de los modelos.
* @param {number} indexToShow - El índice del modelo (0 al 7) que se debe mostrar.
*/
const showModel = (indexToShow) => {
console.log(`Mostrando modelo: ${indexToShow}`);

Object.keys(models).forEach(key => {
const model = models[key];

if (key == indexToShow) {
model.setAttribute('visible', 'true');
} else {
model.setAttribute('visible', 'false');
}
});
};btnInicial.addEventListener('click', () => showModel(0));
btn1.addEventListener('click', () => showModel(1));
btn2.addEventListener('click', () => showModel(2));
btn3.addEventListener('click', () => showModel(3));
btn4.addEventListener('click', () => showModel(4));
btn5.addEventListener('click', () => showModel(5));
btn6.addEventListener('click', () => showModel(6));

btn7.addEventListener('click', (e) => {
e.preventDefault();
});

});

Y para finalizar miremos el CSS que en este caso es el encargado de todo este tutorial:


/* Estilos básicos */
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
font-family: verdana; /* Añadido de tu ejemplo */
}

.mindar-container {
width: 100%;
height: 100%;
position: relative;
}

/* Contenedor de botones (overlay) */
.controls {
position: absolute;
bottom: 20px;
left: 0;
width: 100%;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}

/* Estilo base para todos los botones (y enlaces como botones) */
.controls button,
.controls a {
padding: 10px 15px;
font-size: 14px;
font-weight: bold;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 10px rgba(0,0,0,0.2);
text-decoration: none;
text-transform: uppercase;
display: inline-block;
line-height: 1.2;
}

/* Botón Inicial (Estilo simple) */
.btn-inicial {
background-color: #f0f0f0;
color: #333;
border: 2px solid #ccc;
}
.btn-inicial:hover {
background-color: #ddd;
}

/* --- Estilos y Animaciones Únicas --- */

/* Botón 1: Pulso brillante */
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(0, 119, 255, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(0, 119, 255, 0); }
100% { box-shadow: 0 0 0 0 rgba(0, 119, 255, 0); }
}
.btn-1 {
background-color: #007bff;
color: white;
animation: pulse 2s infinite;
}
.btn-1:hover {
transform: scale(1.05);
}

/* Botón 2: Sacudida (Shake) */
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.btn-2 {
background-color: #28a745;
color: white;
}
.btn-2:hover {
animation: shake 0.5s ease-in-out;
}

/* Botón 3: Cambio de color */
@keyframes color-change {
0% { background-color: #ffc107; }
50% { background-color: #e0a800; }
100% { background-color: #ffc107; }
}
.btn-3 {
color: #333;
animation: color-change 3s infinite linear;
}

/* Botón 4: Efecto 3D (Flip) */
.btn-4 {
background-color: #dc3545;
color: white;
transition: transform 0.5s;
transform-style: preserve-3d;
}
.btn-4:hover {
transform: rotateY(180deg);
}

/* Botón 5: Rebote */
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
.btn-5 {
background-color: #17a2b8;
color: white;
}
.btn-5:hover {
animation: bounce 0.5s ease;
}

/* Botón 6: Borde animado */
.btn-6 {
background-color: #343a40;
color: white;
position: relative;
overflow: hidden;
border: 2px solid transparent;
}
.btn-6::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: conic-gradient(
transparent,
rgba(108, 117, 125, 0.8),
transparent 30%
);
animation: rotate 4s linear infinite;
}
.btn-6:hover::before {
animation-play-state: paused;
}
@keyframes rotate {
100% { transform: rotate(360deg); }
}

/* --- Botón 7: Efecto Flip 3D (Adaptado) --- */
.controls a.btn-7 {
padding: 0;
box-shadow: none;
border-radius: 0;
background: none;
/* El font-size se hereda de '.controls a' */
}

.controls a.btn-7 span {
padding: 10px 15px; /* Ajustado */
font-size: 14px; /* Ajustado */
transition: .5s;
position: relative;
display: inline-block;
box-shadow: 0 4px 10px rgba(0,0,0,0.2);
}

.controls a.btn-7 span:nth-child(1) {
color: #fff;
background: #262626;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}

.controls a.btn-7 span:nth-child(2) {
color: #fff;
background: #ff3636;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
margin-left: -5px; /* Unimos los botones */
}

.controls a.btn-7 span:nth-child(1):before {
content: attr(data-attr);
position: absolute;
top: 0;
left: 0;
background: #ff3636;
padding: 10px 15px; /* Ajustado */
transition: 0.5S;
transform-origin: top;
transform: rotateX(90deg) translateY(-50%);
width: 100%;
box-sizing: border-box;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}

.controls a.btn-7:hover span:nth-child(1):before {
transform: rotateX(0deg) translateY(0%);
}

.controls a.btn-7 span:nth-child(2):before {
content: attr(data-attr);
position: absolute;
top: 0;
left: 0;
background: #262626;
padding: 10px 15px; /* Ajustado */
transition: 0.5S;
transform-origin: bottom;
transform: rotateX(90deg) translateY(50%);
width: 100%;
box-sizing: border-box;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}

.controls a.btn-7:hover span:nth-child(2):before {
transform: rotateX(0deg) translateY(0%);
}

.controls a.btn-7 span:nth-child(1):after {
content: attr(data-attr);
padding: 10px 15px; /* Ajustado */
position: absolute;
top: 0;
left: 0;
background: #262626;
transform-origin: bottom;
transform: rotateX(0deg) translateY(0%);
transition: 0.5s;
width: 100%;
box-sizing: border-box;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}

.controls a.btn-7:hover span:nth-child(1):after {
transform: rotateX(90deg) translateY(50%);
}

.controls a.btn-7 span:nth-child(2):after {
content: attr(data-attr);
position: absolute;
top: 0;
left: 0;
background: #ff3636;
padding: 10px 15px; /* Ajustado */
transition: 0.5S;
transform-origin: top;
transform: rotateX(0deg) translateY(0%);
width: 100%;
box-sizing: border-box;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}

.controls a.btn-7:hover span:nth-child(2):after {
transform: rotateX(90deg) translateY(-50%);
}

Te invito a que descargues todos los archivos de este tutorial: DESCARGA AQUI

  • El proyecto completo en Visual Studio Code.
  • Modelos 3D.
  • Código HTML, CSS y JAVASCRIPT – Comentado línea por línea.

Conclusión

La Realidad Aumentada es una herramienta de visualización increíble, pero su verdadero potencial se desbloquea cuando se convierte en una herramienta de interacción.

Invertir tiempo en el CSS, en las animaciones de los botones y en el diseño general de la interfaz no es un paso extra; es el paso que eleva una demo técnica a una experiencia de usuario memorable y efectiva. No te límites a mostrarle al usuario un modelo 3D; dale una forma hermosa e intuitiva de controlarlo.

 

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Scroll al inicio
0
Would love your thoughts, please comment.x
()
x