<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="<https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.1.4/dist/mindar-image.prod.js>"></script>
<script src="<https://aframe.io/releases/1.2.0/aframe.min.js>"></script>
<script src="<https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.1.4/dist/mindar-image-aframe.prod.js>"></script>
<title>My Business Card - Jane Doe</title>
</head>
<body>
</body>
</html>
Criando a cena
Iniciaremos criando a cena, a a-scene, que é o objeto global da nossa aplicação. Nela iremos especificar algumas propriedades conforme a documentação do MindAR e também adicionar todos os elementos que irão compor o cenário.
<a-scene
mindar-image="imageTargetSrc: ./assets/target/target.mind;"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false">
</a-scene>
|
Propriedades da a-scene:
-
mindar-image: para especificar o caminho para o target compilado.
-
color-space e renderer: são duas propriedades opcionais que garantem uma maior qualidade na renderização dos elementos gráficos.
-
vr-mode-ui: será inserido para desabilitar o botão que permite acessar a experiência de realidade virtual.
-
device-orientation-permission-ui: será desabilitado para não exibir diálogos que solicitam acesso à alguns eventos relacionados à orientação do dispositivo.
Adicionando elementos na cena
Dentro de a-scene, importaremos os nossos assets através da tag a-assets. Nela podemos colocar imagens, objetos 3D, áudio e vídeos. Para cada elemento importado, devemos indicar um ID único, que é a forma como esse elemento será referenciado mais adiante e o atributo src que conterá o caminho para o item, conforme os exemplos abaixo.
<a-assets>
<img id="imagem" src="./imagem.png"/>
<a-asset-item id="object3D" src="./objeto3D.glft"></a-asset-item>
<audio id="audio" src="./audio.mp3"></audio>
<video id="video" src="./video.mp4"></video>
</a-assets>
|
Como iremos inserir imagens na nossa aplicação, precisaremos da tag img. Vamos colocar o nosso primeiro conteúdo que é a imagem do cartão de visitas que você criou.
<a-assets>
<img id="businessCard" src="./assets/target/businessCard.png"/>
</a-assets>
|
Agora, vamos inserir a câmera usando a tag a-câmera. Nela colocaremos os seguintes parâmetros iniciais:
-
position: para setar o posicionamento dessa entidade considerando as coordenadas x, y e z, respectivamente.
-
look-controls: para desabilitar a opção de rotacionar as entidades através do mouse e touch.
<a-camera
position="0 0 0"
look-controls="enabled: false"
>
</a-camera>
|
Para que possamos exibir o nosso primeiro conteúdo, precisamos da tag a-entity que possibilitará a inserção dos componentes que fornecerão aparência, comportamento e funcionalidades.
Como atributo da tag, precisamos especificar o caminho para o target que precisa ser detectado e rastreado em tempo real. Isso é feito através da propriedade mindar-image-target="targetIndex: 0". O targetIndex: 0, indica o índice da imagem compilada.
Informação: É possível compilar mais de uma imagem em conjunto. Neste caso, os targets serão referenciados considerando a ordem em que as imagens foram posicionadas no image targets compiler.
<a-entity
mindar-image-target="targetIndex: 0"
>
</a-entity>
|
Dentro de a-entity, colocamos o conteúdo que queremos exibir. Por ser apenas uma imagem, usando a tag a-image e especificamos os seguintes atributos:
-
id: identificação única do elemento
-
position: considerando as coordenadas x, y, z, podemos posicionar a imagem no centro com os valores 0, 0, 0.
-
height: altura da imagem
-
width: largura da imagem. Sempre que colocamos 1, estamos indicando que é para considerar a largura do target no ambiente real.
-
src: identificador do item que foi carregado na tag a-assets.
<a-entity mindar-image-target="targetIndex: 0">
<a-image
id="card"
position="0 0 0"
height="0.552"
width="1"
src="#businessCard"
></a-image>
</a-entity>
|
Após todos esses procedimentos, o seu index.html , poderá estar conforme o código abaixo.
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Bibliotecas que precisam ser importadas para usar Mindar com A-frame -->
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.1.4/dist/mindar-image.prod.js"></script>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/hiukim/mind-ar-js@1.1.4/dist/mindar-image-aframe.prod.js"></script>
<title>My Business Card - Jane Doe</title>
</head>
<body>
<a-scene
mindar-image="imageTargetSrc: ./assets/target/target.mind;"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false"
>
<a-assets>
<img id="businessCard" src="./assets/target/businessCard.png" />
</a-assets>
<a-camera position="0 0 0" look-controls="enabled: false" ></a-camera>
<a-entity mindar-image-target="targetIndex: 0">
<a-image id="card" position="0 0 0" height="0.552" width="1" src="#businessCard"></a-image>
</a-entity>
</a-scene>
</body>
</html>
|
Vamos executá-lo utilizando o Live Server no seu VS Code. Após instalar a extensão, clique com o botão direito do mouse sobre o arquivo index.html, e selecione a opção Open with Live Server, que a página web será inicializada.
Figura 3: Exemplo de como usar o Live Server.

