Pirates map: Treasure Hunt example

In this tutorial we will show you how to create an augmented and geolocated treasure hunt.


The experience will display a 2D map with treasure locations. Users approaching any of these locations will be able to launch its associated AR scene, which will show treasure chests floating around that they will have to touch to catch them and sum points.

We will use Onirix Studio for the AR scene configuration and setting up the locations. Then, we will use the online code editor to customize styles, and finally we will wrap (embed) the scene into a simple web application made with React that will comunicate with the AR scene via Embed SDK to detect touch events on treasure chests to increase the score.

Let's begin!

Scene configuration with Onirix Studio

First of all, we will log into Onirix Studio and copy the experience from our library called "Treasure Hunt". We will also create a surface-tracking scene called "Chests" we will use to place the floating chests users will need to catch.

To represent a chest, we will use a low-poly 3D model you can download here (Author: KanghLe96). Just pick the GLTF format and upload it as a new asset in Onirix Studio.

Once it is uploaded, use drag&drop from asset library to add 3 chest 3D elements, and position them floating around scene's center.


As you may see, we've added the 3 chest elements inside a collection, whose position is (0,0,0) or scene's center. This will allow us to create a rotate action when scene loads to simulate chests are orbiting around.

TIP: if you want the treasure chests to appear automatically floating around without selecting a surface, you can use the autoload feature from scene properties menu.

In order to make chests dissapear with an animation when they are tapped, we will add, to every chest element, a 'click' event to 'disable' itselves. We will choose 'bounce' as the animation and 'score' as the animation sound.

Now, we will generate as many scenes as locations we will add to the map. You can duplicate the current one and modify it slightly or just create a new one from scratch.

For simplicity, in this tutorial we will reuse the same scene for all locations, so we will just duplicate it several times.

Our last step for configuration, is to set the project as geolocated. You can do this from project settings menu, enabling the "geolocated project" switch. This will enable a new option "View map" in the topbar for placing each AR scene at its location.


Customizing styles

Our goal is to modify the styles so the experience looks with a cartoonish pirate design. To achieve this, we can use the online code editor to include the new CSS rules that overwrite the default styles.

Using the #webar-geolocated-welcome-logo selector we can change the landing page image and with #webar-geolocated-welcome-card the section below which is shown until the GPS activates and the user clicks the start button. We can also swap the location icon inside it to, for example, an open treasure chest.

#webar-geolocated-welcome-logo {
    background-image: url('https://www.onirix.com/docs/pirate-treasure-hunt.png') !important;

#webar-geolocated-welcome-logo img {
    display: none;

#webar-geolocated-welcome-card img {
    content: url('https://www.onirix.com/docs/treasure-icon.png');


Even in the map view, we can modify the styles of the map and the points of interest. For the PoI we can use .ox-map-location to change the default image of the point to a closed treasure. We can also utilize .ox-selected to change the icon to an open chest when the user has clicked the point.

.ox-map-location-wrapper .ox-map-location {
    background-image: url('https://www.onirix.com/docs/treasure-icon-poi-close.png') !important;

.ox-map-location-wrapper.ox-selected .ox-map-location {
    background-image: url('https://www.onirix.com/docs/treasure-icon-poi-open.png') !important;
    width: 40px !important;
    height: 40px !important;

In addition to .ox-selected for the Selected state, there are other two states for available for locations:

  • Normal: the usual state of the location. It is neither selected nor accessible. Use .ox-map-location-wrapper to modify it.
  • Accessible: when the user is inside the range of activation of a location the class .ox-ar-enabled is added to the location wrapper.
  • Selected: a location is selected when the user has clicked on the location. Use .ox-selected to change its style.

In this same view, the menu buttons and the options can also be changed with the following selectors:

  • .ox-g-round-button: for all the buttons with rounded borders. It includes the “View locations” button of the welcome page.
  • .ox-navigate-button: for the round buttons used for navigation (“View on map”).
  • #webar-geolocated-back-button: for the back button on the top left corner.
  • #webar-geolocated-menu-button: for the hamburger menu button on the top right corner.
  • .ox-locations-menu: for the close icon on the locations menu.

In this example, we have changed the colours of all the buttons to match the brown of the treasure chests with the following code:

.ox-g-round-button {
    background: #9a6740 !important;

.ox-g-round-button.ox-navigate-button {
    background: #f1f3fe !important;

#webar-geolocated-back-button svg path {
    fill: #9a6740;

#webar-geolocated-menu-button svg path {
    fill: #9a6740;

.ox-locations-menu svg path {
    fill: #9a6740;

This code will make the application look like this:


Besides the colours, it is also possible to change the content of the buttons with the following rules:

.ox-location-panel .ox-g-round-button.ox-navigate-button span { 
    display: none;
.ox-location-panel .ox-g-round-button.ox-navigate-button::after {
    content: 'Your text here';

Setting display to none on the span removes the original text from the view, and with the ::after pseudo-selector we can define the new text.

Additionally, it is allowed to remove the “powered by” image with the following rule:

#webar-powered-img {
    display: none;

Furthermore, we can customize the preview that is shown on social media and communication applications when the link to the AR experience is shared. To modify it: go back to Studio, click on Share and scroll to the bottom of the sidebar. Under Customizing sharing preview, you will be able to set up an image, a title and a description that will be shown when the link is shared.


Embed in your website and capture events to increase the score

The last step for a fully customized experience is to embed it in your website, under your custom domain.

For that, we will create a simple React application embedding the Onirix Player, and connected with the EmbedSDK.

You can follow this simple snippet that corresponds to a react component.

import './App.css';

import React from 'react';
import OnirixEmbedSDK from "https://sdk.onirix.com/embed/ox-embed-sdk.esm.js";
import ScoreOverlay from './ScoreOverlay';

class App extends React.Component {

    state = {
        score: 0,
        showScore: false,
        sceneCollectedChests: 0

    async componentDidMount() {
        const iframeElement = document.getElementById("visor");
        iframeElement.onload = () => {
            this.embedSDK = new OnirixEmbedSDK(iframeElement);
            this.embedSDK.subscribe(OnirixEmbedSDK.Events.ELEMENT_CLICK, (params) => {
                if (params.name.includes('Chest')) {
            this.embedSDK.subscribe(OnirixEmbedSDK.Events.READY, (params) => {
                this.setState({ sceneCollectedChests: 0 });

    render() {
        return (
        <div id="app">
            <script src="https://www.onirix.com/webar/ox-devicemotion.min.js"></script>
                src="https://studio.onirix.com/projects/122baaefd3dd4ddabd7b91a61bddc5d2/webar?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjI4LCJwcm9qZWN0SWQiOjIyOTQ1LCJyb2xlIjozLCJpYXQiOjE2NDQ1MDA0MDh9.l_q-A6mbr_eEF80tURTfeQwZamNuyOUHtl8ITA7CJsI" allow="geolocation;camera;gyroscope;accelerometer">
            { this.state.showScore &&  

    handleChestClick() {
            score: this.state.score + 25, 
            sceneCollectedChests: this.state.sceneCollectedChests +1 
        if (this.state.sceneCollectedChests == 3) {
            this.setState({ showScore: true });

    handleClose() {
        this.setState({ showScore: false });


export default App;

If you carefully inspect the code, you may see we use the Embed SDK to capture clicks on Chest elements, increasing the overall score by 25. Once the 3 chests are catched, the score dialog is shown.


Next steps could involve integrating with a custom solution or fully managed backend services like Firebase. We are looking forward to see what you create using Onirix!

If you want to get the full source code for the solution. Click here to download.