Adicionando interações
Podemos começar a colocar o restante dos itens no a-assets. Para isso, baixe esses ícones e coloque na pasta icons e insira uma foto sua, de preferência, com dimensões 980 x 980, na pasta profile. Você pode usar o nosso template canvas para colocar a imagem conforme o design proposto por essa aplicação.
<a-assets>
<img id="perfil" src="./assets/images/profile/perfil.png" />
<img id="businessCard" src="./assets/target/businessCard.png" />
<img id="icon_github" src="./assets/images/icons/icon_github.png" />
<img id="icon_linkedin" src="./assets/images/icons/icon_linkedin.png" />
<img id="icon_twitter" src="./assets/images/icons/icon_twitter.png" />
<img id="icon_web" src="./assets/images/icons/icon_web.png" />
<img id="icon_email" src="./assets/images/icons/icon_email.png" />
</a-assets>
|
Após importar os elementos no a-assets, organizaremos melhor o nosso código, colocando a imagem do cartão de visitas e a foto agrupadas em uma a-entity. No código, ajustamos o posicionamento, altura, largura e escala das imagens para corresponder ao design elaborado.
<a-entity mindar-image-target="targetIndex: 0">
<a-entity>
<a-image
id="card"
position="-0.0 0.00427 -0.07243"
height="0.552"
width="1"
src="#businessCard"></a-image>
<a-image
id="foto-perfil"
position="0.850 0.0 -0.04426"
height="0.15"
width="0.15"
src="#perfil"
scale="4.2 4.2 4.2"
></a-image>
</a-entity>
</a-entity>
|
Dica: Caso você queira ajustar visualmente alguns parâmetros, é possível usar a ferramenta de inspector do A-Frame através do atalho <ctrl> + <alt> + i.
Figura 4: Inspector do A-Frame

Vamos em seguida, inserir uma a-entity contendo cinco tags a-image referentes aos botões dos sites e redes sociais. Experimentalmente, ajustamos os posicionamentos de todos os botões e da entidade que os mantém agrupados, conforme o código abaixo.
<a-entity position="0.065 -0.002 -0.004">
<a-image
id="github-button"
position="-0.52361 -0.4575 -0.04426"
height="0.15"
width="0.15"
src="#icon_github"
animation="property: scale; to: 1.1 1.1 1.1; easing: easeInOutQuad; loop: true; dir: alternate"
>
</a-image>
<a-image
id="linkedin-button"
position="-0.30772 -0.4575 -0.04426"
height="0.15"
width="0.15"
src="#icon_linkedin"
animation="property: scale; to: 1.1 1.1 1.1; easing: easeInOutQuad; loop: true; dir: alternate"
>
</a-image>
<a-image
id="twitter-button"
position="-0.07819 -0.4575 -0.04426"
height="0.15"
width="0.15"
src="#icon_twitter"
animation="property: scale; to: 1.1 1.1 1.1; easing: easeInOutQuad; loop: true; dir: alternate"
>
</a-image>
<a-image
id="email-button"
position="0.16583 -0.4575 -0.04426"
height="0.15"
width="0.15"
src="#icon_email"
animation="property: scale; to: 1.1 1.1 1.1; easing: easeInOutQuad; loop: true; dir: alternate"
>
</a-image>
<a-image
id="web-button"
position="0.40564 -0.4575 -0.04426"
height="0.15"
width="0.15"
src="#icon_web"
animation="property: scale; to: 1.1 1.1 1.1; easing: easeInOutQuad; loop: true; dir: alternate"
>
</a-image>
</a-entity>
|
Opcionalmente, inserimos uma animação através da propriedade animation. A animação acontece aumentando o tamanho dos ícones em uma direção alternada. Para mais informações e customizações consulte a documentação oficial do A-frame.
A escala aumenta e diminui levemente, mas, para exemplificarmos de maneira clara como a animação ocorre, ajustamos um dos ícones para uma maior escala conforme o gif abaixo.
Figura 5: Animação nos botões

Após adicionarmos os botões na cena, precisamos permitir as interações, através do clique. Para isso, devemos inserir as propriedades cursor e raycaster na tag a-camera.
<a-camera
position="0 0 0"
look-controls="enabled: false"
cursor="fuse: false; rayOrigin: mouse;"
raycaster=" far: 10000; objects: .clickable;">
</a-camera>
|
Em raycaster, especificamos que todos os objetos com a classe .clickable, serão clicáveis. Logo, para todos os ícones, devemos adicionar o seguinte atributo class=”clickable”.
Para permitir a interatividade, o raycaster gera uma linha a partir do local em que o usuário clicar até a cena. Dessa forma, se algum objeto interativo, ou seja, que possui a classe .cliclable, ficar no caminho da linha, o evento de click será disparado.
Agora precisamos criar o script que adiciona os comportamentos decorrentes do click nos botões. Para isso, vamos importar o arquivo index.js no head do index.html da seguinte forma:
<script defer src="./assets/scripts/index.js"></script>
|
O atributo defer impedirá que o script seja executado até que a página HTML esteja pronta.
No arquivo javascript, precisamos “escutar” os eventos de click para cada botão. Para selecionar os elementos, podemos utilizar o método document.querySelector(), especificando o id que corresponde a cada um dos objetos, conforme o código abaixo.
const btnGithub = document.querySelector("#github-button");
const btnLinkedin = document.querySelector("#linkedin-button");
const btnTwitter = document.querySelector("#twitter-button");
const btnEmail = document.querySelector("#email-button");
const btnWebsite = document.querySelector("#web-button");
|
Após selecionarmos os elementos, podemos inserir os eventos de click usando o método addEventListener(). No método precisamos implementar a função que será executada quando este evento for disparado. Na nossa aplicação, cada um dos botões abrirá uma página web específica em uma nova janela ou tab. Coloque a URL de suas contas e páginas web.
btnGithub.addEventListener('click', () => {
window.open('https://github.com/pitanglabs', '_blank');
});
btnLinkedin.addEventListener('click', () => {
window.open('https://linkedin.com/in/', '_blank');
});
btnTwitter.addEventListener('click', () => {
window.open('https://twitter.com/', '_blank');
});
btnEmail.addEventListener('click', () => {
window.open('mailto:labs-l@pitang.com');
});
btnWebsite.addEventListener('click', () => {
window.open('https://www.pitang.com/', '_blank');
});
Scanner Customizado
Para customizarmos a nossa aplicação, podemos inserir, opcionalmente, um scanner customizado conforme o exemplo disponibilizado pela biblioteca MindAR.
Figura 6: Scanner customizado do MindAR.

Para tal, coloque o código abaixo no body do seu index.html e na tag img, especifique o caminho para a imagem do cartão de visitas.
<div id="example-scanning-overlay" class="hidden">
<div class="inner">
<img src="./assets/target/businessCard.png" />
<div class="scanline"></div>
</div>
</div>
|
Em seguida, importe o arquivo index.css no head da seguinte forma:
<link rel="stylesheet" href="assets/styles/index.css" />
|
Precisamos agora, sobrescrever o scanner padrão do MindAR através do parâmetro uiScanning na propriedade mindar-image em a-scene, da seguinte forma:
<a-scene
mindar-image="imageTargetSrc: ./assets/target/target.mind; uiScanning: #example-scanning-overlay"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false">
...
|
No seu index.css, coloque o código abaixo, em conformidade com essa demo.
body {
margin: 0;
}
.container {
/* ocupar toda a tela*/
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
}
/* Inicio do Scanning do mindar */
#example-scanning-overlay {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: transparent;
z-index: 2;
}
@media (min-aspect-ratio: 1/1) {
#example-scanning-overlay .inner {
width: 50vh;
height: 50vh;
}
}
@media (max-aspect-ratio: 1/1) {
#example-scanning-overlay .inner {
width: 80vw;
height: 80vw;
}
}
#example-scanning-overlay .inner {
display: flex;
align-items: center;
justify-content: center;
position: relative;
background: linear-gradient(to right, white 10px, transparent 10px) 0 0,
linear-gradient(to right, white 10px, transparent 10px) 0 100%,
linear-gradient(to left, white 10px, transparent 10px) 100% 0,
linear-gradient(to left, white 10px, transparent 10px) 100% 100%,
linear-gradient(to bottom, white 10px, transparent 10px) 0 0,
linear-gradient(to bottom, white 10px, transparent 10px) 100% 0,
linear-gradient(to top, white 10px, transparent 10px) 0 100%,
linear-gradient(to top, white 10px, transparent 10px) 100% 100%;
background-repeat: no-repeat;
background-size: 40px 40px;
}
#example-scanning-overlay.hidden {
display: none;
}
#example-scanning-overlay img {
opacity: 0.6;
width: 90%;
align-self: center;
}
#example-scanning-overlay .inner .scanline {
position: absolute;
width: 100%;
height: 10px;
background: white;
animation: move 2s linear infinite;
}
@keyframes move {
0%,
100% {
top: 0%;
}
50% {
top: calc(100% - 10px);
}
}
/* Fim do Scanning do mindar */
Configuração de rastreamento
Se formos executar a aplicação, podemos observar em alguns momentos, tremores nos elementos. Este é considerado um problema comum em aplicações de RA, devido a alguns fatores como ruídos provenientes da câmera.
Figura 7: Elementos com tremores

Para solucionar este problema podemos ajustar os parâmetros filterMinCF e filterBeta. Informações técnicas podem ser consultadas na documentação oficial do MindAR. Mas, de modo geral, ao diminuir o valor de filterMinCF estamos reduzindo os tremores (jitter) e ao aumentar o valor de filterBeta, estamos reduzindo o delay.
Os valores padrões de filterMinCF e filterBeta são 0.001 e 1000. Experimentalmente, alteramos esses valores no atributo mindar-image, com o objetivo de reduzir os tremores sem aumentar tanto o delay.
<a-scene
mindar-image="imageTargetSrc: ./assets/target/target.mind; filterMinCF:0.001; filterBeta: 0.09; uiScanning: #example-scanning-overlay"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false">
...
|
Podemos observar através do gif a seguir, que os tremores foram reduzidos substancialmente, garantindo uma experiência de usuário mais adequada.
Figura 8: Elementos com redução dos tremores.

Ao final, seu projeto completo poderá estar semelhante aos códigos presentes nesse repositório.
Deploy
Para finalizar o nosso tutorial, faremos o deploy na ferramenta Vercel, através dos seguintes passos:
-
Crie um repositório no seu github para colocar o seu código;
-
Faça o cadastro no Vercel, de preferência com a sua conta do Github;
-
Crie um novo projeto no Vercel;

4. Importe a sua conta do Github

5. Você pode dar acesso a todos os repositórios ou apenas ao que você acabou de criar;

6. Após instalar e selecionar o repositório, clique no botão Import;

7. Caso queira, altere o nome do projeto, em seguida, selecione a opção de deploy e aguarde.

8. Uma nova página será aberta, informando que o deploy foi realizado com sucesso.

9. Clique na janela em branco para abrir o site ou aperte no botão de Go to Dashboard para visualizar o status, domínios, etc.

10. No seu cartão de visitas, altere jane.com/card para a URL gerada pelo Vercel. Em seguida, refaça o procedimento de compilação do target com a imagem nova e substitua no seu projeto.
11. Por fim, realize o push no github e aguarde, que o Vercel irá alterar a página com as novas atualizações.
|
|
|